<commit_before>extern crate test;
extern crate itertools;
extern crate debug;

use itertools::Itertools;
use itertools::ItertoolsClonable;
use itertools::Stride;
use itertools::StrideMut;

#[test]
fn mut_stride() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(xs.as_mut_slice(), 2) {
        *x = 0i;
    }
    assert_eq!(xs, vec![0i, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(xs.as_mut_slice(), 2);
        let mut iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0i;
        }
    }
    assert_eq!(xs, vec![0i, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = [7i, 9, 8];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs.slice_from(1), 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride_compose() {
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![1i, 5, 9]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 6]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 1);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 4, 6, 8]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![9i, 5, 1]);

    let xs = [1i, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    let v = odds.clones().collect::<Vec<int>>();
    assert_eq!(v, vec![1i, 3i]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, -2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![8i, 4]);
}

#[test]
fn from_stride_empty()
{
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.drain();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: [u8, ..0]  = [];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 10);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert_eq!(*it.next().unwrap(), 10);
    assert_eq!(*it.next().unwrap(), 9);
    assert_eq!(it.next(), None);
}

#[test]
fn stride_index() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_fail]
fn stride_index_fail() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<commit_msg>Remove use of the debug crate<commit_after>extern crate test;
extern crate itertools;

use itertools::Itertools;
use itertools::ItertoolsClonable;
use itertools::Stride;
use itertools::StrideMut;

#[test]
fn mut_stride() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(xs.as_mut_slice(), 2) {
        *x = 0i;
    }
    assert_eq!(xs, vec![0i, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1i, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(xs.as_mut_slice(), 2);
        let mut iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0i;
        }
    }
    assert_eq!(xs, vec![0i, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = [7i, 9, 8];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs.slice_from(1), 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride_compose() {
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![1i, 5, 9]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 6]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, 1);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2i, 4, 6, 8]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![9i, 5, 1]);

    let xs = [1i, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    let v = odds.clones().collect::<Vec<int>>();
    assert_eq!(v, vec![1i, 3i]);

    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(xs.slice_from(1), 2);
    let it = Stride::from_stride(evens, -2);
    let ans: Vec<int> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![8i, 4]);
}

#[test]
fn from_stride_empty()
{
    let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.drain();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: [u8, ..0]  = [];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let xs = [7i, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 10);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert_eq!(*it.next().unwrap(), 10);
    assert_eq!(*it.next().unwrap(), 9);
    assert_eq!(it.next(), None);
}

#[test]
fn stride_index() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_fail]
fn stride_index_fail() {
    let xs = [7i, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-absolute-difference-queries/
pub fn min_difference(nums: Vec<i32>, queries: Vec<Vec<i32>>) -> Vec<i32> {
    let mut prefix = vec![vec![0; 101]; 100001];
    for i in 0..nums.len() {
        let j = nums[i] as usize;
        prefix[i][j] += 1;
        if i > 0 {
            for j in 1..101 {
                prefix[i][j] += prefix[i - 1][j];
            }
        }
    }
    let mut answer: Vec<i32> = vec![];
    for query in queries.iter() {
        let left = query[0] as usize;
        let right = query[1] as usize;
        let mut counts = vec![0; 101];
        for i in 0..101 {
            if left == 0 {
                counts[i] = prefix[right][i];
            } else {
                counts[i] = prefix[right][i] - prefix[left - 1][i];
            }
        }
        let mut min = i32::MAX;
        let mut prev = 0;
        for i in 0..101 {
            if counts[i] == 0 {
                continue;
            }
            if prev > 0 {
                min = min.min((i as i32 - prev).abs());
            }
            prev = i as i32;
        }
        answer.push(if min == i32::MAX { -1 } else { min });
    }
    answer
}

fn main() {
    println!(
        "{:?}",
        min_difference(
            vec![1, 3, 4, 8],
            vec![vec![0, 1], vec![1, 2], vec![2, 3], vec![0, 3]]
        )
    ); // [2,1,4,1]
    println!(
        "{:?}",
        min_difference(
            vec![4, 5, 2, 2, 7, 10],
            vec![vec![2, 3], vec![0, 2], vec![0, 5], vec![3, 5]]
        )
    ); // [-1,1,1,3]
    println!("{:?}", min_difference(vec![1, 3, 3, 1], vec![vec![0, 3]])); // [2]
    println!("{:?}", min_difference(vec![3, 3, 3, 1], vec![vec![0, 3]])); // [2]
    println!("{:?}", min_difference(vec![3, 3, 3, 3], vec![vec![0, 3]])); // [-1]
}
<commit_msg>Solve problem 1906<commit_after>// https://leetcode.com/problems/minimum-absolute-difference-queries/
pub fn min_difference(nums: Vec<i32>, queries: Vec<Vec<i32>>) -> Vec<i32> {
    let mut prefix = [[0; 101]; 100001];
    for (i, num) in nums.into_iter().enumerate() {
        let j = num as usize;
        prefix[i][j] += 1;
        if i > 0 {
            for j in 1..101 {
                prefix[i][j] += prefix[i - 1][j];
            }
        }
    }
    let mut answer: Vec<i32> = vec![];
    for query in queries.into_iter() {
        let left = query[0] as usize;
        let right = query[1] as usize;
        let mut counts = [0; 101];
        for i in 0..101 {
            if left == 0 {
                counts[i] = prefix[right][i];
            } else {
                counts[i] = prefix[right][i] - prefix[left - 1][i];
            }
        }
        let mut min = i32::MAX;
        let mut prev = 0;
        for i in 0..101 {
            if counts[i] == 0 {
                continue;
            }
            if prev > 0 {
                min = min.min((i as i32 - prev).abs());
            }
            prev = i as i32;
        }
        answer.push(if min == i32::MAX { -1 } else { min });
    }
    answer
}

fn main() {
    println!(
        "{:?}",
        min_difference(
            vec![1, 3, 4, 8],
            vec![vec![0, 1], vec![1, 2], vec![2, 3], vec![0, 3]]
        )
    ); // [2,1,4,1]
    println!(
        "{:?}",
        min_difference(
            vec![4, 5, 2, 2, 7, 10],
            vec![vec![2, 3], vec![0, 2], vec![0, 5], vec![3, 5]]
        )
    ); // [-1,1,1,3]
    println!("{:?}", min_difference(vec![1, 3, 3, 1], vec![vec![0, 3]])); // [2]
    println!("{:?}", min_difference(vec![3, 3, 3, 1], vec![vec![0, 3]])); // [2]
    println!("{:?}", min_difference(vec![3, 3, 3, 3], vec![vec![0, 3]])); // [-1]
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/longest-subarray-with-maximum-bitwise-and/
pub fn longest_subarray(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", longest_subarray(vec![1, 2, 3, 3, 2, 2])); // 2
    println!("{}", longest_subarray(vec![1, 2, 3, 4])); // 1
}
<commit_msg>Solve problem 2419<commit_after>// https://leetcode.com/problems/longest-subarray-with-maximum-bitwise-and/
pub fn longest_subarray(nums: Vec<i32>) -> i32 {
    let mut answer = 0;
    let max = nums.iter().max().unwrap();
    let mut count = 0;
    for num in nums.iter() {
        if num == max {
            count += 1;
        } else {
            count = 0;
        }
        answer = answer.max(count);
    }
    answer
}

fn main() {
    println!("{}", longest_subarray(vec![1, 2, 3, 3, 2, 2])); // 2
    println!("{}", longest_subarray(vec![1, 2, 3, 4])); // 1
    println!(
        "{}",
        longest_subarray(vec![
            311155, 311155, 311155, 311155, 311155, 311155, 311155, 311155, 201191, 311155
        ])
    ); // 8
    println!(
        "{}",
        longest_subarray(vec![
            96317, 96317, 96317, 96317, 96317, 96317, 96317, 96317, 96317, 279979
        ])
    ); // 1
}
<|endoftext|>


<commit_before>extern crate sovrin;

// Workaround to share some utils code based on indy sdk types between tests and indy sdk
use sovrin::api as api;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

#[macro_use]
mod utils;

use utils::wallet::WalletUtils;
use utils::signus::SignusUtils;
use utils::test::TestUtils;

use sovrin::api::ErrorCode;

mod high_cases {
    use super::*;

    mod register_wallet_type {
        use super::*;

        #[test]
        fn sovrin_register_wallet_type_works() {
            TestUtils::cleanup_storage();

            WalletUtils::register_wallet_type("inmem").unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod create_wallet {
        use super::*;

        #[test]
        fn sovrin_create_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "wallet1";
            let xtype = "default";

            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_unknown_type() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_unknown_type";
            let wallet_name = "wallet1";
            let xtype = "type";

            let res = WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletUnknownTypeError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_empty_type() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_empty_type";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "wallet1";
            let xtype = "default";
            let config = r#"{"freshness_time":1000}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), Some(config)).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod delete_wallet {
        use super::*;

        #[test]
        fn sovrin_delete_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_delete_wallet_works";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::delete_wallet(wallet_name).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod open_wallet {
        use super::*;

        #[test]
        fn sovrin_open_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works";
            let wallet_name = "wallet1";
            let config = r#"{"freshness_time":1000}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name, Some(config)).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod close_wallet {
        use super::*;

        #[test]
        fn sovrin_close_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_close_wallet_works";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            let wallet_handle = WalletUtils::open_wallet(wallet_name, None).unwrap();
            WalletUtils::close_wallet(wallet_handle).unwrap();
            WalletUtils::open_wallet(wallet_name, None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod set_seqno_wallet {
        use super::*;

        #[test]
        fn sovrin_wallet_set_seqno_works() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works", None).unwrap();

            let (did, _, _) = SignusUtils::create_my_did(wallet_handle, "{}").unwrap();

            WalletUtils::wallet_set_seq_no_for_value(wallet_handle, &did, 1).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}

mod medium_cases {
    use super::*;

    mod create_wallet {
        use super::*;

        #[test]
        fn sovrin_create_wallet_works_for_duplicate_name() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_duplicate_name";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            let res = WalletUtils::create_wallet(pool_name, wallet_name, None, None);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletAlreadyExistsError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_empty_name() {
            TestUtils::cleanup_storage();

            let pool_name = "pool";
            let wallet_name = "";

            let res = WalletUtils::create_wallet(pool_name, wallet_name, None, None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonInvalidParam3);

            TestUtils::cleanup_storage();
        }
    }

    mod delete_wallet {
        use super::*;

        #[test]
        fn sovrin_delete_wallet_works_for_invalid_wallet_name() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::delete_wallet("wallet1");
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_delete_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_delete_wallet_works_for_deleted_wallet";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::delete_wallet(wallet_name).unwrap();
            let res = WalletUtils::delete_wallet(wallet_name);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }
    }

    mod open_wallet {
        use super::*;

        #[test]
        fn sovrin_open_wallet_works_for_not_created_wallet() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::open_wallet("wallet1", None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        #[ignore] //TODO Check is not implemented
        fn sovrin_open_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "wallet1";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            WalletUtils::open_wallet(wallet_name, None).unwrap();
            let res = WalletUtils::open_wallet(wallet_name, None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_two_wallets() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name_1 = "wallet1";
            let wallet_name_2 = "wallet2";

            WalletUtils::create_wallet(pool_name, wallet_name_1, None, None).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name_2, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name_1, None).unwrap();
            WalletUtils::open_wallet(wallet_name_2, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_invalid_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works";
            let wallet_name = "wallet1";
            let config = r#"{"field":"value"}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            let res = WalletUtils::open_wallet(wallet_name, Some(config));
            assert_eq!(res.unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }

    mod close_wallet {
        use super::*;

        #[test]
        fn sovrin_close_wallet_works_for_invalid_handle() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::close_wallet(1);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_close_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_close_wallet_works_for_closed_wallet", None).unwrap();

            WalletUtils::close_wallet(wallet_handle).unwrap();
            let res = WalletUtils::close_wallet(wallet_handle);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }
    }

    mod set_seqno {
        use super::*;

        #[test]
        fn sovrin_wallet_set_seqno_works_for_not_exists_key() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works_for_not_exists_key", None).unwrap();

            //TODO may be we must return WalletNotFound in case if key not exists in wallet
            WalletUtils::wallet_set_seq_no_for_value(wallet_handle, "key", 1).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_wallet_set_seqno_works_for_invalid_wallet() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works_for_invalid_wallet", None).unwrap();

            let invalid_wallet_handle = wallet_handle + 1;
            let res = WalletUtils::wallet_set_seq_no_for_value(invalid_wallet_handle, "key", 1);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }
    }
}
<commit_msg>* Use different wallet names for wallet tests<commit_after>extern crate sovrin;

// Workaround to share some utils code based on indy sdk types between tests and indy sdk
use sovrin::api as api;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

#[macro_use]
mod utils;

use utils::wallet::WalletUtils;
use utils::signus::SignusUtils;
use utils::test::TestUtils;

use sovrin::api::ErrorCode;

mod high_cases {
    use super::*;

    mod register_wallet_type {
        use super::*;

        #[test]
        fn sovrin_register_wallet_type_works() {
            TestUtils::cleanup_storage();

            WalletUtils::register_wallet_type("inmem").unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod create_wallet {
        use super::*;

        #[test]
        fn sovrin_create_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "sovrin_create_wallet_works";
            let xtype = "default";

            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_plugged() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "sovrin_create_wallet_works";
            let xtype = "inmem";

            WalletUtils::register_wallet_type("inmem").unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_unknown_type() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_unknown_type";
            let wallet_name = "sovrin_create_wallet_works_for_unknown_type";
            let xtype = "type";

            let res = WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletUnknownTypeError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_empty_type() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_empty_type";
            let wallet_name = "sovrin_create_wallet_works_for_empty_type";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "sovrin_create_wallet_works";
            let xtype = "default";
            let config = r#"{"freshness_time":1000}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), Some(config)).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod delete_wallet {
        use super::*;

        #[test]
        fn sovrin_delete_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_delete_wallet_works";
            let wallet_name = "sovrin_delete_wallet_works";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::delete_wallet(wallet_name).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_delete_wallet_works_for_plugged() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_delete_wallet_works_for_plugged";
            let wallet_name = "sovrin_delete_wallet_works_for_plugged";
            let xtype = "inmem";

            WalletUtils::register_wallet_type(xtype).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None).unwrap();
            WalletUtils::delete_wallet(wallet_name).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name, Some(xtype), None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod open_wallet {
        use super::*;

        #[test]
        fn sovrin_open_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works";
            let wallet_name = "sovrin_open_wallet_works";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works_for_config";
            let wallet_name = "sovrin_open_wallet_works_for_config";
            let config = r#"{"freshness_time":1000}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name, Some(config)).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod close_wallet {
        use super::*;

        #[test]
        fn sovrin_close_wallet_works() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_close_wallet_works";
            let wallet_name = "sovrin_close_wallet_works";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            let wallet_handle = WalletUtils::open_wallet(wallet_name, None).unwrap();
            WalletUtils::close_wallet(wallet_handle).unwrap();
            WalletUtils::open_wallet(wallet_name, None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod set_seqno_wallet {
        use super::*;

        #[test]
        fn sovrin_wallet_set_seqno_works() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works", None).unwrap();

            let (did, _, _) = SignusUtils::create_my_did(wallet_handle, "{}").unwrap();

            WalletUtils::wallet_set_seq_no_for_value(wallet_handle, &did, 1).unwrap();

            TestUtils::cleanup_storage();
        }
    }
}

mod medium_cases {
    use super::*;

    mod create_wallet {
        use super::*;

        #[test]
        fn sovrin_create_wallet_works_for_duplicate_name() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_duplicate_name";
            let wallet_name = "sovrin_create_wallet_works_for_duplicate_name";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            let res = WalletUtils::create_wallet(pool_name, wallet_name, None, None);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletAlreadyExistsError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_create_wallet_works_for_empty_name() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works_for_empty_name";
            let wallet_name = "sovrin_create_wallet_works_for_empty_name";

            let res = WalletUtils::create_wallet(pool_name, wallet_name, None, None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonInvalidParam3);

            TestUtils::cleanup_storage();
        }
    }

    mod delete_wallet {
        use super::*;

        #[test]
        fn sovrin_delete_wallet_works_for_invalid_wallet_name() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::delete_wallet("sovrin_delete_wallet_works_for_invalid_wallet_name");
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_delete_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_delete_wallet_works_for_deleted_wallet";
            let wallet_name = "sovrin_delete_wallet_works_for_deleted_wallet";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            WalletUtils::delete_wallet(wallet_name).unwrap();
            let res = WalletUtils::delete_wallet(wallet_name);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }
    }

    mod open_wallet {
        use super::*;

        #[test]
        fn sovrin_open_wallet_works_for_not_created_wallet() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::open_wallet("sovrin_open_wallet_works_for_not_created_wallet", None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        #[ignore] //TODO Check is not implemented
        fn sovrin_open_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_create_wallet_works";
            let wallet_name = "sovrin_open_wallet_works_for_twice";

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();

            WalletUtils::open_wallet(wallet_name, None).unwrap();
            let res = WalletUtils::open_wallet(wallet_name, None);
            assert_eq!(res.unwrap_err(), ErrorCode::CommonIOError);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_two_wallets() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works_for_two_wallets";
            let wallet_name_1 = "sovrin_open_wallet_works_for_two_wallets1";
            let wallet_name_2 = "sovrin_open_wallet_works_for_two_wallets2";

            WalletUtils::create_wallet(pool_name, wallet_name_1, None, None).unwrap();
            WalletUtils::create_wallet(pool_name, wallet_name_2, None, None).unwrap();
            WalletUtils::open_wallet(wallet_name_1, None).unwrap();
            WalletUtils::open_wallet(wallet_name_2, None).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_open_wallet_works_for_invalid_config() {
            TestUtils::cleanup_storage();

            let pool_name = "sovrin_open_wallet_works_for_invalid_config";
            let wallet_name = "sovrin_open_wallet_works_for_invalid_config";
            let config = r#"{"field":"value"}"#;

            WalletUtils::create_wallet(pool_name, wallet_name, None, None).unwrap();
            let res = WalletUtils::open_wallet(wallet_name, Some(config));
            assert_eq!(res.unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }

    mod close_wallet {
        use super::*;

        #[test]
        fn sovrin_close_wallet_works_for_invalid_handle() {
            TestUtils::cleanup_storage();

            let res = WalletUtils::close_wallet(1);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_close_wallet_works_for_twice() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_close_wallet_works_for_twice", None).unwrap();

            WalletUtils::close_wallet(wallet_handle).unwrap();
            let res = WalletUtils::close_wallet(wallet_handle);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }
    }

    mod set_seqno {
        use super::*;

        #[test]
        fn sovrin_wallet_set_seqno_works_for_not_exists_key() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works_for_not_exists_key", None).unwrap();

            //TODO may be we must return WalletNotFound in case if key not exists in wallet
            WalletUtils::wallet_set_seq_no_for_value(wallet_handle, "key", 1).unwrap();

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_wallet_set_seqno_works_for_invalid_wallet() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("sovrin_wallet_set_seqno_works_for_invalid_wallet", None).unwrap();

            let invalid_wallet_handle = wallet_handle + 1;
            let res = WalletUtils::wallet_set_seq_no_for_value(invalid_wallet_handle, "key", 1);
            assert_eq!(res.unwrap_err(), ErrorCode::WalletInvalidHandle);

            TestUtils::cleanup_storage();
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate hawk;
extern crate hyper;
extern crate hyper_hawk;
extern crate url;

use hawk::{Request, Credentials, Key, SHA256, PayloadHasher};
use std::io::{Read, Write};
use hyper_hawk::{HawkScheme, ServerAuthorization};
use hyper::Client;
use hyper::header;
use hyper::server;
use url::Url;
use std::thread;

fn client(send_hash: bool, require_hash: bool, port: u16) {
    let credentials = Credentials {
        id: "test-client".to_string(),
        key: Key::new(vec![1u8; 32], &SHA256),
    };
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let body = "foo=bar";

    let payload_hash;
    let mut request = Request::new().method("POST").url(&url).unwrap();

    if send_hash {
        payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        request = request.hash(Some(&payload_hash));
    }

    let mut headers = hyper::header::Headers::new();
    let header = request.make_header(&credentials).unwrap();
    headers.set(header::Authorization(HawkScheme(header.clone())));

    let client = Client::new();
    let mut res = client
        .post(url.as_str())
        .headers(headers)
        .body(body)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert_eq!(res.status, hyper::Ok);
    assert_eq!(body, "OK");

    let server_hdr: &ServerAuthorization<HawkScheme> = res.headers.get().unwrap();

    // most fields in `Server-Authorization: Hawk` are omitted
    assert_eq!(server_hdr.id, None);
    assert_eq!(server_hdr.ts, None);
    assert_eq!(server_hdr.nonce, None);
    assert_eq!(server_hdr.ext, Some("server-ext".to_string()));
    if require_hash {
        assert!(server_hdr.hash.is_some());
    }
    assert_eq!(server_hdr.app, None);
    assert_eq!(server_hdr.dlg, None);

    let payload_hash;
    let mut response = request.make_response(&header);
    if require_hash {
        payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        response = response.hash(&payload_hash);
    }

    if !response.validate_header(&server_hdr, &credentials.key) {
        panic!("authentication of response header failed");
    }
}

struct TestHandler {
    require_hash: bool,
    send_hash: bool,
    port: u16,
}

impl server::Handler for TestHandler {
    fn handle(&self, mut req: server::Request, mut res: server::Response) {
        // get the body
        let mut body = String::new();
        req.read_to_string(&mut body).unwrap();

        // get the Authorization header the client sent
        let hdr: &header::Authorization<HawkScheme> = req.headers.get().unwrap();

        // build a request object based on what we know
        let payload_hash;
        let mut request = Request::new()
            .method("POST")
            .host("localhost")
            .port(self.port)
            .path("/resource");

        // add a body hash, if we require such a thing
        if self.require_hash {
            payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
            request = request.hash(Some(&payload_hash));
        }

        assert_eq!(hdr.id, Some("test-client".to_string()));
        assert_eq!(hdr.ext, None);
        let key = Key::new(vec![1u8; 32], &SHA256);
        if !request.validate_header(&hdr, &key, time::Duration::minutes(1)) {
            panic!("header validation failed");
        }

        let body = "OK".as_bytes();
        let payload_hash;
        let mut response = request.make_response(&hdr).ext("server-ext");
        if self.send_hash {
            payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body);
            response = response.hash(&payload_hash);
        }
        let server_hdr = response.make_header(&key).unwrap();
        res.headers_mut()
            .set(ServerAuthorization(HawkScheme(server_hdr)));

        res.headers_mut()
            .set(header::ContentLength(body.len() as u64));

        let mut res = res.start().unwrap();
        res.write_all(body).unwrap();
    }
}

fn run_client_server(client_send_hash: bool,
                     server_require_hash: bool,
                     server_send_hash: bool,
                     client_require_hash: bool,
                     port: u16) {
    let handler = TestHandler {
        require_hash: server_require_hash,
        send_hash: server_send_hash,
        port: port,
    };
    let server = server::Server::http(("127.0.0.1", port)).unwrap();
    let mut listening = server.handle_threads(handler, 1).unwrap();
    let client_thread =
        thread::spawn(move || { client(client_send_hash, client_require_hash, port); });

    // finish both threads
    let client_res = client_thread.join();
    listening.close().unwrap();

    // *then* evaluate client_res
    if let Err(_) = client_res {
        panic!("client failed");
    }
}

// Each test uses a different port, since the tests run in parallel.

#[test]
fn no_hashes() {
    run_client_server(false, false, false, false, 9001);
}

#[test]
fn client_sends() {
    run_client_server(true, false, false, false, 9002);
}

#[test]
fn server_requires() {
    run_client_server(true, true, false, false, 9003);
}

#[test]
fn server_sends() {
    run_client_server(true, true, true, false, 9004);
}

#[test]
fn client_requires() {
    run_client_server(true, true, true, true, 9005);
}

#[test]
fn response_hash_only() {
    run_client_server(false, false, true, true, 9006);
}
<commit_msg>use dynamically assigned ports for client-server tests<commit_after>extern crate time;
extern crate hawk;
extern crate hyper;
extern crate hyper_hawk;
extern crate url;

use hawk::{Request, Credentials, Key, SHA256, PayloadHasher};
use std::io::{Read, Write};
use hyper_hawk::{HawkScheme, ServerAuthorization};
use hyper::Client;
use hyper::header;
use hyper::server;
use url::Url;
use std::thread;

fn client(send_hash: bool, require_hash: bool, port: u16) {
    let credentials = Credentials {
        id: "test-client".to_string(),
        key: Key::new(vec![1u8; 32], &SHA256),
    };
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let body = "foo=bar";

    let payload_hash;
    let mut request = Request::new().method("POST").url(&url).unwrap();
    // for purposes of the test, we pretend we're using port 9999
    request = request.port(9999);

    if send_hash {
        payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        request = request.hash(Some(&payload_hash));
    }

    let mut headers = hyper::header::Headers::new();
    let header = request.make_header(&credentials).unwrap();
    headers.set(header::Authorization(HawkScheme(header.clone())));

    let client = Client::new();
    let mut res = client
        .post(url.as_str())
        .headers(headers)
        .body(body)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert_eq!(res.status, hyper::Ok);
    assert_eq!(body, "OK");

    let server_hdr: &ServerAuthorization<HawkScheme> = res.headers.get().unwrap();

    // most fields in `Server-Authorization: Hawk` are omitted
    assert_eq!(server_hdr.id, None);
    assert_eq!(server_hdr.ts, None);
    assert_eq!(server_hdr.nonce, None);
    assert_eq!(server_hdr.ext, Some("server-ext".to_string()));
    if require_hash {
        assert!(server_hdr.hash.is_some());
    }
    assert_eq!(server_hdr.app, None);
    assert_eq!(server_hdr.dlg, None);

    let payload_hash;
    let mut response = request.make_response(&header);
    if require_hash {
        payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        response = response.hash(&payload_hash);
    }

    if !response.validate_header(&server_hdr, &credentials.key) {
        panic!("authentication of response header failed");
    }
}

struct TestHandler {
    require_hash: bool,
    send_hash: bool,
}

impl server::Handler for TestHandler {
    fn handle(&self, mut req: server::Request, mut res: server::Response) {
        // get the body
        let mut body = String::new();
        req.read_to_string(&mut body).unwrap();

        // get the Authorization header the client sent
        let hdr: &header::Authorization<HawkScheme> = req.headers.get().unwrap();

        // build a request object based on what we know
        let payload_hash;
        let mut request = Request::new()
            .method("POST")
            .host("localhost")
            .port(9999)
            .path("/resource");

        // add a body hash, if we require such a thing
        if self.require_hash {
            payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
            request = request.hash(Some(&payload_hash));
        }

        assert_eq!(hdr.id, Some("test-client".to_string()));
        assert_eq!(hdr.ext, None);
        let key = Key::new(vec![1u8; 32], &SHA256);
        if !request.validate_header(&hdr, &key, time::Duration::minutes(1)) {
            panic!("header validation failed");
        }

        let body = "OK".as_bytes();
        let payload_hash;
        let mut response = request.make_response(&hdr).ext("server-ext");
        if self.send_hash {
            payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body);
            response = response.hash(&payload_hash);
        }
        let server_hdr = response.make_header(&key).unwrap();
        res.headers_mut()
            .set(ServerAuthorization(HawkScheme(server_hdr)));

        res.headers_mut()
            .set(header::ContentLength(body.len() as u64));

        let mut res = res.start().unwrap();
        res.write_all(body).unwrap();
    }
}

fn run_client_server(client_send_hash: bool,
                     server_require_hash: bool,
                     server_send_hash: bool,
                     client_require_hash: bool) {
    let handler = TestHandler {
        require_hash: server_require_hash,
        send_hash: server_send_hash,
    };
    let mut server = server::Server::http(("127.0.0.1", 0)).unwrap();
    let local_address = server.local_addr().unwrap();
    let mut listening = server.handle_threads(handler, 1).unwrap();
    let client_thread =
        thread::spawn(move || {
                          client(client_send_hash, client_require_hash, local_address.port());
                      });

    // finish both threads
    let client_res = client_thread.join();
    listening.close().unwrap();

    // *then* evaluate client_res
    if let Err(_) = client_res {
        panic!("client failed");
    }
}

#[test]
fn no_hashes() {
    run_client_server(false, false, false, false);
}

#[test]
fn client_sends() {
    run_client_server(true, false, false, false);
}

#[test]
fn server_requires() {
    run_client_server(true, true, false, false);
}

#[test]
fn server_sends() {
    run_client_server(true, true, true, false);
}

#[test]
fn client_requires() {
    run_client_server(true, true, true, true);
}

#[test]
fn response_hash_only() {
    run_client_server(false, false, true, true);
}
<|endoftext|>


<commit_before>//! compile-time representations of offsets

use super::write::{FontWrite, TableWriter};

/// The width in bytes of an Offset16
pub const WIDTH_16: usize = 2;
/// The width in bytes of an Offset24
#[allow(dead_code)] // will be used one day :')
pub const WIDTH_24: usize = 3;
/// The width in bytes of an Offset32
pub const WIDTH_32: usize = 4;

/// An offset subtable.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

/// An offset subtable which may be null.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NullableOffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object. Fonts in the wild may be malformed, so this still returns
    /// an option?
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// Create a new marker.
    pub fn new(obj: T) -> Self {
        OffsetMarker { obj: Some(obj) }
    }

    /// Creates a new marker with an object that may be null.
    //TODO: figure out how we're actually handling null offsets. Some offsets
    //are allowed to be null, but even offsets that aren't *may* be null,
    //and we should handle this.
    pub fn new_maybe_null(obj: Option<T>) -> Self {
        OffsetMarker { obj }
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object, if it exists.
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    pub fn new(obj: Option<T>) -> Self {
        NullableOffsetMarker { obj }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for OffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => {
                eprintln!("warning: unexpected null OffsetMarker");
                writer.write_slice([0u8; N].as_slice());
            }
        }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for NullableOffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => writer.write_slice([0u8; N].as_slice()),
        }
    }
}

impl<T: Default, const N: usize> Default for OffsetMarker<T, N> {
    fn default() -> Self {
        Self {
            obj: Some(T::default()),
        }
    }
}

impl<T, const N: usize> Default for NullableOffsetMarker<T, N> {
    fn default() -> Self {
        Self { obj: None }
    }
}
// In case I still want to use these?

//impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for OffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(f, "OffsetMarker({}, {:?})", N * 8, self.obj.as_ref(),)
//}
//}

//impl<const N: usize, T: std::fmt::Debug> std::fmt::Debug for NullableOffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(
//f,
//"NullableOffsetMarker({}, {:?})",
//N * 8,
//self.obj.as_ref(),
//)
//}
//}
<commit_msg>Add blanket From<T> and From<Option<T>> for offset markers<commit_after>//! compile-time representations of offsets

use super::write::{FontWrite, TableWriter};

/// The width in bytes of an Offset16
pub const WIDTH_16: usize = 2;
/// The width in bytes of an Offset24
#[allow(dead_code)] // will be used one day :')
pub const WIDTH_24: usize = 3;
/// The width in bytes of an Offset32
pub const WIDTH_32: usize = 4;

/// An offset subtable.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

/// An offset subtable which may be null.
///
/// The generic const `N` is the width of the offset, in bytes.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NullableOffsetMarker<T, const N: usize = WIDTH_16> {
    obj: Option<T>,
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object. Fonts in the wild may be malformed, so this still returns
    /// an option?
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> OffsetMarker<T, N> {
    /// Create a new marker.
    pub fn new(obj: T) -> Self {
        OffsetMarker { obj: Some(obj) }
    }

    /// Creates a new marker with an object that may be null.
    //TODO: figure out how we're actually handling null offsets. Some offsets
    //are allowed to be null, but even offsets that aren't *may* be null,
    //and we should handle this.
    pub fn new_maybe_null(obj: Option<T>) -> Self {
        OffsetMarker { obj }
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    /// `true` if the offset is non-null
    pub fn is_some(&self) -> bool {
        self.obj.is_some()
    }

    /// `true` if the offset is null
    pub fn is_none(&self) -> bool {
        self.obj.is_none()
    }

    //TODO: how do we handle malformed inputs? do we error earlier than this?
    /// Get the object, if it exists.
    pub fn get(&self) -> Option<&T> {
        self.obj.as_ref()
    }

    pub fn get_mut(&mut self) -> Option<&mut T> {
        self.obj.as_mut()
    }

    pub fn set(&mut self, obj: T) {
        self.obj = Some(obj);
    }

    pub fn clear(&mut self) {
        self.obj = None;
    }
}

impl<const N: usize, T> NullableOffsetMarker<T, N> {
    pub fn new(obj: Option<T>) -> Self {
        NullableOffsetMarker { obj }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for OffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => {
                eprintln!("warning: unexpected null OffsetMarker");
                writer.write_slice([0u8; N].as_slice());
            }
        }
    }
}

impl<const N: usize, T: FontWrite> FontWrite for NullableOffsetMarker<T, N> {
    fn write_into(&self, writer: &mut TableWriter) {
        match self.obj.as_ref() {
            Some(obj) => writer.write_offset(obj, N),
            None => writer.write_slice([0u8; N].as_slice()),
        }
    }
}

impl<T: Default, const N: usize> Default for OffsetMarker<T, N> {
    fn default() -> Self {
        Self {
            obj: Some(T::default()),
        }
    }
}

impl<T, const N: usize> Default for NullableOffsetMarker<T, N> {
    fn default() -> Self {
        Self { obj: None }
    }
}

impl<T, const N: usize> From<T> for OffsetMarker<T, N> {
    fn from(src: T) -> Self {
        OffsetMarker::new(src)
    }
}

impl<T, const N: usize> From<T> for NullableOffsetMarker<T, N> {
    fn from(src: T) -> Self {
        NullableOffsetMarker::new(Some(src))
    }
}

impl<T, const N: usize> From<Option<T>> for NullableOffsetMarker<T, N> {
    fn from(src: Option<T>) -> Self {
        NullableOffsetMarker::new(src)
    }
}

// In case I still want to use these?

//impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for OffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(f, "OffsetMarker({}, {:?})", N * 8, self.obj.as_ref(),)
//}
//}

//impl<const N: usize, T: std::fmt::Debug> std::fmt::Debug for NullableOffsetMarker<T, N> {
//fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//write!(
//f,
//"NullableOffsetMarker({}, {:?})",
//N * 8,
//self.obj.as_ref(),
//)
//}
//}
<|endoftext|>


<commit_before>use std::str::pattern::*;

// This macro makes it easier to write
// tests that do a series of iterations
macro_rules! search_asserts {
    ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => {
        let mut searcher = $needle.into_searcher($haystack);
        let arr = [$( Step::from(searcher.$func()) ),+];
        assert_eq!(&arr[..], &$result, $testname);
    }
}

/// Combined enum for the results of next() and next_match()/next_reject()
#[derive(Debug, PartialEq, Eq)]
enum Step {
    // variant names purposely chosen to
    // be the same length for easy alignment
    Matches(usize, usize),
    Rejects(usize, usize),
    InRange(usize, usize),
    Done
}

use Step::*;

impl From<SearchStep> for Step {
    fn from(x: SearchStep) -> Self {
        match x {
            SearchStep::Match(a, b) => Matches(a, b),
            SearchStep::Reject(a, b) => Rejects(a, b),
            SearchStep::Done => Done
        }
    }
}

impl From<Option<(usize, usize)>> for Step {
    fn from(x: Option<(usize, usize)>) -> Self {
        match x {
            Some((a, b)) => InRange(a, b),
            None => Done
        }
    }
}

#[test]
fn test_simple_iteration() {
    search_asserts! ("abcdeabcd", 'a', "forward iteration for ASCII string",
        // a            b              c              d              e              a              b              c              d              EOF
        [next,          next,          next,          next,          next,          next,          next,          next,          next,          next],
        [Matches(0, 1), Rejects(1, 2), Rejects(2, 3), Rejects(3, 4), Rejects(4, 5), Matches(5, 6), Rejects(6, 7), Rejects(7, 8), Rejects(8, 9), Done]
    );

    search_asserts! ("abcdeabcd", 'a', "reverse iteration for ASCII string",
        // d            c              b              a            e                d              c              b              a             EOF
        [next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back],
        [Rejects(8, 9), Rejects(7, 8), Rejects(6, 7), Matches(5, 6), Rejects(4, 5), Rejects(3, 4), Rejects(2, 3), Rejects(1, 2), Matches(0, 1), Done]
    );

    search_asserts! ("我爱我的猫", '我', "forward iteration for Chinese string",
        // 我           愛             我             的              貓               EOF
        [next,          next,          next,          next,           next,            next],
        [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done]
    );

    search_asserts! ("我的猫说meow", 'm', "forward iteration for mixed string",
        // 我           的             猫             说              m                e                o                w                EOF
        [next,          next,          next,          next,           next,            next,            next,            next,            next],
        [Rejects(0, 3), Rejects(3, 6), Rejects(6, 9), Rejects(9, 12), Matches(12, 13), Rejects(13, 14), Rejects(14, 15), Rejects(15, 16), Done]
    );

    search_asserts! ("我的猫说meow", '猫', "reverse iteration for mixed string",
        // w             o                 e                m                说              猫             的             我             EOF
        [next_back,       next_back,       next_back,       next_back,       next_back,      next_back,      next_back,    next_back,     next_back],
        [Rejects(15, 16), Rejects(14, 15), Rejects(13, 14), Rejects(12, 13), Rejects(9, 12), Matches(6, 9), Rejects(3, 6), Rejects(0, 3), Done]
    );
}

#[test]
fn test_simple_search() {
    search_asserts!("abcdeabcdeabcde", 'a', "next_match for ASCII string",
        [next_match,    next_match,    next_match,      next_match],
        [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done]
    );

    search_asserts!("abcdeabcdeabcde", 'a', "next_match_back for ASCII string",
        [next_match_back, next_match_back, next_match_back, next_match_back],
        [InRange(10, 11), InRange(5, 6),   InRange(0, 1),   Done]
    );

    search_asserts!("abcdeab", 'a', "next_reject for ASCII string",
        [next_reject,   next_reject,   next_match,    next_reject,   next_reject],
        [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done]
    );

    search_asserts!("abcdeabcdeabcde", 'a', "next_reject_back for ASCII string",
        [next_reject_back, next_reject_back, next_match_back, next_reject_back, next_reject_back, next_reject_back],
        [InRange(14, 15),  InRange(13, 14),  InRange(10, 11), InRange(9, 10),   InRange(8, 9),    InRange(7, 8)]
    );
}

<commit_msg>Add stresstests for shared bytes for pattern API<commit_after>use std::str::pattern::*;

// This macro makes it easier to write
// tests that do a series of iterations
macro_rules! search_asserts {
    ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => {
        let mut searcher = $needle.into_searcher($haystack);
        let arr = [$( Step::from(searcher.$func()) ),+];
        assert_eq!(&arr[..], &$result, $testname);
    }
}

/// Combined enum for the results of next() and next_match()/next_reject()
#[derive(Debug, PartialEq, Eq)]
enum Step {
    // variant names purposely chosen to
    // be the same length for easy alignment
    Matches(usize, usize),
    Rejects(usize, usize),
    InRange(usize, usize),
    Done
}

use self::Step::*;

impl From<SearchStep> for Step {
    fn from(x: SearchStep) -> Self {
        match x {
            SearchStep::Match(a, b) => Matches(a, b),
            SearchStep::Reject(a, b) => Rejects(a, b),
            SearchStep::Done => Done
        }
    }
}

impl From<Option<(usize, usize)>> for Step {
    fn from(x: Option<(usize, usize)>) -> Self {
        match x {
            Some((a, b)) => InRange(a, b),
            None => Done
        }
    }
}

// XXXManishearth these tests focus on single-character searching  (CharSearcher)
// and on next()/next_match(), not next_reject(). This is because
// the memchr changes make next_match() for single chars complex, but next_reject()
// continues to use next() under the hood. We should add more test cases for all
// of these, as well as tests for StrSearcher and higher level tests for str::find() (etc)

#[test]
fn test_simple_iteration() {
    search_asserts! ("abcdeabcd", 'a', "forward iteration for ASCII string",
        // a            b              c              d              e              a              b              c              d              EOF
        [next,          next,          next,          next,          next,          next,          next,          next,          next,          next],
        [Matches(0, 1), Rejects(1, 2), Rejects(2, 3), Rejects(3, 4), Rejects(4, 5), Matches(5, 6), Rejects(6, 7), Rejects(7, 8), Rejects(8, 9), Done]
    );

    search_asserts! ("abcdeabcd", 'a', "reverse iteration for ASCII string",
        // d            c              b              a            e                d              c              b              a             EOF
        [next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back,     next_back],
        [Rejects(8, 9), Rejects(7, 8), Rejects(6, 7), Matches(5, 6), Rejects(4, 5), Rejects(3, 4), Rejects(2, 3), Rejects(1, 2), Matches(0, 1), Done]
    );

    search_asserts! ("我爱我的猫", '我', "forward iteration for Chinese string",
        // 我           愛             我             的              貓               EOF
        [next,          next,          next,          next,           next,            next],
        [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done]
    );

    search_asserts! ("我的猫说meow", 'm', "forward iteration for mixed string",
        // 我           的             猫             说              m                e                o                w                EOF
        [next,          next,          next,          next,           next,            next,            next,            next,            next],
        [Rejects(0, 3), Rejects(3, 6), Rejects(6, 9), Rejects(9, 12), Matches(12, 13), Rejects(13, 14), Rejects(14, 15), Rejects(15, 16), Done]
    );

    search_asserts! ("我的猫说meow", '猫', "reverse iteration for mixed string",
        // w             o                 e                m                说              猫             的             我             EOF
        [next_back,       next_back,       next_back,       next_back,       next_back,      next_back,      next_back,    next_back,     next_back],
        [Rejects(15, 16), Rejects(14, 15), Rejects(13, 14), Rejects(12, 13), Rejects(9, 12), Matches(6, 9), Rejects(3, 6), Rejects(0, 3), Done]
    );
}

#[test]
fn test_simple_search() {
    search_asserts!("abcdeabcdeabcde", 'a', "next_match for ASCII string",
        [next_match,    next_match,    next_match,      next_match],
        [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done]
    );

    search_asserts!("abcdeabcdeabcde", 'a', "next_match_back for ASCII string",
        [next_match_back, next_match_back, next_match_back, next_match_back],
        [InRange(10, 11), InRange(5, 6),   InRange(0, 1),   Done]
    );

    search_asserts!("abcdeab", 'a', "next_reject for ASCII string",
        [next_reject,   next_reject,   next_match,    next_reject,   next_reject],
        [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done]
    );

    search_asserts!("abcdeabcdeabcde", 'a', "next_reject_back for ASCII string",
        [next_reject_back, next_reject_back, next_match_back, next_reject_back, next_reject_back, next_reject_back],
        [InRange(14, 15),  InRange(13, 14),  InRange(10, 11), InRange(9, 10),   InRange(8, 9),    InRange(7, 8)]
    );
}

// Á, 각, ก, 😀 all end in 0x81
// 🁀, ᘀ do not end in 0x81 but contain the byte
// ꁁ has 0x81 as its second and third bytes.
//
// The memchr-using implementation of next_match
// and next_match_back temporarily violate
// the property that the search is always on a unicode boundary,
// which is fine as long as this never reaches next() or next_back().
// So we test if next() is correct after each next_match() as well.
const STRESS: &str = "Áa🁀bÁꁁfg😁각กᘀ각aÁ각ꁁก😁a";

#[test]
fn test_stress_indices() {
    // this isn't really a test, more of documentation on the indices of each character in the stresstest string

    search_asserts!(STRESS, 'x', "Indices of characters in stress test",
        [next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next, next],
        [Rejects(0, 2), // Á
         Rejects(2, 3), // a
         Rejects(3, 7), // 🁀
         Rejects(7, 8), // b
         Rejects(8, 10), // Á
         Rejects(10, 13), // ꁁ
         Rejects(13, 14), // f
         Rejects(14, 15), // g
         Rejects(15, 19), // 😀
         Rejects(19, 22), // 각
         Rejects(22, 25), // ก
         Rejects(25, 28), // ᘀ
         Rejects(28, 31), // 각
         Rejects(31, 32), // a
         Rejects(32, 34), // Á
         Rejects(34, 37), // 각
         Rejects(37, 40), // ꁁ
         Rejects(40, 43), // ก
         Rejects(43, 47), // 😀
         Rejects(47, 48), // a
         Done]
    );
}

#[test]
fn test_forward_search_shared_bytes() {
    search_asserts!(STRESS, 'Á', "Forward search for two-byte Latin character",
        [next_match,    next_match,     next_match,      next_match],
        [InRange(0, 2), InRange(8, 10), InRange(32, 34), Done]
    );

    search_asserts!(STRESS, 'Á', "Forward search for two-byte Latin character; check if next() still works",
        [next_match,    next,          next_match,     next,             next_match,     next,            next_match],
        [InRange(0, 2), Rejects(2, 3), InRange(8, 10), Rejects(10, 13), InRange(32, 34), Rejects(34, 37), Done]
    );

    search_asserts!(STRESS, '각', "Forward search for three-byte Hangul character",
        [next_match,      next,            next_match,      next_match,      next_match],
        [InRange(19, 22), Rejects(22, 25), InRange(28, 31), InRange(34, 37), Done]
    );

    search_asserts!(STRESS, '각', "Forward search for three-byte Hangul character; check if next() still works",
        [next_match,      next,            next_match,      next,            next_match,      next,            next_match],
        [InRange(19, 22), Rejects(22, 25), InRange(28, 31), Rejects(31, 32), InRange(34, 37), Rejects(37, 40), Done]
    );

    search_asserts!(STRESS, 'ก', "Forward search for three-byte Thai character",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done]
    );

    search_asserts!(STRESS, 'ก', "Forward search for three-byte Thai character; check if next() still works",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done]
    );

    search_asserts!(STRESS, '😁', "Forward search for four-byte emoji",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done]
    );

    search_asserts!(STRESS, '😁', "Forward search for four-byte emoji; check if next() still works",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done]
    );

    search_asserts!(STRESS, 'ꁁ', "Forward search for three-byte Yi character with repeated bytes",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done]
    );

    search_asserts!(STRESS, 'ꁁ', "Forward search for three-byte Yi character with repeated bytes; check if next() still works",
        [next_match,      next,            next_match,      next,            next_match],
        [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done]
    );
}

#[test]
fn test_reverse_search_shared_bytes() {
    search_asserts!(STRESS, 'Á', "Reverse search for two-byte Latin character",
        [next_match_back, next_match_back, next_match_back, next_match_back],
        [InRange(32, 34), InRange(8, 10),  InRange(0, 2),   Done]
    );

    search_asserts!(STRESS, 'Á', "Reverse search for two-byte Latin character; check if next_back() still works",
        [next_match_back, next_back,       next_match_back, next_back,     next_match_back, next_back],
        [InRange(32, 34), Rejects(31, 32), InRange(8, 10),  Rejects(7, 8), InRange(0, 2),   Done]
    );

    search_asserts!(STRESS, '각', "Reverse search for three-byte Hangul character",
        [next_match_back, next_back,        next_match_back, next_match_back, next_match_back],
        [InRange(34, 37), Rejects(32, 34), InRange(28, 31),  InRange(19, 22), Done]
    );

    search_asserts!(STRESS, '각', "Reverse search for three-byte Hangul character; check if next_back() still works",
        [next_match_back, next_back,       next_match_back, next_back,       next_match_back, next_back,       next_match_back],
        [InRange(34, 37), Rejects(32, 34), InRange(28, 31), Rejects(25, 28), InRange(19, 22), Rejects(15, 19), Done]
    );

    search_asserts!(STRESS, 'ก', "Reverse search for three-byte Thai character",
        [next_match_back, next_back,       next_match_back, next_back,       next_match_back],
        [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done]
    );

    search_asserts!(STRESS, 'ก', "Reverse search for three-byte Thai character; check if next_back() still works",
        [next_match_back, next_back,       next_match_back, next_back,       next_match_back],
        [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done]
    );

    search_asserts!(STRESS, '😁', "Reverse search for four-byte emoji",
        [next_match_back, next_back,       next_match_back, next_back,       next_match_back],
        [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done]
    );

    search_asserts!(STRESS, '😁', "Reverse search for four-byte emoji; check if next_back() still works",
        [next_match_back, next_back,       next_match_back, next_back,       next_match_back],
        [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done]
    );

    search_asserts!(STRESS, 'ꁁ', "Reverse search for three-byte Yi character with repeated bytes",
        [next_match_back, next_back,       next_match_back, next_back,      next_match_back],
        [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done]
    );

    search_asserts!(STRESS, 'ꁁ', "Reverse search for three-byte Yi character with repeated bytes; check if next_back() still works",
        [next_match_back, next_back,       next_match_back, next_back,      next_match_back],
        [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done]
    );
}
<|endoftext|>