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