1 #![allow(dead_code)]
2 
3 use std::env;
4 use std::io::{self, Write};
5 use std::path::PathBuf;
6 use std::process::{self, Command};
7 
8 static STRANGE: &'static str = include_str!("../examples/data/strange.csv");
9 static USPOP: &'static str = include_str!("../examples/data/uspop.csv");
10 static USPOP_NULL: &'static str =
11     include_str!("../examples/data/uspop-null.csv");
12 static USPOP_LATIN1: &'static [u8] =
13     include_bytes!("../examples/data/uspop-latin1.csv");
14 static WORLDPOP: &'static str =
15     include_str!("../examples/data/bench/worldcitiespop.csv");
16 static SMALLPOP: &'static str = include_str!("../examples/data/smallpop.csv");
17 static SMALLPOP_COLON: &'static str =
18     include_str!("../examples/data/smallpop-colon.csv");
19 static SMALLPOP_NO_HEADERS: &'static str =
20     include_str!("../examples/data/smallpop-no-headers.csv");
21 
22 #[test]
cookbook_read_basic()23 fn cookbook_read_basic() {
24     let mut cmd = cmd_for_example("cookbook-read-basic");
25     let out = cmd_output_with(&mut cmd, SMALLPOP.as_bytes());
26     assert_eq!(out.stdout().lines().count(), 10);
27 }
28 
29 #[test]
cookbook_read_serde()30 fn cookbook_read_serde() {
31     let mut cmd = cmd_for_example("cookbook-read-serde");
32     let out = cmd_output_with(&mut cmd, SMALLPOP.as_bytes());
33     assert_eq!(out.stdout().lines().count(), 10);
34 }
35 
36 #[test]
cookbook_read_colon()37 fn cookbook_read_colon() {
38     let mut cmd = cmd_for_example("cookbook-read-colon");
39     let out = cmd_output_with(&mut cmd, SMALLPOP_COLON.as_bytes());
40     assert_eq!(out.stdout().lines().count(), 10);
41 }
42 
43 #[test]
cookbook_read_no_headers()44 fn cookbook_read_no_headers() {
45     let mut cmd = cmd_for_example("cookbook-read-no-headers");
46     let out = cmd_output_with(&mut cmd, SMALLPOP_NO_HEADERS.as_bytes());
47     assert_eq!(out.stdout().lines().count(), 10);
48 }
49 
50 #[test]
cookbook_write_basic()51 fn cookbook_write_basic() {
52     let mut cmd = cmd_for_example("cookbook-write-basic");
53     let out = cmd_output(&mut cmd);
54     assert_eq!(out.stdout().lines().count(), 3);
55 }
56 
57 #[test]
cookbook_write_serde()58 fn cookbook_write_serde() {
59     let mut cmd = cmd_for_example("cookbook-write-serde");
60     let out = cmd_output(&mut cmd);
61     assert_eq!(out.stdout().lines().count(), 3);
62 }
63 
64 #[test]
tutorial_setup_01()65 fn tutorial_setup_01() {
66     let mut cmd = cmd_for_example("tutorial-setup-01");
67     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
68     assert_eq!(out.stdout().lines().count(), 100);
69 }
70 
71 #[test]
tutorial_error_01()72 fn tutorial_error_01() {
73     let mut cmd = cmd_for_example("tutorial-error-01");
74     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
75     assert_eq!(out.stdout().lines().count(), 100);
76 }
77 
78 #[test]
tutorial_error_01_errored()79 fn tutorial_error_01_errored() {
80     let data = "\
81 header1,header2
82 foo,bar
83 quux,baz,foobar
84 ";
85     let mut cmd = cmd_for_example("tutorial-error-01");
86     let out = cmd_output_with(&mut cmd, data.as_bytes());
87     assert!(out.stderr().contains("thread 'main' panicked"));
88 }
89 
90 #[test]
tutorial_error_02()91 fn tutorial_error_02() {
92     let mut cmd = cmd_for_example("tutorial-error-02");
93     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
94     assert_eq!(out.stdout().lines().count(), 100);
95 }
96 
97 #[test]
tutorial_error_02_errored()98 fn tutorial_error_02_errored() {
99     let data = "\
100 header1,header2
101 foo,bar
102 quux,baz,foobar
103 ";
104     let mut cmd = cmd_for_example("tutorial-error-02");
105     let out = cmd_output_with(&mut cmd, data.as_bytes());
106     assert!(out.stdout_failed().contains("error reading CSV from <stdin>"));
107 }
108 
109 #[test]
tutorial_error_03()110 fn tutorial_error_03() {
111     let mut cmd = cmd_for_example("tutorial-error-03");
112     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
113     assert_eq!(out.stdout().lines().count(), 100);
114 }
115 
116 #[test]
tutorial_error_03_errored()117 fn tutorial_error_03_errored() {
118     let data = "\
119 header1,header2
120 foo,bar
121 quux,baz,foobar
122 ";
123     let mut cmd = cmd_for_example("tutorial-error-03");
124     let out = cmd_output_with(&mut cmd, data.as_bytes());
125     assert!(out.stdout_failed().contains("CSV error:"));
126 }
127 
128 #[test]
tutorial_error_04()129 fn tutorial_error_04() {
130     let mut cmd = cmd_for_example("tutorial-error-04");
131     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
132     assert_eq!(out.stdout().lines().count(), 100);
133 }
134 
135 #[test]
tutorial_error_04_errored()136 fn tutorial_error_04_errored() {
137     let data = "\
138 header1,header2
139 foo,bar
140 quux,baz,foobar
141 ";
142     let mut cmd = cmd_for_example("tutorial-error-04");
143     let out = cmd_output_with(&mut cmd, data.as_bytes());
144     assert!(out.stdout_failed().contains("CSV error:"));
145 }
146 
147 #[test]
tutorial_read_01()148 fn tutorial_read_01() {
149     let mut cmd = cmd_for_example("tutorial-read-01");
150     cmd.arg(data_dir().join("uspop.csv"));
151     let out = cmd_output(&mut cmd);
152     assert_eq!(out.stdout().lines().count(), 100);
153 }
154 
155 #[test]
tutorial_read_headers_01()156 fn tutorial_read_headers_01() {
157     let mut cmd = cmd_for_example("tutorial-read-headers-01");
158     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
159     assert_eq!(out.stdout().lines().count(), 101);
160 }
161 
162 #[test]
tutorial_read_headers_02()163 fn tutorial_read_headers_02() {
164     let mut cmd = cmd_for_example("tutorial-read-headers-02");
165     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
166     assert_eq!(out.stdout().lines().count(), 102);
167 }
168 
169 #[test]
tutorial_read_delimiter_01()170 fn tutorial_read_delimiter_01() {
171     let mut cmd = cmd_for_example("tutorial-read-delimiter-01");
172     let out = cmd_output_with(&mut cmd, STRANGE.as_bytes());
173     assert_eq!(out.stdout().lines().count(), 6);
174 }
175 
176 #[test]
tutorial_read_serde_01()177 fn tutorial_read_serde_01() {
178     let mut cmd = cmd_for_example("tutorial-read-serde-01");
179     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
180     assert_eq!(out.stdout().lines().count(), 100);
181     assert!(out.stdout().lines().all(|x| x.contains("pop:")));
182 }
183 
184 #[test]
tutorial_read_serde_02()185 fn tutorial_read_serde_02() {
186     let mut cmd = cmd_for_example("tutorial-read-serde-02");
187     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
188     assert_eq!(out.stdout().lines().count(), 100);
189     assert!(out.stdout().lines().all(|x| x.starts_with("(")));
190 }
191 
192 #[test]
tutorial_read_serde_03()193 fn tutorial_read_serde_03() {
194     let mut cmd = cmd_for_example("tutorial-read-serde-03");
195     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
196     assert_eq!(out.stdout().lines().count(), 100);
197     assert!(out.stdout().lines().all(|x| x.contains("\"City\":")));
198 }
199 
200 #[test]
tutorial_read_serde_04()201 fn tutorial_read_serde_04() {
202     let mut cmd = cmd_for_example("tutorial-read-serde-04");
203     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
204     assert_eq!(out.stdout().lines().count(), 100);
205     assert!(out.stdout().lines().all(|x| x.starts_with("Record { latitude:")));
206 }
207 
208 #[test]
tutorial_read_serde_05_invalid()209 fn tutorial_read_serde_05_invalid() {
210     let mut cmd = cmd_for_example("tutorial-read-serde-invalid-01");
211     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
212     assert_eq!(out.stdout().lines().count(), 100);
213     assert!(out.stdout().lines().all(|x| x.starts_with("Record { latitude:")));
214 }
215 
216 #[test]
tutorial_read_serde_05_invalid_errored()217 fn tutorial_read_serde_05_invalid_errored() {
218     let mut cmd = cmd_for_example("tutorial-read-serde-invalid-01");
219     let out = cmd_output_with(&mut cmd, USPOP_NULL.as_bytes());
220     assert!(out.stdout_failed().contains("CSV deserialize error:"));
221 }
222 
223 #[test]
tutorial_read_serde_invalid_06()224 fn tutorial_read_serde_invalid_06() {
225     let mut cmd = cmd_for_example("tutorial-read-serde-invalid-02");
226     let out = cmd_output_with(&mut cmd, USPOP_NULL.as_bytes());
227     assert_eq!(out.stdout().lines().count(), 100);
228     assert!(out.stdout().lines().all(|x| x.starts_with("Record { latitude:")));
229 }
230 
231 #[test]
tutorial_write_01()232 fn tutorial_write_01() {
233     let mut cmd = cmd_for_example("tutorial-write-01");
234     let out = cmd_output(&mut cmd);
235     assert_eq!(out.stdout().lines().count(), 4);
236 }
237 
238 #[test]
tutorial_write_delimiter_01()239 fn tutorial_write_delimiter_01() {
240     let mut cmd = cmd_for_example("tutorial-write-delimiter-01");
241     let out = cmd_output(&mut cmd);
242     assert_eq!(out.stdout().lines().count(), 4);
243     assert!(out.stdout().lines().all(|x| x.contains('\t')));
244 }
245 
246 #[test]
tutorial_write_serde_01()247 fn tutorial_write_serde_01() {
248     let mut cmd = cmd_for_example("tutorial-write-serde-01");
249     let out = cmd_output(&mut cmd);
250     assert_eq!(out.stdout().lines().count(), 4);
251 }
252 
253 #[test]
tutorial_write_serde_02()254 fn tutorial_write_serde_02() {
255     let mut cmd = cmd_for_example("tutorial-write-serde-02");
256     let out = cmd_output(&mut cmd);
257     assert_eq!(out.stdout().lines().count(), 4);
258 }
259 
260 #[test]
tutorial_pipeline_search_01()261 fn tutorial_pipeline_search_01() {
262     let mut cmd = cmd_for_example("tutorial-pipeline-search-01");
263     cmd.arg("MA");
264     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
265     assert_eq!(out.stdout().lines().count(), 2);
266 }
267 
268 #[test]
tutorial_pipeline_search_01_errored()269 fn tutorial_pipeline_search_01_errored() {
270     let mut cmd = cmd_for_example("tutorial-pipeline-search-01");
271     cmd.arg("MA");
272     let out = cmd_output_with(&mut cmd, USPOP_LATIN1);
273     assert!(out.stdout_failed().contains("invalid utf-8"));
274 }
275 
276 #[test]
tutorial_pipeline_search_02()277 fn tutorial_pipeline_search_02() {
278     let mut cmd = cmd_for_example("tutorial-pipeline-search-02");
279     cmd.arg("MA");
280     let out = cmd_output_with(&mut cmd, USPOP_LATIN1);
281     assert_eq!(out.stdout().lines().count(), 2);
282 }
283 
284 #[test]
tutorial_pipeline_pop_01()285 fn tutorial_pipeline_pop_01() {
286     let mut cmd = cmd_for_example("tutorial-pipeline-pop-01");
287     cmd.arg("100000");
288     let out = cmd_output_with(&mut cmd, USPOP.as_bytes());
289     assert_eq!(out.stdout().lines().count(), 4);
290 }
291 
292 #[test]
tutorial_perf_alloc_01()293 fn tutorial_perf_alloc_01() {
294     let mut cmd = cmd_for_example("tutorial-perf-alloc-01");
295     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
296     assert_eq!(out.stdout(), "11\n");
297 }
298 
299 #[test]
tutorial_perf_alloc_02()300 fn tutorial_perf_alloc_02() {
301     let mut cmd = cmd_for_example("tutorial-perf-alloc-02");
302     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
303     assert_eq!(out.stdout(), "11\n");
304 }
305 
306 #[test]
tutorial_perf_alloc_03()307 fn tutorial_perf_alloc_03() {
308     let mut cmd = cmd_for_example("tutorial-perf-alloc-03");
309     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
310     assert_eq!(out.stdout(), "11\n");
311 }
312 
313 #[test]
tutorial_perf_serde_01()314 fn tutorial_perf_serde_01() {
315     let mut cmd = cmd_for_example("tutorial-perf-serde-01");
316     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
317     assert_eq!(out.stdout(), "11\n");
318 }
319 
320 #[test]
tutorial_perf_serde_02()321 fn tutorial_perf_serde_02() {
322     let mut cmd = cmd_for_example("tutorial-perf-serde-02");
323     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
324     assert_eq!(out.stdout(), "11\n");
325 }
326 
327 #[test]
tutorial_perf_serde_03()328 fn tutorial_perf_serde_03() {
329     let mut cmd = cmd_for_example("tutorial-perf-serde-03");
330     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
331     assert_eq!(out.stdout(), "11\n");
332 }
333 
334 #[test]
tutorial_perf_core_01()335 fn tutorial_perf_core_01() {
336     let mut cmd = cmd_for_example("tutorial-perf-core-01");
337     let out = cmd_output_with(&mut cmd, WORLDPOP.as_bytes());
338     assert_eq!(out.stdout(), "11\n");
339 }
340 
341 // Helper functions follow.
342 
343 /// Return the target/debug directory path.
debug_dir() -> PathBuf344 fn debug_dir() -> PathBuf {
345     env::current_exe()
346         .expect("test binary path")
347         .parent()
348         .expect("test binary directory")
349         .parent()
350         .expect("example binary directory")
351         .to_path_buf()
352 }
353 
354 /// Return the directory containing the example test binaries.
example_bin_dir() -> PathBuf355 fn example_bin_dir() -> PathBuf {
356     debug_dir().join("examples")
357 }
358 
359 /// Return the repo root directory path.
repo_dir() -> PathBuf360 fn repo_dir() -> PathBuf {
361     PathBuf::from(env!("CARGO_MANIFEST_DIR"))
362 }
363 
364 /// Return the directory containing the example data.
data_dir() -> PathBuf365 fn data_dir() -> PathBuf {
366     repo_dir().join("examples").join("data")
367 }
368 
369 /// Return a command ready to execute the given example test binary.
370 ///
371 /// The command's current directory is set to the repo root.
cmd_for_example(name: &str) -> Command372 fn cmd_for_example(name: &str) -> Command {
373     let mut cmd = Command::new(example_bin_dir().join(name));
374     cmd.current_dir(repo_dir());
375     cmd
376 }
377 
378 /// Return the (stdout, stderr) of running the command as a string.
379 ///
380 /// If the command has a non-zero exit code, then this function panics.
cmd_output(cmd: &mut Command) -> Output381 fn cmd_output(cmd: &mut Command) -> Output {
382     cmd.stdout(process::Stdio::piped());
383     cmd.stderr(process::Stdio::piped());
384     let child = cmd.spawn().expect("command spawns successfully");
385     Output::new(cmd, child)
386 }
387 
388 /// Like cmd_output, but sends the given data as stdin to the given child.
cmd_output_with(cmd: &mut Command, data: &[u8]) -> Output389 fn cmd_output_with(cmd: &mut Command, data: &[u8]) -> Output {
390     cmd.stdin(process::Stdio::piped());
391     cmd.stdout(process::Stdio::piped());
392     cmd.stderr(process::Stdio::piped());
393     let mut child = cmd.spawn().expect("command spawns successfully");
394     {
395         let stdin = child.stdin.as_mut().expect("failed to get stdin");
396         stdin.write_all(data).expect("failed to write to stdin");
397     }
398     Output::new(cmd, child)
399 }
400 
401 struct Output {
402     stdout: String,
403     stderr: String,
404     command: String,
405     status: process::ExitStatus,
406 }
407 
408 impl Output {
409     /// Return the (stdout, stderr) of running the given child as a string.
410     ///
411     /// If the command has a non-zero exit code, then this function panics.
new(cmd: &mut Command, child: process::Child) -> Output412     fn new(cmd: &mut Command, child: process::Child) -> Output {
413         let out = child.wait_with_output().expect("command runs successfully");
414         let stdout =
415             String::from_utf8(out.stdout).expect("valid utf-8 (stdout)");
416         let stderr =
417             String::from_utf8(out.stderr).expect("valid utf-8 (stderr)");
418         Output {
419             stdout: stdout,
420             stderr: stderr,
421             command: format!("{:?}", cmd),
422             status: out.status,
423         }
424     }
425 
stdout(&self) -> &str426     fn stdout(&self) -> &str {
427         if !self.status.success() {
428             panic!(
429                 "\n\n==== {:?} ====\n\
430                  command failed but expected success!\
431                  \n\ncwd: {}\
432                  \n\nstatus: {}\
433                  \n\nstdout: {}\
434                  \n\nstderr: {}\
435                  \n\n=====\n",
436                 self.command,
437                 repo_dir().display(),
438                 self.status,
439                 self.stdout,
440                 self.stderr
441             );
442         }
443         &self.stdout
444     }
445 
stdout_failed(&self) -> &str446     fn stdout_failed(&self) -> &str {
447         if self.status.success() {
448             panic!(
449                 "\n\n==== {:?} ====\n\
450                  command succeeded but expected failure!\
451                  \n\ncwd: {}\
452                  \n\nstatus: {}\
453                  \n\nstdout: {}\
454                  \n\nstderr: {}\
455                  \n\n=====\n",
456                 self.command,
457                 repo_dir().display(),
458                 self.status,
459                 self.stdout,
460                 self.stderr
461             );
462         }
463         &self.stdout
464     }
465 
stderr(&self) -> &str466     fn stderr(&self) -> &str {
467         if self.status.success() {
468             panic!(
469                 "\n\n==== {:?} ====\n\
470                  command succeeded but expected failure!\
471                  \n\ncwd: {}\
472                  \n\nstatus: {}\
473                  \n\nstdout: {}\
474                  \n\nstderr: {}\
475                  \n\n=====\n",
476                 self.command,
477                 repo_dir().display(),
478                 self.status,
479                 self.stdout,
480                 self.stderr
481             );
482         }
483         &self.stderr
484     }
485 }
486 
487 /// Consume the reader given into a string.
read_to_string<R: io::Read>(mut rdr: R) -> String488 fn read_to_string<R: io::Read>(mut rdr: R) -> String {
489     let mut s = String::new();
490     rdr.read_to_string(&mut s).unwrap();
491     s
492 }
493