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);