1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! # Overview
//! This crate provides the macro `utest!(..)` Implementing the 3 phases setup/test/teardown.
//! [![Crates.io](https://img.shields.io/crates/v/test-generator.svg)](https://crates.io/crates/test-generator-utest)
//! [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/frehberg/test-generator/blob/master/LICENSE-MIT)
//! [![Apache License](http://img.shields.io/badge/license-Apache-blue.svg)](https://github.com/frehberg/test-generator/blob/master/LICENSE-APACHE)
//! [![Example](http://img.shields.io/badge/crate-Example-red.svg)](https://github.com/frehberg/test-generator/tree/master/example)
//!
//! [Documentation](https://docs.rs/test-generator-utest/)
//!
//! [Repository](https://github.com/frehberg/test-generator/)
//!
//! # Getting Started
//!
//! First of all you have to add this dependency to your `Cargo.toml`:
//!
//! ```toml
//! [dev-dependencies]
//! test-generator-utest = "^0.2"
//! ```
//! The test-functionality is supports stable Rust.

//! ```ignore
//! #![cfg(test)]
//! extern crate test_generator-utest;
//!
//! // Don't forget that procedural macros are imported with `use` statement,
//! // for example importing the macro 'test_resources'
//! #![cfg(test)]
//! use test_generator-utest::utest;
//! ```
//!

/// Macro implementing the 3 phases setup/test/teardown
///
/// # Usage
///
/// The `utest` functionality supports the stable release of Rust-compiler since version 1.30.
///
/// ```ignore
/// #[cfg(test)]
/// extern crate test_generator_utest;
///
/// // demonstrating usage of utest-harness
/// mod testsuite {
///     use std::fs::File;
///     use std::io::prelude::*;
///
///     use test_generator_utest::utest;
///
///     utest!(hello_world,
///         || setup("/tmp/hello_world.txt"),
///         |ctx_ref| test_write_hello_world(ctx_ref),
///         |ctx|teardown(ctx));
///
///     utest!(hello_europe,
///         || setup("/tmp/hello_europe.txt"),
///         test_write_hello_europe,
///         teardown);
///
///     // Defining a context structure, storing the resources
///     struct Context<'t> { file: File, name: &'t str }
///
///     // Setup - Initializing the resources
///     fn setup<'t>(filename: &str) -> Context {
///         // unwrap may panic
///         Context { file: File::create(filename).unwrap(), name: filename }
///     }
///
///     // Teardown - Releasing the resources
///     fn teardown(context: Context) {
///         let Context { file, name } = context;
///         // drop file resources explicitly
///         std::mem::drop(file);
///         // unwrap may panic
///         std::fs::remove_file(name).unwrap();
///     }
///
///     // Test - verify feature
///     fn test_write_hello_world(ctx: &Context) {
///         // may panic
///         let mut file = ctx.file.try_clone().unwrap();
///         // may panic
///         file.write_all(b"Hello, world!\n").unwrap();
///         // !!!! although this assertion will fail, the teardown function will be invoked
///         assert_eq!(1, 0);
///     }
///
///     // Test - verify feature
///     fn test_write_hello_europe(ctx: &Context) {
///         // may panic
///         let mut file = ctx.file.try_clone().unwrap();
///         // may panic
///         file.write_all(b"Hello, Europe!\n").unwrap();
///     }
/// }
/// ```
#[macro_export]
macro_rules! utest {
    ( $id: ident, $setup:expr, $test:expr, $teardown:expr ) => {
       #[test]
       fn $id() {
            let context = std::panic::catch_unwind(|| {
                $setup()
            });

            assert!(context.is_ok());

            // unwrap the internal context item
            let ctx = match context {
                Ok(ctx) => ctx,
                Err(_) => unreachable!(),
            };

            let result = std::panic::catch_unwind(|| {
                $test(&ctx)
            });

            let finalizer = std::panic::catch_unwind(|| {
                $teardown(ctx)
            });

            assert!(result.is_ok());

            assert!(finalizer.is_ok());
       }
    };
}