1- use std:: { fs , error:: Error } ;
1+ use std:: { error:: Error , fs , env } ;
22
33pub struct Config {
44 pub query : String ,
55 pub filename : String ,
6+ pub is_sensitive : bool ,
67}
78
89impl Config {
910 pub fn new ( args : & [ String ] ) -> Result < Config , & ' static str > {
1011 if args. len ( ) < 3 {
11- return Err ( "not enough arguments" )
12+ return Err ( "not enough arguments" ) ;
1213 }
1314 /*
1415 注意 vector 的第一个值 (args[0]) 是 "target/debug/grep",它是我们二进制文件的名称。
@@ -25,12 +26,182 @@ impl Config {
2526 在第一轮编写时拥有一个可以工作但有点低效的程序要比尝试过度优化代码更好一些。
2627 随着你对 Rust 更加熟练,将能更轻松的直奔合适的方法,不过现在调用 clone 是完全可以接受的。
2728 */
28- Ok ( Config { query, filename } )
29+
30+ // env::var 返回一个 Result,
31+ // 它在环境变量被设置时返回包含其值的 Ok 成员,
32+ // 并在环境变量未被设置时返回 Err 成员。
33+ let is_sensitive = env:: var ( "IS_SENSITIVE" ) . is_err ( ) ;
34+ Ok ( Config { query, filename, is_sensitive } )
2935 }
3036}
3137
3238pub fn run ( config : Config ) -> Result < ( ) , Box < dyn Error > > {
3339 let contents = fs:: read_to_string ( config. filename ) ?;
34- println ! ( "\n Contents is: \n {}" , contents) ;
40+ println ! ( "Result of search is:" ) ;
41+ let res = if config. is_sensitive {
42+ search_sensitive ( & config. query , & contents)
43+ } else {
44+ search_insensitive ( & config. query , & contents)
45+ } ;
46+ for v in res {
47+ println ! ( "{}" , v)
48+ }
3549 Ok ( ( ) )
50+
51+ }
52+
53+ pub fn search_sensitive < ' a > ( query : & str , contents : & ' a str ) -> Vec < & ' a str > {
54+ let mut res = vec ! [ ] ;
55+ for line in contents. lines ( ) {
56+ if line. contains ( query) {
57+ res. push ( line) ;
58+ }
59+ }
60+ res
61+ }
62+
63+ pub fn search_insensitive < ' a > ( query : & str , contents : & ' a str ) -> Vec < & ' a str > {
64+ let mut res = vec ! [ ] ;
65+ for line in contents. lines ( ) {
66+ if line. to_lowercase ( ) . contains ( & query. to_lowercase ( ) ) {
67+ res. push ( line) ;
68+ }
69+ }
70+ res
71+ }
72+
73+ #[ cfg( test) ]
74+ mod config_tests {
75+ use super :: * ;
76+
77+ #[ test]
78+ fn test_4_new_config_1 ( ) -> Result < ( ) , String > {
79+ let mut args: Vec < String > = vec ! [ "" . to_string( ) ] ;
80+ args. push ( "query" . to_string ( ) ) ;
81+ args. push ( "filename" . to_string ( ) ) ;
82+ let config = Config :: new ( & args) ?;
83+ assert_eq ! ( & config. query, & args[ 1 ] ) ;
84+ assert_eq ! ( & config. filename, & args[ 2 ] ) ;
85+ Ok ( ( ) )
86+ }
87+
88+ #[ test]
89+ fn test_4_new_config_2 ( ) -> Result < ( ) , String > {
90+ let mut args: Vec < String > = vec ! [ "" . to_string( ) ] ;
91+ args. push ( "query" . to_string ( ) ) ;
92+ args. push ( "filename" . to_string ( ) ) ;
93+ args. push ( "xxx" . to_string ( ) ) ;
94+ let config = Config :: new ( & args) ?;
95+ assert_eq ! ( & config. query, & args[ 1 ] ) ;
96+ assert_eq ! ( & config. filename, & args[ 2 ] ) ;
97+ Ok ( ( ) )
98+ }
99+
100+ #[ test]
101+ #[ should_panic]
102+ fn test_4_new_config_err ( ) {
103+ let mut args: Vec < String > = vec ! [ "" . to_string( ) ] ;
104+ args. push ( "query" . to_string ( ) ) ;
105+ let _res = Config :: new ( & args) ;
106+ let _config = match _res {
107+ Ok ( config) => config,
108+ Err ( err_str) => {
109+ panic ! ( "{}" , err_str)
110+ }
111+ } ;
112+ }
113+
114+ #[ test]
115+ #[ should_panic]
116+ fn test_4_new_config_err_2 ( ) {
117+ let args: Vec < String > = vec ! [ "" . to_string( ) ] ;
118+ let _res = Config :: new ( & args) ;
119+ let _config = match _res {
120+ Ok ( config) => config,
121+ Err ( err_str) => {
122+ panic ! ( "{}" , err_str)
123+ }
124+ } ;
125+ }
126+ }
127+
128+ #[ cfg( test) ]
129+ mod run_tests {
130+ use super :: * ;
131+
132+ #[ test]
133+ fn test_run ( ) -> Result < ( ) , String > {
134+ let mut args: Vec < String > = vec ! [ "" . to_string( ) ] ;
135+ args. push ( "query" . to_string ( ) ) ;
136+ args. push ( "poem.txt" . to_string ( ) ) ;
137+ let config = Config :: new ( & args) ?;
138+
139+ if let Err ( e) = run ( config) {
140+ assert_eq ! ( "" . to_string( ) , e. to_string( ) )
141+ }
142+ Ok ( ( ) )
143+ }
144+
145+ #[ test]
146+ fn test_run_err ( ) -> Result < ( ) , String > {
147+ let mut args: Vec < String > = vec ! [ "" . to_string( ) ] ;
148+ args. push ( "query" . to_string ( ) ) ;
149+ args. push ( "poemNotFound.txt" . to_string ( ) ) ;
150+ let config = Config :: new ( & args) ?;
151+
152+ if let Err ( e) = run ( config) {
153+ assert_ne ! ( "" . to_string( ) , e. to_string( ) )
154+ }
155+ Ok ( ( ) )
156+ }
157+ }
158+
159+ #[ cfg( test) ]
160+ mod search_test {
161+ use super :: * ;
162+
163+ #[ test]
164+ fn test_search_case_sensitive ( ) {
165+ let query = "us" ;
166+ let contents = "\
167+ I'm nobody! Who are you?
168+ Are you nobody, too?
169+ Then there's a pair of us - don't tell!
170+ They'd banish us, you know.
171+
172+ How dreary to be somebody!
173+ How public, like a frog
174+ To tell your name the livelong day
175+ To an admiring bog!" ;
176+ assert_eq ! (
177+ vec![
178+ " Then there's a pair of us - don't tell!" ,
179+ " They'd banish us, you know." ,
180+ ] ,
181+ search_sensitive( query, contents)
182+ )
183+ }
184+
185+ #[ test]
186+ fn test_search_case_insensitive ( ) {
187+ let query = "us" ;
188+ let contents = "US
189+ I'm nobody! Who are you?
190+ Are you nobody, too?
191+ Then there's a pair of us - don't tell!
192+ They'd banish us, you know.
193+
194+ How dreary to be somebody!
195+ How public, like a frog
196+ To tell your name the livelong day
197+ To an admiring bog!" ;
198+ assert_eq ! (
199+ vec![
200+ "US" ,
201+ " Then there's a pair of us - don't tell!" ,
202+ " They'd banish us, you know." ,
203+ ] ,
204+ search_insensitive( query, contents)
205+ )
206+ }
36207}
0 commit comments