leetcode_rust/
common.rs

1//! # Common Contents
2//!
3//! This module provide common structs, enums and functions used in solutions,
4//! test cases, test suites.
5//!
6//! # 公共内容
7//!
8//! 此模块提供用于解法、测试用例、测试程序使用的公共 Struct、Enum 和函数。
9//!
10
11////////////////////////////////////////////////////////////////////////////////
12
13use crate::macros::codegen_case_create_impl;
14// use crate::macros::codegen_vector_case_create_impl;
15use std::fmt::Debug;
16
17/// Test case wrapper struct
18///
19/// # Generics
20/// * `T` - type of test inputs
21/// * `G` - type of expectations, must implement `PartialEq` and `Display` traits
22/// * `P` - type of optional parameters
23pub struct Case<T, G, P> {
24    /// Input values of test case
25    pub inputs: Vec<T>,
26
27    /// Optional parameters when executing test case
28    pub params: Vec<P>,
29
30    /// Expected values of given input
31    pub values: Vec<G>,
32
33    /// Test case index (for labeling)
34    index: i32,
35}
36
37impl<T, G, P> Case<T, G, P>
38where
39    T: PartialEq + Debug,
40    G: PartialEq + Debug,
41    P: PartialEq + Debug,
42{
43    /// Create new test case with no parameters
44    ///
45    /// # Arguments
46    /// * `input` - test input
47    /// * `values` - expected values, accept single- or multi-value vector
48    pub fn new(input: T, values: Vec<G>) -> Case<T, G, P> {
49        Case {
50            inputs: vec![input],
51            params: vec![],
52            values: values,
53            index: 0,
54        }
55    }
56
57    /// Create new test case with no parameters but multiple inputs
58    ///
59    /// # Arguments
60    /// * `inputs` - test input, accept single- or multi-value vector
61    /// * `values` - expected values, accept single- or multi-value vector
62    pub fn new_multi(inputs: Vec<T>, values: Vec<G>) -> Case<T, G, P> {
63        Case {
64            inputs: inputs,
65            params: vec![],
66            values: values,
67            index: 0,
68        }
69    }
70
71    /// Create new test case with parameters
72    ///
73    /// # Arguments
74    /// * `input` - test input
75    /// * `params` - test parameters that vary among different cases
76    /// * `values` - expected values, accept single- or multi-value vector
77    pub fn new_params(input: T, params: Vec<P>, values: Vec<G>) -> Case<T, G, P> {
78        Case {
79            inputs: vec![input],
80            params: params,
81            values: values,
82            index: 0,
83        }
84    }
85
86    /// Create new test case with parameters and multi input
87    ///
88    /// # Arguments
89    /// * `inputs` - test input, accept single- or multi-value vector
90    /// * `params` - test parameters that vary among different cases
91    /// * `values` - expected values, accept single- or multi-value vector
92    pub fn new_params_multi(inputs: Vec<T>, params: Vec<P>, values: Vec<G>) -> Case<T, G, P> {
93        Case {
94            inputs: inputs,
95            params: params,
96            values: values,
97            index: 0,
98        }
99    }
100
101    /// Check if solution output matches any expectations
102    ///
103    /// # Arguments
104    /// * `&self` - inmutable borrow to object itself
105    /// * `result` - solution output
106    ///
107    /// ```
108    /// use leetcode_rust::common::Case;
109    /// let case:Case<String, String, i32> = Case::new(String::from("A"), vec![String::from("A")]);
110    /// case.is_valid(String::from("A"))
111    /// ```
112    pub fn is_valid(&self, result: G) {
113        if self.values.len() == 0 {
114            assert!(false);
115        }
116        for val in self.values.iter() {
117            if *val == result {
118                return assert!(true);
119            }
120        }
121
122        if self.values.len() == 1 {
123            if self.inputs.len() == 1 {
124                assert!(
125                    false,
126                    "[#{}] INPUT=`{:?}`, OUTPUT=`{:?}`, EXPECTATION=`{:?}`",
127                    self.index, &self.inputs[0], &result, self.values[0]
128                );
129            } else {
130                assert!(
131                    false,
132                    "[#{}] INPUT=`[{:?}]`, OUTPUT=`{:?}`, EXPECTATION=`{:?}`",
133                    self.index, self.inputs, &result, self.values[0]
134                );
135            }
136        } else {
137            assert!(
138                false,
139                "Result `{:?}` doesn't match any expectations",
140                &result
141            );
142        }
143    }
144
145    /// Returns the index value in String form.
146    pub fn label(&self) -> String {
147        self.index.to_string()
148    }
149
150    /// Returns the first element of inputs
151    pub fn input(&self) -> &T {
152        &self.inputs[0]
153    }
154}
155
156/// A easy to use test case collection struct that also provide functions for
157/// simple test case creation.
158pub struct CaseGroup<T, G, P> {
159    /// A vector containing all test cases.
160    cases: Vec<Case<T, G, P>>,
161
162    // Number of test cases included. Used when labeling each case
163    count: i32,
164}
165
166impl<T, G, P> CaseGroup<T, G, P> {
167    /// Create a new CaseGroup instance.
168    pub fn new() -> CaseGroup<T, G, P> {
169        CaseGroup {
170            cases: vec![],
171            count: 0,
172        }
173    }
174
175    /// Add existing test case instance to the collection.
176    ///
177    /// Note: an additional `index` value will be set by calling this method.
178    pub fn add(&mut self, mut case: Case<T, G, P>) {
179        self.count += 1;
180        case.index = self.count;
181        self.cases.push(case);
182    }
183
184    /// Get all test cases within current test case collection.
185    pub fn all(self) -> Vec<Case<T, G, P>> {
186        self.cases
187    }
188}
189
190/// Implement two handy methods on CaseGroup<String, G, P> struct.
191impl<G, P> CaseGroup<String, G, P>
192where
193    P: PartialEq + Debug,
194    G: PartialEq + Debug,
195{
196    /// Create a new test case (no input parameters) matching
197    /// &str and other generic types.
198    ///
199    /// # Argument
200    /// * `ipt` - this argument is set to `&str` to simplify method calls.
201    /// * `exp` - expected values in `Vec<G>` form.
202    pub fn create(&mut self, ipt: &str, exp: Vec<G>) {
203        self.add(Case::new(ipt.to_string(), exp));
204    }
205
206    /// Create a new test case (with input parameters) matching
207    /// &str and other generic types.
208    ///
209    /// # Argument
210    /// * `ipt` - this argument is set to `&str` to simplify method calls.
211    /// * `exp` - expected values in `Vec<G>` form.
212    /// * `params` - expected values in `Vec<P>` form.
213    pub fn create_param(&mut self, ipt: &str, exp: Vec<G>, params: Vec<P>) {
214        self.add(Case::new_params(ipt.to_string(), params, exp));
215    }
216
217    /// Create a new test case (no input parameters but multiple inputs)
218    /// matching &str and other generic types.
219    ///
220    /// # Argument
221    /// * `ipts` - this argument is set to `&str` to simplify method calls.
222    /// * `exp` - expected values in `Vec<G>` form.
223    pub fn create_multi(&mut self, ipts: Vec<&str>, exp: Vec<G>) {
224        self.add(Case::new_multi(
225            ipts.iter().map(|x| x.to_string()).collect(),
226            exp,
227        ));
228    }
229
230    /// Create a new test case (with input parameters and multiple inputs)
231    /// matching &str and other generic types.
232    ///
233    /// # Argument
234    /// * `ipts` - this argument is set to `&str` to simplify method calls.
235    /// * `exp` - expected values in `Vec<G>` form.
236    /// * `params` - expected values in `Vec<P>` form.
237    pub fn create_param_multi(&mut self, ipts: Vec<&str>, exp: Vec<G>, params: Vec<P>) {
238        self.add(Case::new_params_multi(
239            ipts.iter().map(|x| x.to_string()).collect(),
240            params,
241            exp,
242        ));
243    }
244}
245
246codegen_case_create_impl!(i32, i32, i32);
247codegen_case_create_impl!(i32, String, i32);
248codegen_case_create_impl!(i32, bool, i32);
249codegen_case_create_impl!(Vec<i32>, i32, i32);
250codegen_case_create_impl!(Vec<i32>, Vec<Vec<i32>>, i32);