#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate q_debug;
use chrono;
use regex::Regex;
use std::env;
use std::fs;
use std::io::Read;
use std::sync::Mutex;
use std::thread::sleep;
use std::time;
lazy_static! {
static ref QFILE: Mutex<fs::File> = {
Mutex::new(
fs::OpenOptions::new()
.read(true)
.append(true)
.create(true)
.open(env::temp_dir().join("q"))
.unwrap(),
)
};
}
macro_rules! read_log {
($e:expr) => {{
let mut file = QFILE.lock().unwrap();
let mut output = String::new();
file.read_to_string(&mut output).unwrap();
output.clear();
$e;
file.read_to_string(&mut output).unwrap();
output.trim().to_owned()
}};
}
lazy_static! {
static ref HEADER_RE: Regex = Regex::new(
r"\[(?P<time>\d{2}:\d{2}:\d{2}) (?P<thread_id>.*) tests/smoke\.rs (?P<funcp>.*):(?P<lineno>\d+)\]"
)
.unwrap();
static ref LOG_LINE_RE: Regex = Regex::new(r">( (?P<msg>.*))?").unwrap();
}
fn check_header_line(header_line: &str, func_path: &str, lineno: u32) {
let caps = HEADER_RE.captures(&header_line.trim()).unwrap();
assert_eq!(&caps["funcp"], func_path);
assert_eq!(caps["lineno"].parse::<u32>().unwrap(), lineno);
}
fn check_log_line(log_line: &str, msg: &str) {
println!("{}", log_line);
let caps = LOG_LINE_RE.captures(&log_line.trim()).unwrap();
if msg == "" {
assert_eq!(caps.name("msg"), None);
} else {
assert_eq!(&caps["msg"], msg);
}
}
#[test]
fn test_empty_call() {
let line_before_call = line!();
let output = read_log!(q!());
check_header_line(&output, "smoke::test_empty_call", line_before_call + 1);
check_log_line(&output, "");
}
#[test]
fn test_literal() {
let output = read_log!(q!("Test message"));
check_log_line(&output, "\"Test message\"");
assert_eq!(q!("Test message"), "Test message");
}
#[test]
fn test_ident() {
let x = 1;
let output = read_log!(q!(x));
check_log_line(&output, "x = 1");
assert_eq!(q!(x), x);
}
#[test]
fn test_expr() {
fn add_two(x: i32) -> i32 {
x + 2
}
let output = read_log!(q!(add_two(2)));
check_log_line(&output, "add_two(2) = 4");
assert_eq!(q!(add_two(2)), 4);
}
#[test]
fn test_header_interval() {
q_debug::set_header_interval(chrono::Duration::seconds(2));
let output_1 = read_log!(q!()); let output_2 = read_log!(q!());
q_debug::set_header_interval(chrono::Duration::milliseconds(200));
sleep(time::Duration::from_millis(250));
let output_3 = read_log!(q!()); let output_4 = read_log!(q!());
assert!(HEADER_RE.is_match(&output_1));
assert!(!HEADER_RE.is_match(&output_2));
assert!(HEADER_RE.is_match(&output_3));
assert!(!HEADER_RE.is_match(&output_4));
}
#[test]
fn test_header_on_function_or_module_change() {
q_debug::set_header_interval(chrono::Duration::seconds(2));
let output_1 = read_log!(q!()); let output_2 = read_log!(q!());
fn foo() -> String {
read_log!(q!())
}
let output_3 = foo(); let output_4 = read_log!(q!()); let output_5 = read_log!(q!());
mod bar {
use super::*;
pub fn baz() -> String {
read_log!(q!())
}
}
let output_6 = bar::baz(); let output_7 = read_log!(q!()); let output_8 = read_log!(q!());
assert!(HEADER_RE.is_match(&output_1));
assert!(!HEADER_RE.is_match(&output_2));
assert!(HEADER_RE.is_match(&output_3));
assert!(HEADER_RE.is_match(&output_4));
assert!(!HEADER_RE.is_match(&output_5));
assert!(HEADER_RE.is_match(&output_6));
assert!(HEADER_RE.is_match(&output_7));
assert!(!HEADER_RE.is_match(&output_8));
}