file_diff/
lib.rs

1// (c) 2014, Ethan Pailes
2// All Rights Reserved
3//
4// Licensed under the "Revised" BSD 3-clause licence. See LICENCE file at the
5// root directory of this repository.
6
7//! File Diff
8//!
9//! This module provides an atomic file diffing function for use in unit tests.
10//!
11//! The diff_files() function takes two file handles and determines returns true
12//! if they point to identical files.
13//!
14//! ```
15//! use file_diff::{diff_files};
16//! use std::fs::{File};
17//!
18//! let mut file1 = match File::open("./src/lib.rs") {
19//!     Ok(f) => f,
20//!     Err(e) => panic!("{}", e),
21//! };
22//! let mut file2 = match File::open("./src/lib.rs") {
23//!     Ok(f) => f,
24//!     Err(e) => panic!("{}", e),
25//! };
26//!
27//! diff_files(&mut file1, &mut file2);
28//! ```
29//!
30//! The diff() function takes string representations of the files and returns true
31//! if the strings represent real files and those files are identical.
32//!
33//! ```
34//! use file_diff::{diff};
35//!
36//! diff("./src/lib.rs", "./src/lib.rs");
37//! ```
38
39use std::io::Read;
40
41
42
43use std::fs::{File};
44
45
46/// Takes two file arguments and returns true if the two files are identical.
47pub fn diff_files(f1: &mut File, f2: &mut File) -> bool {
48
49    let mut buff1 : &mut [u8] = &mut [0; 1024];
50    let mut buff2 : &mut [u8] = &mut [0; 1024];
51    
52    loop {
53
54        match f1.read(buff1) {
55            Err(_) => return false,
56            Ok(f1_read_len) => match f2.read(buff2) {
57                Err(_) => return false,
58                Ok(f2_read_len) => {
59                    if f1_read_len != f2_read_len {
60                        return false;
61                    }
62                    if f1_read_len == 0 {
63                        return true;
64                    }
65                    if &buff1[0..f1_read_len] != &buff2[0..f2_read_len] {
66                        return false;
67                    }
68                }
69            }
70        }
71    }
72}
73
74/// Takes two string filepaths and returns true if the two files are identical and exist.
75pub fn diff(f1: &str, f2: &str) -> bool {
76    let mut fh1 = File::open(f1);
77    let mut fh2 = File::open(f2);
78
79    fh1.as_mut().and_then(|file1|
80        fh2.as_mut().and_then(|file2|
81            Ok(diff_files(file1, file2)))).unwrap_or(false)
82}
83
84#[cfg(test)]
85mod tests {
86    const LIB_RS: &'static str = "./src/lib.rs";
87    const CARGO_FILE: &'static str = "./Cargo.toml";
88    const RUST_BIN_FILE: &'static str = "./testdata/rust_hello";
89    const C_BIN_FILE: &'static str = "./testdata/c_hello";
90    const C_BIN_FILE_COPY: &'static str = "./testdata/c_hello_copy";
91
92    #[test]
93    fn diff_the_same_text_file() { assert!(super::diff(LIB_RS, LIB_RS)); }
94
95    #[test]
96    fn diff_the_same_binary_file() { assert!(super::diff(RUST_BIN_FILE, RUST_BIN_FILE)); }
97
98    #[test]
99    fn diff_identical_binary_files() { assert!(super::diff(C_BIN_FILE, C_BIN_FILE_COPY)); }
100
101    #[test]
102    fn diff_different_text_files() { assert!( !super::diff(LIB_RS, CARGO_FILE)); }
103
104    #[test]
105    fn diff_different_binary_files() { assert!( !super::diff(RUST_BIN_FILE, C_BIN_FILE)); }
106}
107