+++ /dev/null
-use criterion::{black_box, criterion_group, criterion_main, Criterion};
-
-pub fn build_dir(c: &mut Criterion) {
-    let dir = std::path::PathBuf::from("files/bench_site")
-        .canonicalize()
-        .unwrap();
-
-    let mut opts = metaforge::Options::new();
-    opts.root = dir.clone();
-    opts.source = dir.join("source");
-    opts.build = dir.join("build");
-    opts.pattern = dir.join("pattern");
-    opts.clean = true;
-
-    c.bench_function("build dir", |b| {
-        if opts.build.exists() {
-            std::fs::remove_dir_all(&opts.build).expect("clean build dir");
-        }
-
-        std::fs::create_dir(&opts.build).expect("create build dir");
-        b.iter(|| metaforge::build_site(black_box(&opts)).unwrap())
-    });
-}
-
-criterion_group! {
-    name = benches;
-    config = Criterion::default().sample_size(10).measurement_time(core::time::Duration::from_secs(140));
-    targets =  build_dir
-}
-
-criterion_main!(benches);
 
--- /dev/null
+#{ ignore = true }
+
+This file shouldn't be passed on
 
+++ /dev/null
-use crate::{MetaError, Options};
-use eyre::Result;
-use rayon::prelude::*;
-use std::{fs, path::PathBuf};
-
-use super::*;
-
-#[derive(Debug, Clone)]
-pub struct DirNode<'a> {
-    path: PathBuf,
-    opts: &'a Options,
-    global: MetaFile<'a>,
-    files: Vec<MetaFile<'a>>,
-    dirs: Vec<DirNode<'a>>,
-}
-
-impl<'a> DirNode<'a> {
-    pub fn build(path: PathBuf, opts: &'a Options) -> Result<Self> {
-        assert!(path.is_dir() && path.exists());
-
-        // copy over directory structure from source dir
-        let build_dir = opts.build.join(path.strip_prefix(&opts.source)?);
-        if !build_dir.exists() {
-            fs::create_dir_all(build_dir)?;
-        }
-
-        let files: Vec<MetaFile> = Vec::new();
-        let dirs: Vec<DirNode> = Vec::new();
-        let global = MetaFile::new(opts);
-
-        Ok(Self {
-            path,
-            opts,
-            global,
-            files,
-            dirs,
-        })
-    }
-
-    // parses all contained files and directories and pushes
-    // parsed structures into the files and directories vectors
-    pub fn map(&mut self, global: &'a MetaFile) -> Result<()> {
-        if self.opts.parallel {}
-
-        for f in fs::read_dir(&self.path)? {
-            let file = f?.path();
-
-            if file.is_dir() {
-                let dir = DirNode::build(file, self.opts)?;
-                self.dirs.push(dir);
-            } else if file.file_name().and_then(|f| f.to_str()) == Some("default.meta") {
-                let mut new_global = MetaFile::build(file, self.opts)?;
-                new_global.merge(global);
-                self.global = new_global;
-            } else if file.extension().and_then(|f| f.to_str()) == Some("meta") {
-                let file = MetaFile::build(file, self.opts)?;
-                self.files.push(file)
-            }
-        }
-
-        Ok(())
-    }
-
-    pub fn build_files(&mut self) -> Result<()> {
-        for file in self.files.iter_mut() {
-            file.merge(&self.global);
-            match file.construct() {
-                Ok(str) => {
-                    fs::write(file.dest()?, str)?;
-                }
-                Err(e) => {
-                    // print a line to stderr about failure but continue with other files
-                    if self.opts.force {
-                        eprintln!("ignoring {}: {}", file.path.display(), e);
-                        continue;
-                    } else {
-                        // we raise an ignored error to quickly abort any file parsing
-                        if let MetaError::Ignored = *e {
-                            continue;
-                        // anything else gets wrapped up and passed up the calling chain
-                        } else {
-                            return Err(e.into());
-                        }
-                    }
-                }
-            }
-        }
-        Ok(())
-    }
-
-    pub fn build_dir(&'a mut self) -> Result<()> {
-        self.build_files()?;
-
-        for dir in self.dirs.iter_mut() {
-            dir.map(&self.global)?;
-            dir.build_dir()?;
-        }
-
-        Ok(())
-    }
-}
 
 pub enum MetaError {
     #[error("unknown internal error")]
     Unknown,
-    #[error("internal break switch")]
+    #[error("file ignored")]
     Ignored,
     #[error("internal filetype error")]
     Filetype,
 
     // parses all contained files and directories and pushes
     // parsed structures into the files and directories vectors
     pub fn map(&mut self, global: &'a MetaFile) -> Result<()> {
+        if self.opts.parallel {}
+
         for f in fs::read_dir(&self.path)? {
             let file = f?.path();
 
     pub fn build_files(&mut self) -> Result<()> {
         for file in self.files.iter_mut() {
             file.merge(&self.global);
+            println!(":constructing {:?}", &file);
             match file.construct() {
                 Ok(str) => {
                     fs::write(file.dest()?, str)?;
                         eprintln!("ignoring {}: {}", file.path.display(), e);
                         continue;
                     } else {
-                        // we raise an ignored error to quickly abort any file parsing
-                        if let MetaError::Ignored = *e {
-                            continue;
-                        // anything else gets wrapped up and passed up the calling chain
-                        } else {
-                            return Err(e.into());
+                        match *e {
+                            MetaError::Ignored => continue,
+                            e => return Err(e.into()),
                         }
                     }
                 }
 
     };
 );
 
+macro_rules! panic_test (
+    ($name:ident, $file:expr,$test:literal) => {
+        #[test]
+        #[should_panic]
+        fn $name() {
+            let dir = PathBuf::from("files/test_site").canonicalize().unwrap_or_default();
+
+            let mut opts = Options::new();
+            opts.root = dir.clone();
+            opts.source = dir.join("source");
+            opts.build = dir.join("build");
+            opts.pattern = dir.join("pattern");
+
+            let test_dir = opts.source.join("unit_tests");
+            let mut path = test_dir.join($file);
+            path.set_extension("meta");
+            let file = MetaFile::build(path, &opts).unwrap();
+            assert_eq!(file.construct().unwrap(), $test);
+        }
+    };
+);
+
 unit_test!(blank_pattern, "blank/blank_pattern", "");
 unit_test!(blank_variable, "blank/blank_variable", "<html>\n</html>\n");
 unit_test!(blank_array, "blank/blank_array", "<html>\n</html>\n");
     "<html>\n<p>GOOD</p>\n</html>\n"
 );
 
+panic_test!(ignore, "ignore.meta", "");
+
 #[test]
 fn test_filetype_header() -> Result<()> {
     let dir = PathBuf::from("files/test_site").canonicalize()?;