Repository: xd009642/tarpaulin
Pull request #1174 (2023-01-09 16:36:22)

Update release workflow
<!--- When contributing to tarpaulin all contributions should branch off the -->
<!--- develop branch as master is only used for releases. --> 

<!--- Check CONTRIBUTING.md for more information-->

<!--- Please describe the changes in the PR and them motivation below -->

As said in https://github.com/taiki-e/install-action/pull/42#issuecomment-1372184541, I would like to help improve release staff. (If work on this is in progress on your end and you do not need this patch, feel free to close this PR.)

This patch updates the release workflow and makes the release work on x86_64 linux-gnu/linux-musl/macos/windows and aarch64 linux-gnu/linux-musl/macos. The following are specific changes:

- Add x86_64/aarch64 linux-musl
  - Closes https://github.com/xd009642/tarpaulin/issues/1130
- Remove aarch64 windows.
  - ~~aarch64 linux fails to build [^1]: https://github.com/taiki-e/tarpaulin/actions/runs/3875026523/jobs/6606999714~~ EDIT: fixed in https://github.com/xd009642/tarpaulin/pull/1174/commits/5476833acd2cf994ebecba6949d29aeb74a857e7
  - aarch64 windows doesn't support profiler_builtins
- Enable vendored-openssl feature
  - At least on linux-musl we cannot build without it. [^1]
  - For now, I enabled this for all targets, but it is possible to control whether this is enabled or disabled per target.
- Use the latest taiki-e/create-gh-release-action and actions/checkout
- Update binstall metadata to match new archive names.

I tested this with a fork by temporarily disabling the configs around `cargo publish`; here is generated release: https://github.com/taiki-e/tarpaulin/releases/tag/0.23.1
I also confirmed that the binaries created in the above test pass install-action's CI in all environments: https://github.com/taiki-e/install-action/actions/runs/3875547860/jobs/6608244922

cc https://github.com/taiki-e/install-action/pull/42
fyi @thomcc @NobodyXu 

[^1]: [These targets are included in the test matrix in rust.yml](https://github.com/xd009642/tarpaulin/blob/5f5e566e173d34afe7919b480b40336c4aaf6537/.github/workflows/rust.yml#L21-L22), but the job is actually testing the host target instead of these targets because [the --target option is not passed to cargo](https://github.com/xd009642/tarpaulin/blob/5f5e566e173d34afe7919b480b40336c4aaf6537/.github/workflows/rust.yml#L33-L39).


taiki-e: > But maybe that's because they're building on target not via cross and my detecting of x64_64 in my build.rs doesn't work when cross compiling 🤔

Ah, #[cfg] in the build script refers to the host target on which the build script is run, so the following line seems to be causing the problem when cross-compiling.

https://github.com/xd009642/tarpaulin/blob/5f5e566e173d34afe7919b480b40336c4aaf6537/build.rs#L13-L14
xd009642: Yeah that what I was concerned about... Is there a way in build scripts to access the _actual_ target architecture you're compiling for :thinking: 
taiki-e: > Is there a way in build scripts to access the _actual_ target architecture you're compiling for 🤔

Cargo sets those information via [`CARGO_CFG_*` environment variables](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts).
taiki-e: Fixed build scripts and re-added aarch64 linux/macos to the workflow. 

I can confirm that the cross-compilation issue on aarch64 linux has been fixed: https://github.com/taiki-e/tarpaulin/actions/runs/3876026314/jobs/6609363516

Patch:
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..9127556
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,25 @@
+name: Coverage
+on:
+  push:
+    branches:
+      - "*"
+env:
+  RUST_BACKTRACE: 1
+jobs:
+  coverage:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        version:
+          - nightly
+        target:
+          - x86_64-unknown-linux-gnu
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: ${{ matrix.version }}
+      - name: coverage
+        run: cargo run --release -- tarpaulin --engine llvm --follow-exec --post-test-delay 10 --coveralls ${{ secrets.COVERALLS_TOKEN }} 
+
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1bb1321..b102684 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,7 +12,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: taiki-e/create-gh-release-action@v1.3.0
+      - uses: taiki-e/create-gh-release-action@v1
         with:
           changelog: CHANGELOG.md
         env:
@@ -20,7 +20,7 @@ jobs:
   crates:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: publish package to crates
         run: |
           cargo package
@@ -31,26 +31,33 @@ jobs:
     needs:
       - create-release
     strategy:
+      fail-fast: false
       matrix:
         include:
           - target: x86_64-unknown-linux-gnu
             os: ubuntu-latest
+          - target: x86_64-unknown-linux-musl
+            os: ubuntu-latest
           - target: x86_64-apple-darwin
             os: macos-latest
           - target: x86_64-pc-windows-msvc
             os: windows-latest
           - target: aarch64-unknown-linux-gnu
             os: ubuntu-latest
+          - target: aarch64-unknown-linux-musl
+            os: ubuntu-latest
           - target: aarch64-apple-darwin
             os: macos-latest
-          - target: aarch64-pc-windows-msvc
-            os: windows-latest
+          - target: universal-apple-darwin
+            os: macos-latest
     runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@stable
       - uses: taiki-e/upload-rust-binary-action@v1
         with:
-          bin: rust-sandbox
+          bin: cargo-tarpaulin
           target: ${{ matrix.target }}
+          features: vendored-openssl
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 10d6287..9939130 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -3,7 +3,7 @@ on:
   push:
     branches:
       - "*"
-  pull_request_target:
+  pull_request:
 env:
   RUST_BACKTRACE: 1
 
@@ -23,15 +23,12 @@ jobs:
       fail-fast: false
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ matrix.version }}
-          override: true
           components: rustfmt
       - name: cache
         uses: Swatinem/rust-cache@v2
-      - name: build
-        run: cargo build
       - name: test
         run: cargo test
       - name: ignored test
@@ -60,14 +57,11 @@ jobs:
       fail-fast: false
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ matrix.version }}
-          override: true
       - name: cache
         uses: Swatinem/rust-cache@v2
-      - name: build
-        run: cargo build
       - name: test
         run: cargo test
       - uses: actions/upload-artifact@v3
@@ -90,38 +84,18 @@ jobs:
       fail-fast: false
     steps:
       - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ matrix.version }}
-          override: true
       - name: cache
         uses: Swatinem/rust-cache@v2
-      - name: build
-        run: cargo build
       - name: test
-        run: cargo test
+        run: cargo test || true
       - uses: actions/upload-artifact@v3
-        if: failure()
+        #if: failure()
         with:
           name: mac ${{ matrix.version }}
           retention-days: 3
           path: |
               tests/data/
               !tests/data/**/*.rs
-  coverage:
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        version:
-          - nightly
-        target:
-          - x86_64-unknown-linux-gnu
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: ${{ matrix.version }}
-          override: true
-      - name: coverage
-        run: cargo run --release -- tarpaulin --engine llvm --follow-exec --post-test-delay 10 --coveralls ${{ secrets.COVERALLS_TOKEN }} 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a62954..c702337 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ file.
 ### Added
 - Merge rustdocflags field from `cargo/config.toml` with env tarpaulin sets
 
+### Changed
+- Create profraw folder if it doesn't exist
+- Normalise UNC paths provided via env or CLI args
+
 ## [0.23.1] 2022-11-18
 ### Changed
 - Fix linux cfg instead of ptrace\_supported cfg on event log for ARM linux builds
diff --git a/Cargo.lock b/Cargo.lock
index b2dfc15..c8fe391 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -120,7 +120,7 @@ dependencies = [
  "memmap",
  "nix",
  "num_cpus",
- "object 0.30.1",
+ "object 0.30.2",
  "proc-macro2",
  "procfs",
  "quick-xml",
@@ -342,9 +342,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.15.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
+checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b"
 dependencies = [
  "bitflags",
  "libc",
@@ -508,9 +508,9 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
 
 [[package]]
 name = "libgit2-sys"
-version = "0.14.0+1.5.0"
+version = "0.14.1+1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b"
+checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
 dependencies = [
  "cc",
  "libc",
@@ -631,9 +631,9 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.26.1"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
+checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -692,9 +692,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.30.1"
+version = "0.30.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a"
+checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83"
 dependencies = [
  "flate2",
  "memchr",
@@ -755,9 +755,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.49"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
+checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
 dependencies = [
  "unicode-ident",
 ]
@@ -812,9 +812,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.7.0"
+version = "1.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
 dependencies = [
  "aho-corasick",
  "memchr",
diff --git a/Cargo.toml b/Cargo.toml
index fc03c3f..399be43 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@ clap = "2.34.0"
 coveralls-api = "0.5.0"
 fallible-iterator = "0.2.0"
 gimli = "0.27.0"
-git2 = "0.15"
+git2 = "0.16"
 humantime-serde = "1"
 indexmap = { version = "~1.8", features = ["serde-1"] }
 lazy_static = "1.0"
@@ -50,7 +50,7 @@ walkdir = "2.3.2"
 
 [target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies]
 libc = "0.2.94"
-nix = {version = "0.26.1", default-features = false, features = ["sched", "signal", "ptrace", "personality"]}
+nix = {version = "0.26.2", default-features = false, features = ["sched", "signal", "ptrace", "personality"]}
 procfs = "0.14"
 
 [features]
@@ -63,7 +63,10 @@ rustc_version = "0.4"
 [dev-dependencies]
 rusty-fork = "0.3.0"
 
-[package.metadata.binstall."x86_64-unknown-linux-gnu"]
-pkg-url = "{ repo }/releases/download/{ version }/cargo-tarpaulin-{ version }-travis.tar.gz"
-bin-dir = "cargo-tarpaulin"
+[package.metadata.binstall]
+pkg-url = "{ repo }/releases/download/{ version }/cargo-tarpaulin-{ target }.tar.gz"
+bin-dir = "cargo-tarpaulin{ binary-ext }"
 pkg-fmt = "tgz"
+
+[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
+pkg-fmt = "zip"
diff --git a/README.md b/README.md
index 9089884..e35f6e8 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
 [![License:MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
 [![Docker](https://img.shields.io/docker/automated/xd009642/tarpaulin.svg)](https://hub.docker.com/r/xd009642/tarpaulin/)
 [![Developers Wiki](https://img.shields.io/badge/development-wiki-yellowgreen.svg)](https://github.com/xd009642/tarpaulin/wiki/Developers)
+[![Coverage Status](https://coveralls.io/repos/github/xd009642/tarpaulin/badge.svg?branch=develop)](https://coveralls.io/github/xd009642/tarpaulin?branch=develop)
 
 Tarpaulin is a code coverage reporting tool for the Cargo build system, named 
 for a waterproof cloth used to cover cargo on a ship. Currently, tarpaulin
diff --git a/build.rs b/build.rs
index 59346fa..022e0be 100644
--- a/build.rs
+++ b/build.rs
@@ -1,4 +1,5 @@
 use rustc_version::{version, version_meta, Channel};
+use std::env;
 
 fn main() {
     assert!(version().expect("Couldn't get compiler version").major >= 1);
@@ -10,6 +11,9 @@ fn main() {
         println!("cargo:rustc-cfg=nightly");
     }
 
-    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-    println!("cargo:rustc-cfg=ptrace_supported");
+    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH not set");
+    let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set");
+    if target_os == "linux" && target_arch == "x86_64" {
+        println!("cargo:rustc-cfg=ptrace_supported");
+    }
 }
diff --git a/src/cargo.rs b/src/cargo.rs
index 6c9475c..2f3bb47 100644
--- a/src/cargo.rs
+++ b/src/cargo.rs
@@ -1,6 +1,6 @@
 use crate::config::*;
 use crate::errors::RunError;
-use crate::path_utils::get_source_walker;
+use crate::path_utils::{fix_unc_path, get_source_walker};
 use cargo_metadata::{diagnostic::DiagnosticLevel, CargoOpt, Message, Metadata, MetadataCommand};
 use lazy_static::lazy_static;
 use regex::Regex;
@@ -224,7 +224,8 @@ pub fn get_tests(config: &Config) -> Result<CargoOutput, RunError> {
             }
         }
     }
-    let manifest = config.manifest.as_path().to_str().unwrap_or("Cargo.toml");
+    let man_binding = config.manifest();
+    let manifest = man_binding.as_path().to_str().unwrap_or("Cargo.toml");
     let metadata = MetadataCommand::new()
         .manifest_path(manifest)
         .features(CargoOpt::AllFeatures)
@@ -280,7 +281,7 @@ fn run_cargo(
                         }
                         result
                             .test_binaries
-                            .push(TestBinary::new(PathBuf::from(path), ty));
+                            .push(TestBinary::new(fix_unc_path(path.as_std_path()), ty));
                         package_ids.push(Some(art.package_id.clone()));
                     }
                 }
@@ -343,7 +344,7 @@ fn run_cargo(
                 res.cargo_dir = package
                     .manifest_path
                     .parent()
-                    .map(|x| PathBuf::from(x.to_path_buf()));
+                    .map(|x| fix_unc_path(x.as_std_path()));
                 res.pkg_name = Some(package.name.clone());
                 res.pkg_version = Some(package.version.to_string());
                 res.pkg_authors = Some(package.authors.clone());
@@ -375,7 +376,7 @@ fn run_cargo(
         let should_panics = get_attribute_candidates(&dir_entries, config, "should_panic");
         let no_runs = get_attribute_candidates(&dir_entries, config, "no_run");
         for dt in &dir_entries {
-            let mut tb = TestBinary::new(dt.path().to_path_buf(), ty);
+            let mut tb = TestBinary::new(fix_unc_path(dt.path()), ty);
 
             if let Some(meta) = DocTestBinaryMeta::new(dt.path()) {
                 if no_runs
@@ -393,7 +394,7 @@ fn run_cargo(
             let mut current_dir = dt.path();
             loop {
                 if current_dir.is_dir() && current_dir.join("Cargo.toml").exists() {
-                    tb.cargo_dir = Some(current_dir.to_path_buf());
+                    tb.cargo_dir = Some(fix_unc_path(current_dir));
                     break;
                 }
                 match current_dir.parent() {
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 6783853..71fb376 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -31,7 +31,7 @@ pub struct Config {
     pub name: String,
     /// Path to the projects cargo manifest
     #[serde(rename = "manifest-path")]
-    pub manifest: PathBuf,
+    manifest: PathBuf,
     /// Path to a tarpaulin.toml config file
     pub config: Option<PathBuf>,
     /// Path to the projects cargo manifest
@@ -413,7 +413,7 @@ impl Config {
     }
 
     pub fn target_dir(&self) -> PathBuf {
-        if let Some(s) = &self.target_dir {
+        let res = if let Some(s) = &self.target_dir {
             s.clone()
         } else {
             match *self.get_metadata() {
@@ -421,11 +421,12 @@ impl Config {
                 _ => self
                     .manifest
                     .parent()
-                    .map(Path::to_path_buf)
+                    .map(fix_unc_path)
                     .unwrap_or_default()
                     .join("target"),
             }
-        }
+        };
+        fix_unc_path(&res)
     }
 
     /// Get directory profraws are stored in
@@ -447,7 +448,7 @@ impl Config {
 
     pub fn doctest_dir(&self) -> PathBuf {
         // https://github.com/rust-lang/rust/issues/98690
-        let mut result = fix_unc_path(&self.target_dir());
+        let mut result = self.target_dir();
         result.push("doctests");
         result
     }
@@ -463,11 +464,21 @@ impl Config {
         }
         self.metadata.borrow()
     }
+
     pub fn root(&self) -> PathBuf {
-        match *self.get_metadata() {
+        let res = match *self.get_metadata() {
             Some(ref meta) => PathBuf::from(meta.workspace_root.clone()),
             _ => self.manifest.parent().map(fix_unc_path).unwrap_or_default(),
-        }
+        };
+        fix_unc_path(&res)
+    }
+
+    pub fn manifest(&self) -> PathBuf {
+        fix_unc_path(&self.manifest)
+    }
+
+    pub fn set_manifest(&mut self, manifest: PathBuf) {
+        self.manifest = manifest;
     }
 
     pub fn get_packages(&self) -> Vec<Package> {
@@ -478,11 +489,12 @@ impl Config {
     }
 
     pub fn output_dir(&self) -> PathBuf {
-        if let Some(ref path) = self.output_directory {
+        let path = if let Some(ref path) = self.output_directory {
             path.clone()
         } else {
             env::current_dir().unwrap()
-        }
+        };
+        fix_unc_path(&path)
     }
 
     pub fn get_config_vec(file_configs: std::io::Result<Vec<Self>>, backup: Self) -> ConfigWrapper {
@@ -787,7 +799,7 @@ impl Config {
     /// uses root if set, else env::current_dir()
     #[inline]
     pub fn get_base_dir(&self) -> PathBuf {
-        if let Some(root) = &self.root {
+        let res = if let Some(root) = &self.root {
             if Path::new(root).is_absolute() {
                 PathBuf::from(root)
             } else {
@@ -800,7 +812,8 @@ impl Config {
             }
         } else {
             env::current_dir().unwrap()
-        }
+        };
+        fix_unc_path(&res)
     }
 
     /// returns the relative path from the base_dir
diff --git a/src/config/parse.rs b/src/config/parse.rs
index 6cd75e5..e011273 100644
--- a/src/config/parse.rs
+++ b/src/config/parse.rs
@@ -1,4 +1,5 @@
 use crate::config::types::*;
+use crate::path_utils::fix_unc_path;
 use clap::{value_t, values_t, ArgMatches};
 use coveralls_api::CiService;
 use regex::Regex;
@@ -39,7 +40,7 @@ pub(super) fn get_manifest(args: &ArgMatches) -> PathBuf {
                 .canonicalize()
                 .unwrap();
         }
-        return path;
+        return fix_unc_path(&path);
     }
 
     let mut manifest = env::current_dir().unwrap();
@@ -49,13 +50,13 @@ pub(super) fn get_manifest(args: &ArgMatches) -> PathBuf {
     }
 
     manifest.push("Cargo.toml");
-    manifest.canonicalize().unwrap_or(manifest)
+    fix_unc_path(&manifest.canonicalize().unwrap_or(manifest))
 }
 
 pub(super) fn default_manifest() -> PathBuf {
     let mut manifest = env::current_dir().unwrap();
     manifest.push("Cargo.toml");
-    manifest.canonicalize().unwrap_or(manifest)
+    fix_unc_path(&manifest.canonicalize().unwrap_or(manifest))
 }
 
 pub(super) fn get_target(args: &ArgMatches) -> Option<String> {
@@ -87,7 +88,7 @@ pub(super) fn get_target_dir(args: &ArgMatches) -> Option<PathBuf> {
     } else {
         path
     };
-    Some(path)
+    Some(fix_unc_path(&path))
 }
 
 pub(super) fn get_root(args: &ArgMatches) -> Option<PathBuf> {
diff --git a/src/lib.rs b/src/lib.rs
index 358ab32..ff018fd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -33,6 +33,7 @@ pub fn setup_logging(color: Color, debug: bool, verbose: bool) {
     let base_exceptions = |env: EnvFilter| {
         if debug {
             env.add_directive("cargo_tarpaulin=trace".parse().unwrap())
+                .add_directive("llvm_profparser=trace".parse().unwrap())
         } else if verbose {
             env.add_directive("cargo_tarpaulin=debug".parse().unwrap())
         } else {
@@ -187,7 +188,7 @@ fn collect_tracemap(configs: &[Config]) -> Result<TraceMap, RunError> {
     Ok(tracemap)
 }
 
-fn report_tracemap(configs: &[Config], tracemap: TraceMap) -> Result<(), RunError> {
+pub fn report_tracemap(configs: &[Config], tracemap: TraceMap) -> Result<(), RunError> {
     let mut reported = false;
     for c in configs.iter() {
         if c.no_run || c.name != "report" {
diff --git a/src/report/cobertura.rs b/src/report/cobertura.rs
index c2ffab0..dc8101c 100644
--- a/src/report/cobertura.rs
+++ b/src/report/cobertura.rs
@@ -433,7 +433,7 @@ mod tests {
     #[test]
     fn package_coverage() {
         let mut config = Config::default();
-        config.manifest = PathBuf::from("fake/Cargo.toml");
+        config.set_manifest(PathBuf::from("fake/Cargo.toml"));
         let mut map = TraceMap::new();
 
         map.add_file(&PathBuf::from("fake/examples/foo.rs"));
diff --git a/src/report/coveralls.rs b/src/report/coveralls.rs
index c80a12e..35f130d 100644
--- a/src/report/coveralls.rs
+++ b/src/report/coveralls.rs
@@ -105,7 +105,7 @@ pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError>
             }
         }
 
-        match get_git_info(&config.manifest) {
+        match get_git_info(&config.manifest()) {
             Ok(git_info) => {
                 report.set_detailed_git_info(git_info);
                 info!("Git info collected");
diff --git a/src/statemachine/instrumented.rs b/src/statemachine/instrumented.rs
index f8722a9..ae3e8fc 100644
--- a/src/statemachine/instrumented.rs
+++ b/src/statemachine/instrumented.rs
@@ -98,6 +98,9 @@ impl<'a> StateData for LlvmInstrumentedData<'a> {
                         .collect::<Vec<_>>();
 
                     let profraw_dir = self.config.profraw_dir();
+                    if !profraw_dir.exists() {
+                        let _ = fs::create_dir_all(&profraw_dir);
+                    }
 
                     info!(
                         "For binary: {}",


Test patch:
diff --git a/src/test_loader.rs b/src/test_loader.rs
index 48451d3..db0195c 100644
--- a/src/test_loader.rs
+++ b/src/test_loader.rs
@@ -1,5 +1,5 @@
 use crate::config::{types::TraceEngine, Config};
-use crate::path_utils::is_coverable_file_path;
+use crate::path_utils::{fix_unc_path, is_coverable_file_path};
 use crate::source_analysis::*;
 use crate::traces::*;
 use gimli::read::Error;
@@ -179,7 +179,7 @@ where
                     }
                 }
                 if let Ok(p) = path.canonicalize() {
-                    path = p;
+                    path = fix_unc_path(&p);
                 }
                 let file = file.path_name();
                 let line = ln_row.line().unwrap();
diff --git a/tests/data/simple_project/.gitignore b/tests/data/simple_project/.gitignore
new file mode 100644
index 0000000..a9a1bd3
--- /dev/null
+++ b/tests/data/simple_project/.gitignore
@@ -0,0 +1,1 @@
+reports/
diff --git a/tests/data/torch_test/Cargo.lock b/tests/data/torch_test/Cargo.lock
index 8b0265b..02d579a 100644
--- a/tests/data/torch_test/Cargo.lock
+++ b/tests/data/torch_test/Cargo.lock
@@ -28,9 +28,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bzip2"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
 dependencies = [
  "bzip2-sys",
  "libc",
diff --git a/tests/doc_coverage.rs b/tests/doc_coverage.rs
index abcd1e7..d9c0a87 100644
--- a/tests/doc_coverage.rs
+++ b/tests/doc_coverage.rs
@@ -14,8 +14,9 @@ fn doc_test_env() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doctest_env");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("doc_test_env"));
 
     config.run_types = vec![RunType::Doctests];
@@ -36,8 +37,9 @@ fn doc_test_coverage() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doc_coverage");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     config.run_types = vec![RunType::Doctests];
     config.set_profraw_folder(PathBuf::from("doc_test_coverage_1"));
@@ -66,8 +68,9 @@ fn doc_test_panics() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doctest_should_panic");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     config.run_types = vec![RunType::Doctests];
     config.set_profraw_folder(PathBuf::from("doc_test_panics_1"));
@@ -96,8 +99,9 @@ fn doc_test_panics_workspace() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doctest_workspace_should_panic");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("doc_test_panics_workspace_1"));
 
     config.run_types = vec![RunType::Doctests];
@@ -126,8 +130,9 @@ fn doc_test_compile_fail() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doctest_compile_fail_fail");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     config.run_types = vec![RunType::Doctests];
 
@@ -143,8 +148,9 @@ fn doc_test_no_run() {
     config.test_timeout = Duration::from_secs(60);
     let test_dir = get_test_path("doctest_norun");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     config.run_types = vec![RunType::Doctests];
 
@@ -162,8 +168,9 @@ fn rustdocflags_handling() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("rustflags");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     let res = launch_tarpaulin(&config, &None);
     env::set_current_dir(&restore_dir).unwrap();
diff --git a/tests/failure_thresholds.rs b/tests/failure_thresholds.rs
index 7131aa4..fab6ee8 100644
--- a/tests/failure_thresholds.rs
+++ b/tests/failure_thresholds.rs
@@ -15,8 +15,9 @@ fn coverage_below_threshold() {
     let mut config = Config::default();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.fail_under = Some(100.0);
     config.set_clean(false);
     config.set_profraw_folder(PathBuf::from("coverage_below_threshold"));
@@ -38,8 +39,9 @@ fn coverage_above_threshold() {
     let mut config = Config::default();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.fail_under = Some(30.0);
     config.set_clean(false);
     config.set_profraw_folder(PathBuf::from("coverage_above_threshold"));
@@ -55,16 +57,18 @@ fn report_coverage_fail() {
     let mut config = Config::default();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir.clone();
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir.clone();
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.fail_under = Some(10.0);
     config.set_clean(false);
     config.set_profraw_folder(PathBuf::from("report_coverage_fail"));
 
     let mut report = Config::default();
     report.name = "report".to_string();
-    report.manifest = test_dir;
-    report.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    report.set_manifest(manifest);
     report.fail_under = Some(99.0);
 
     let result = run(&[config, report]);
diff --git a/tests/failures.rs b/tests/failures.rs
index db6fe9f..849b7c6 100644
--- a/tests/failures.rs
+++ b/tests/failures.rs
@@ -15,8 +15,9 @@ fn error_if_build_script_fails() {
     let mut config = Config::default();
     let test_dir = get_test_path("build_script_fail");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_clean(false);
 
     let result = launch_tarpaulin(&config, &None);
@@ -35,8 +36,9 @@ fn error_if_compilation_fails() {
     let mut config = Config::default();
     let test_dir = get_test_path("compile_fail");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_clean(false);
 
     let result = launch_tarpaulin(&config, &None);
@@ -55,8 +57,9 @@ fn error_if_test_fails() {
     let mut config = Config::default();
     let test_dir = get_test_path("failing_test");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_clean(false);
 
     let result = run(&[config]);
@@ -76,8 +79,9 @@ fn issue_610() {
     let test_dir = get_test_path("issue_610");
     config.test_names.insert("foo".to_string());
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_clean(false);
 
     let result = run(&[config.clone()]);
diff --git a/tests/line_coverage.rs b/tests/line_coverage.rs
index 02d7225..7ad4d2b 100644
--- a/tests/line_coverage.rs
+++ b/tests/line_coverage.rs
@@ -17,8 +17,9 @@ fn simple_project_coverage() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir.clone();
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir.clone();
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
     assert_eq!(ret, 0);
@@ -58,8 +59,9 @@ fn debug_info_0() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     let backup_flag = env::var("RUSTFLAGS").ok();
     env::set_var("RUSTFLAGS", "-Cdebuginfo=0");
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
@@ -80,8 +82,9 @@ fn test_threads_1() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("simple_project");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir.clone();
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir.clone();
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.varargs.push("--test-threads".to_string());
     config.varargs.push("1".to_string());
 
diff --git a/tests/mod.rs b/tests/mod.rs
old mode 100644
new mode 100755
index cd64f81..a32ceb0
--- a/tests/mod.rs
+++ b/tests/mod.rs
@@ -1,477 +1,575 @@
-use crate::utils::get_test_path;
-use cargo_tarpaulin::config::{Color, Config, ConfigWrapper, Mode, RunType, TraceEngine};
-use cargo_tarpaulin::event_log::EventLog;
-use cargo_tarpaulin::path_utils::*;
-use cargo_tarpaulin::traces::TraceMap;
-use cargo_tarpaulin::{launch_tarpaulin, setup_logging};
-use clap::App;
-use rusty_fork::rusty_fork_test;
-use std::collections::HashSet;
-use std::env;
-use std::fs;
-use std::path::Path;
-use std::time::Duration;
-
-#[cfg(nightly)]
-mod doc_coverage;
-mod failure_thresholds;
-mod failures;
-mod line_coverage;
-mod test_types;
-mod utils;
-mod workspaces;
-
-pub fn check_percentage_with_cli_args(minimum_coverage: f64, has_lines: bool, args: &[String]) {
-    setup_logging(Color::Never, false, false);
-    let restore_dir = env::current_dir().unwrap();
-    let matches = App::new("tarpaulin")
-        .args_from_usage(
-             "--config [FILE] 'Path to a toml file specifying a list of options this will override any other options set'
-             --ignore-config 'Ignore any project config files'
-             --debug 'Show debug output - this is used for diagnosing issues with tarpaulin'
-             --verbose -v 'Show extra output'
-             --root -r [DIR] 'directory'
-             --include-tests 'include tests in your tests'
-             --post-test-delay [SECONDS] 'Delay after test to collect coverage profiles'
-             --implicit-test-threads 'Don't supply an explicit `--test-threads` argument to tarpaulin. By default tarpaulin will infer the default rustc would pick if not ran via tarpaulin and set it'"
-        ).get_matches_from(args);
-
-    let mut configs = ConfigWrapper::from(&matches).0;
-    let mut res = TraceMap::new();
-    for config in &mut configs {
-        config.set_clean(false);
-        let (t, _) = launch_tarpaulin(config, &None).unwrap();
-        res.merge(&t);
-    }
-    res.dedup();
-    env::set_current_dir(restore_dir).unwrap();
-    if has_lines {
-        assert!(
-            res.coverage_percentage() >= minimum_coverage,
-            "Assertion failed {} >= {}",
-            res.coverage_percentage(),
-            minimum_coverage
-        );
-        assert!(res.total_coverable() > 0);
-    }
-}
-
-pub fn check_percentage_with_config(
-    project_name: &str,
-    minimum_coverage: f64,
-    has_lines: bool,
-    mut config: Config,
-) {
-    setup_logging(Color::Never, false, false);
-    config.test_timeout = Duration::from_secs(60);
-    let restore_dir = env::current_dir().unwrap();
-    let test_dir = get_test_path(project_name);
-    env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
-    config.set_clean(false);
-
-    // Note to contributors. If an integration test fails, uncomment this to be able to see the
-    // tarpaulin logs
-    //cargo_tarpaulin::setup_logging(true, true);
-    let event_log = if config.dump_traces {
-        let mut paths = HashSet::new();
-        paths.insert(config.manifest.clone());
-        Some(EventLog::new(paths))
-    } else {
-        None
-    };
-
-    let (res, ret) = launch_tarpaulin(&config, &event_log).unwrap();
-    assert_eq!(ret, 0);
-
-    env::set_current_dir(restore_dir).unwrap();
-    if has_lines {
-        assert!(res.total_coverable() > 0);
-        assert!(
-            res.coverage_percentage() >= minimum_coverage,
-            "Assertion failed {} >= {}",
-            res.coverage_percentage(),
-            minimum_coverage
-        );
-    } else {
-        assert_eq!(res.total_coverable(), 0);
-    }
-}
-
-pub fn check_percentage(project_name: &str, minimum_coverage: f64, has_lines: bool) {
-    let mut config = Config::default();
-    config.set_ignore_tests(false);
-    config.set_clean(false);
-    check_percentage_with_config(project_name, minimum_coverage, has_lines, config);
-}
-
-rusty_fork_test! {
-
-#[test]
-fn incorrect_manifest_path() {
-    let mut config = Config::default();
-    config.manifest.push("__invalid_dir__");
-    config.set_clean(false);
-    let launch = launch_tarpaulin(&config, &None);
-    assert!(launch.is_err());
-}
-
-#[test]
-fn proc_macro_link() {
-    let mut config = Config::default();
-    config.test_timeout = Duration::from_secs(60);
-    config.set_clean(false);
-    let test_dir = get_test_path("proc_macro");
-    config.manifest = test_dir.join("Cargo.toml");
-    assert!(launch_tarpaulin(&config, &None).is_ok());
-}
-
-#[test]
-fn array_coverage() {
-    check_percentage("arrays", 1.0f64, true);
-}
-
-#[test]
-fn lets_coverage() {
-    check_percentage("lets", 1.0f64, true);
-}
-
-#[test]
-#[cfg_attr(not(target_os="linux"), ignore)] // TODO So there are linker issues I can't adequately diagnose myself in windows
-#[cfg(not(tarpaulin))]
-fn picking_up_shared_objects() {
-    // Need a project which downloads a shared object to target folder and uses build script to set
-    // the linker path.
-    check_percentage("torch_test", 1.0f64, true);
-}
-
-// Just for linux if we have ptrace as default
-#[test]
-fn llvm_sanity_test() {
-    let mut config = Config::default();
-    config.set_engine(TraceEngine::Llvm);
-    config.follow_exec = true;
-    config.set_ignore_tests(false);
-    config.set_clean(false);
-
-    check_percentage_with_config("structs", 1.0f64, true, config.clone());
-    check_percentage_with_config("ifelse", 1.0f64, true, config.clone());
-    check_percentage_with_config("returns", 1.0f64, true, config.clone());
-    check_percentage_with_config("follow_exe", 1.0f64, true, config);
-}
-
-#[test]
-fn struct_expr_coverage() {
-    check_percentage("structs", 1.0f64, true);
-}
-
-#[test]
-fn ifelse_expr_coverage() {
-    check_percentage("ifelse", 1.0f64, true);
-}
-
-#[test]
-fn returns_expr_coverage() {
-    check_percentage("returns", 1.0f64, true);
-}
-
-#[test]
-fn loops_expr_coverage() {
-    check_percentage("loops", 1.0f64, true);
-}
-
-#[test]
-fn loops_assigns_coverage() {
-    check_percentage("assigns", 1.0f64, true);
-}
-
-#[test]
-fn paths_coverage() {
-    check_percentage("paths", 1.0f64, true);
-}
-
-#[test]
-fn futures_coverage() {
-    check_percentage("futures", 1.0f64, true);
-}
-
-#[test]
-fn breaks_expr_coverage() {
-    check_percentage("breaks", 1.0f64, true);
-}
-
-#[test]
-fn continues_expr_coverage() {
-    check_percentage("continues", 1.0f64, true);
-}
-
-#[test]
-fn boxes_coverage() {
-    check_percentage("boxes", 1.0f64, true);
-}
-
-#[test]
-#[ignore]
-fn method_calls_expr_coverage() {
-    check_percentage("method_calls", 1.0f64, true);
-}
-
-#[test]
-fn config_file_coverage() {
-    let test_dir = get_test_path("configs");
-    let mut args = vec![
-        "tarpaulin".to_string(),
-        "--root".to_string(),
-        test_dir.display().to_string(),
-    ];
-    check_percentage_with_cli_args(1.0f64, true, &args);
-    args.push("--ignore-config".to_string());
-    check_percentage_with_cli_args(0.0f64, true, &args);
-}
-
-#[test]
-fn issue_966_follow_exec() {
-    let test_dir = get_test_path("follow_exec_issue966");
-    let args = vec![
-        "tarpaulin".to_string(),
-        "--root".to_string(),
-        test_dir.display().to_string(),
-        "--post-test-delay".to_string(),
-        10.to_string(),
-    ];
-    check_percentage_with_cli_args(1.0f64, true, &args);
-}
-
-#[test]
-fn rustflags_config_coverage() {
-    let test_dir = get_test_path("multiple_rustflags");
-    let mut args = vec![
-        "tarpaulin".to_string(),
-        "--root".to_string(),
-        test_dir.display().to_string(),
-    ];
-    check_percentage_with_cli_args(1.0f64, true, &args);
-    args.push("--ignore-config".to_string());
-    check_percentage_with_cli_args(0.0f64, false, &args);
-}
-
-#[test]
-fn match_expr_coverage() {
-    check_percentage("matches", 1.0f64, true);
-}
-
-#[test]
-#[ignore]
-fn benchmark_coverage() {
-    let test = "benchmark_coverage";
-    check_percentage(test, 0.0f64, true);
-
-    let mut config = Config::default();
-    config.set_clean(false);
-    config.run_types = vec![RunType::Benchmarks];
-    check_percentage_with_config(test, 1.0f64, true, config);
-}
-
-#[test]
-fn cargo_run_coverage() {
-    let mut config = Config::default();
-    config.command = Mode::Build;
-    config.set_clean(false);
-    check_percentage_with_config("run_coverage", 1.0f64, true, config);
-}
-
-#[test]
-fn examples_coverage() {
-    let test = "example_test";
-    check_percentage(test, 0.0f64, true);
-
-    let mut config = Config::default();
-    config.run_types = vec![RunType::Examples];
-    config.set_clean(false);
-    config.set_ignore_tests(false);
-    check_percentage_with_config(test, 1.0f64, true, config.clone());
-
-    config.run_types.clear();
-    config.example_names.insert("say_hello".to_string());
-    check_percentage_with_config(test, 1.0f64, true, config);
-}
-
-#[test]
-fn access_env_var() {
-    // This test is mainly to check that expected environment variables are present
-    // using `CARGO_BIN_EXE_<name>` to test
-    let test = "env_var";
-    check_percentage(test, 1.0f64, true);
-}
-
-#[test]
-fn tarpaulin_attrs() {
-    check_percentage("tarpaulin_attrs", 0.0f64, true);
-}
-
-#[test]
-#[cfg(nightly)]
-fn tarpaulin_tool_attr() {
-    check_percentage("tool_attr", 0.0f64, false);
-}
-
-#[test]
-#[cfg(nightly)]
-fn filter_with_inner_attributes() {
-    check_percentage("filter_inner_modules", 0.0f64, false);
-}
-
-#[test]
-fn cargo_home_filtering() {
-    let new_home =
-        Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/data/HttptestAndReqwest/new_home");
-    let previous = env::var("CARGO_HOME");
-
-    let mut config = Config::default();
-    config.test_timeout = Duration::from_secs(60);
-    config.set_clean(false);
-    let restore_dir = env::current_dir().unwrap();
-    let test_dir = get_test_path("HttptestAndReqwest");
-    env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
-
-    env::set_var("CARGO_HOME", new_home.display().to_string());
-    let run = launch_tarpaulin(&config, &None);
-    let _ = fs::remove_dir_all(&new_home);
-    match previous {
-        Ok(s) => env::set_var("CARGO_HOME", s),
-        Err(_) => {
-            let _ = env::remove_var("CARGO_HOME");
-        }
-    }
-    let (res, _) = run.unwrap();
-
-    env::set_current_dir(restore_dir).unwrap();
-
-    assert_eq!(res.iter().count(), 1);
-}
-
-#[test]
-fn rustflags_handling() {
-    check_percentage("rustflags", 1.0f64, true);
-    env::set_var("RUSTFLAGS", "--cfg=foo");
-    let mut config = Config::default();
-    config.set_clean(false);
-
-    let restore_dir = env::current_dir().unwrap();
-    let test_dir = get_test_path("rustflags");
-    env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
-
-    let res = launch_tarpaulin(&config, &None);
-    env::set_current_dir(&restore_dir).unwrap();
-    env::remove_var("RUSTFLAGS");
-    assert!(res.is_err() || res.unwrap().1 != 0);
-
-    let (_, ret) = launch_tarpaulin(&config, &None).unwrap();
-    env::set_current_dir(&restore_dir).unwrap();
-    assert_eq!(ret, 0);
-}
-
-#[test]
-fn follow_exes_down() {
-    let mut config = Config::default();
-    config.follow_exec = true;
-    config.set_clean(false);
-    check_percentage_with_config("follow_exe", 1.0f64, true, config);
-}
-
-#[test]
-fn handle_module_level_exclude_attrs() {
-    check_percentage("crate_level_ignores", 1.0f64, true);
-}
-
-#[test]
-#[cfg(unix)]
-fn handle_forks() {
-    let mut config = Config::default();
-    config.set_clean(false);
-    config.set_ignore_tests(false);
-    config.post_test_delay = Some(Duration::from_secs(10));
-    // Some false negatives on more recent compilers so lets just aim for >90% and 0 return code
-    check_percentage_with_config("fork-test", 0.85f64, true, config);
-}
-
-#[test]
-fn no_test_args() {
-    let test_dir = get_test_path("no_test_args");
-    let args = vec![
-        "tarpaulin".to_string(),
-        "--root".to_string(),
-        test_dir.display().to_string(),
-        "--implicit-test-threads".to_string(),
-        "--include-tests".to_string(),
-    ];
-    check_percentage_with_cli_args(1.0, true, &args);
-}
-
-#[test]
-fn dot_rs_in_dir_name() {
-    // issue #857
-    let mut config = Config::default();
-    config.set_clean(false);
-    config.set_ignore_tests(false);
-
-    let restore_dir = env::current_dir().unwrap();
-    let test_dir = get_test_path("not_a_file.rs");
-    env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
-
-    let (res, _ret) = launch_tarpaulin(&config, &None).unwrap();
-    env::set_current_dir(&restore_dir).unwrap();
-
-    assert_eq!(res.files().len(), 1);
-
-    for dir in get_source_walker(&config) {
-        assert!(dir.path().is_file());
-    }
-}
-
-#[test]
-#[cfg(unix)]
-#[cfg(not(tarpaulin))]
-fn kill_used_in_test() {
-    let mut config = Config::default();
-    if config.engine() == TraceEngine::Llvm {
-        println!("Tests using signals are not supported");
-        return;
-    }
-
-    config.follow_exec = true;
-    config.set_clean(false);
-    config.set_ignore_tests(false);
-    // Currently 2 false negatives, but if it was only covering the integration test max coverage
-    // is 75% so this is high enough to prove it works
-    check_percentage_with_config("kill_proc", 0.9f64, true, config);
-}
-
-
-#[test]
-fn doc_test_bootstrap() {
-    let mut config = Config::default();
-    config.verbose = true;
-    config.set_clean(false);
-    config.test_timeout = Duration::from_secs(60);
-    let test_dir = get_test_path("doc_coverage");
-    env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
-
-    config.run_types = vec![RunType::Doctests];
-
-    env::set_var("RUSTC_BOOTSTRAP", "1");
-
-    let (_res, ret) = launch_tarpaulin(&config, &None).unwrap();
-    assert_eq!(ret, 0);
-}
-
-}
+use crate::utils::get_test_path;
+use cargo_tarpaulin::config::{
+    Color, Config, ConfigWrapper, Mode, OutputFile, RunType, TraceEngine,
+};
+use cargo_tarpaulin::event_log::EventLog;
+use cargo_tarpaulin::path_utils::*;
+use cargo_tarpaulin::traces::TraceMap;
+use cargo_tarpaulin::{launch_tarpaulin, run, setup_logging};
+use clap::{App, Arg};
+use regex::Regex;
+use rusty_fork::rusty_fork_test;
+use std::collections::HashSet;
+use std::path::{Path, PathBuf};
+use std::time::Duration;
+use std::{env, fs, io};
+
+#[cfg(nightly)]
+mod doc_coverage;
+mod failure_thresholds;
+mod failures;
+mod line_coverage;
+mod test_types;
+mod utils;
+mod workspaces;
+
+pub fn check_percentage_with_cli_args(
+    minimum_coverage: f64,
+    has_lines: bool,
+    args: &[String],
+) -> TraceMap {
+    setup_logging(Color::Never, false, false);
+    let restore_dir = env::current_dir().unwrap();
+    let matches = App::new("tarpaulin")
+        .args_from_usage(
+             "--config [FILE] 'Path to a toml file specifying a list of options this will override any other options set'
+             --ignore-config 'Ignore any project config files'
+             --debug 'Show debug output - this is used for diagnosing issues with tarpaulin'
+             --verbose -v 'Show extra output'
+             --root -r [DIR] 'directory'
+             --include-tests 'include tests in your tests'
+             --post-test-delay [SECONDS] 'Delay after test to collect coverage profiles'
+             --implicit-test-threads 'Don't supply an explicit `--test-threads` argument to tarpaulin. By default tarpaulin will infer the default rustc would pick if not ran via tarpaulin and set it'"
+        ).args(&[
+                Arg::from_usage("--out -o [FMT]   'Output format of coverage report'")
+                    .possible_values(&OutputFile::variants())
+                    .case_insensitive(true)
+                    .multiple(true),
+                Arg::from_usage("--engine [ENGINE] 'Coverage tracing backend to use'")
+                    .possible_values(&TraceEngine::variants())
+                    .case_insensitive(true)
+                    .multiple(false),
+                Arg::from_usage("--output-dir [PATH] 'Specify a custom directory to write report files'"),
+                Arg::from_usage("--color [WHEN] 'Coloring: auto, always, never'")
+                    .case_insensitive(true)
+                    .possible_values(&Color::variants()),
+        ])
+        .get_matches_from(args);
+
+    let mut configs = ConfigWrapper::from(&matches).0;
+    let mut res = TraceMap::new();
+    for config in &mut configs {
+        config.set_clean(false);
+        let (t, _) = launch_tarpaulin(config, &None).unwrap();
+        res.merge(&t);
+    }
+    res.dedup();
+    env::set_current_dir(restore_dir).unwrap();
+    if has_lines {
+        assert!(
+            res.coverage_percentage() >= minimum_coverage,
+            "Assertion failed {} >= {}",
+            res.coverage_percentage(),
+            minimum_coverage
+        );
+        assert!(res.total_coverable() > 0);
+    }
+    res
+}
+
+pub fn run_config(project_name: &str, mut config: Config) {
+    setup_logging(Color::Never, false, false);
+    config.test_timeout = Duration::from_secs(60);
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path(project_name);
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+    env::set_current_dir(config.root()).unwrap();
+    config.set_clean(false);
+
+    run(&[config]).unwrap();
+
+    env::set_current_dir(restore_dir).unwrap();
+}
+
+pub fn check_percentage_with_config(
+    project_name: &str,
+    minimum_coverage: f64,
+    has_lines: bool,
+    mut config: Config,
+) -> TraceMap {
+    setup_logging(Color::Never, false, false);
+    config.test_timeout = Duration::from_secs(60);
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path(project_name);
+    env::set_current_dir(&test_dir).unwrap();
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+    config.set_clean(false);
+
+    // Note to contributors. If an integration test fails, uncomment this to be able to see the
+    // tarpaulin logs
+    //cargo_tarpaulin::setup_logging(true, true);
+    let event_log = if config.dump_traces {
+        let mut paths = HashSet::new();
+        paths.insert(config.manifest().clone());
+        Some(EventLog::new(paths))
+    } else {
+        None
+    };
+
+    let (res, ret) = launch_tarpaulin(&config, &event_log).unwrap();
+    assert_eq!(ret, 0);
+
+    env::set_current_dir(restore_dir).unwrap();
+    if has_lines {
+        assert!(res.total_coverable() > 0);
+        assert!(
+            res.coverage_percentage() >= minimum_coverage,
+            "Assertion failed {} >= {}",
+            res.coverage_percentage(),
+            minimum_coverage
+        );
+    } else {
+        assert_eq!(res.total_coverable(), 0);
+    }
+    res
+}
+
+pub fn check_percentage(project_name: &str, minimum_coverage: f64, has_lines: bool) -> TraceMap {
+    let mut config = Config::default();
+    config.set_ignore_tests(false);
+    config.set_clean(false);
+    check_percentage_with_config(project_name, minimum_coverage, has_lines, config)
+}
+
+rusty_fork_test! {
+
+#[test]
+fn incorrect_manifest_path() {
+    let mut config = Config::default();
+    let mut invalid = config.manifest();
+    invalid.push("__invalid_dir__");
+    config.set_manifest(invalid);
+    config.set_clean(false);
+    let launch = launch_tarpaulin(&config, &None);
+    assert!(launch.is_err());
+}
+
+#[test]
+fn proc_macro_link() {
+    let mut config = Config::default();
+    config.test_timeout = Duration::from_secs(60);
+    config.set_clean(false);
+    let test_dir = get_test_path("proc_macro");
+    config.set_manifest(test_dir.join("Cargo.toml"));
+    assert!(launch_tarpaulin(&config, &None).is_ok());
+}
+
+#[test]
+fn array_coverage() {
+    check_percentage("arrays", 1.0f64, true);
+}
+
+#[test]
+fn lets_coverage() {
+    check_percentage("lets", 1.0f64, true);
+}
+
+#[test]
+#[cfg_attr(not(target_os="linux"), ignore)] // TODO So there are linker issues I can't adequately diagnose myself in windows
+#[cfg(not(tarpaulin))]
+fn picking_up_shared_objects() {
+    // Need a project which downloads a shared object to target folder and uses build script to set
+    // the linker path.
+    check_percentage("torch_test", 1.0f64, true);
+}
+
+// Just for linux if we have ptrace as default
+#[test]
+fn llvm_sanity_test() {
+    let mut config = Config::default();
+    config.set_engine(TraceEngine::Llvm);
+    config.follow_exec = true;
+    config.set_ignore_tests(false);
+    config.set_clean(false);
+
+    check_percentage_with_config("structs", 1.0f64, true, config.clone());
+    check_percentage_with_config("ifelse", 1.0f64, true, config.clone());
+    check_percentage_with_config("returns", 1.0f64, true, config.clone());
+    check_percentage_with_config("follow_exe", 1.0f64, true, config);
+}
+
+#[test]
+fn struct_expr_coverage() {
+    check_percentage("structs", 1.0f64, true);
+}
+
+#[test]
+fn ifelse_expr_coverage() {
+    check_percentage("ifelse", 1.0f64, true);
+}
+
+#[test]
+fn returns_expr_coverage() {
+    check_percentage("returns", 1.0f64, true);
+}
+
+#[test]
+fn loops_expr_coverage() {
+    check_percentage("loops", 1.0f64, true);
+}
+
+#[test]
+fn loops_assigns_coverage() {
+    check_percentage("assigns", 1.0f64, true);
+}
+
+#[test]
+fn paths_coverage() {
+    check_percentage("paths", 1.0f64, true);
+}
+
+#[test]
+fn futures_coverage() {
+    check_percentage("futures", 1.0f64, true);
+}
+
+#[test]
+fn breaks_expr_coverage() {
+    check_percentage("breaks", 1.0f64, true);
+}
+
+#[test]
+fn continues_expr_coverage() {
+    check_percentage("continues", 1.0f64, true);
+}
+
+#[test]
+fn boxes_coverage() {
+    check_percentage("boxes", 1.0f64, true);
+}
+
+#[test]
+#[ignore]
+fn method_calls_expr_coverage() {
+    check_percentage("method_calls", 1.0f64, true);
+}
+
+#[test]
+fn config_file_coverage() {
+    let test_dir = get_test_path("configs");
+    let mut args = vec![
+        "tarpaulin".to_string(),
+        "--root".to_string(),
+        test_dir.display().to_string(),
+    ];
+    check_percentage_with_cli_args(1.0f64, true, &args);
+    args.push("--ignore-config".to_string());
+    check_percentage_with_cli_args(0.0f64, true, &args);
+}
+
+#[test]
+fn issue_966_follow_exec() {
+    let test_dir = get_test_path("follow_exec_issue966");
+    let args = vec![
+        "tarpaulin".to_string(),
+        "--root".to_string(),
+        test_dir.display().to_string(),
+        "--post-test-delay".to_string(),
+        10.to_string(),
+    ];
+    check_percentage_with_cli_args(1.0f64, true, &args);
+}
+
+#[test]
+fn rustflags_config_coverage() {
+    let test_dir = get_test_path("multiple_rustflags");
+    let mut args = vec![
+        "tarpaulin".to_string(),
+        "--root".to_string(),
+        test_dir.display().to_string(),
+    ];
+    check_percentage_with_cli_args(1.0f64, true, &args);
+    args.push("--ignore-config".to_string());
+    check_percentage_with_cli_args(0.0f64, false, &args);
+}
+
+#[test]
+fn match_expr_coverage() {
+    check_percentage("matches", 1.0f64, true);
+}
+
+#[test]
+#[ignore]
+fn benchmark_coverage() {
+    let test = "benchmark_coverage";
+    check_percentage(test, 0.0f64, true);
+
+    let mut config = Config::default();
+    config.set_clean(false);
+    config.run_types = vec![RunType::Benchmarks];
+    check_percentage_with_config(test, 1.0f64, true, config);
+}
+
+#[test]
+fn cargo_run_coverage() {
+    let mut config = Config::default();
+    config.command = Mode::Build;
+    config.set_clean(false);
+    check_percentage_with_config("run_coverage", 1.0f64, true, config);
+}
+
+#[test]
+fn examples_coverage() {
+    let test = "example_test";
+    check_percentage(test, 0.0f64, true);
+
+    let mut config = Config::default();
+    config.run_types = vec![RunType::Examples];
+    config.set_clean(false);
+    config.set_ignore_tests(false);
+    check_percentage_with_config(test, 1.0f64, true, config.clone());
+
+    config.run_types.clear();
+    config.example_names.insert("say_hello".to_string());
+    check_percentage_with_config(test, 1.0f64, true, config);
+}
+
+#[test]
+fn access_env_var() {
+    // This test is mainly to check that expected environment variables are present
+    // using `CARGO_BIN_EXE_<name>` to test
+    let test = "env_var";
+    check_percentage(test, 1.0f64, true);
+}
+
+#[test]
+fn tarpaulin_attrs() {
+    check_percentage("tarpaulin_attrs", 0.0f64, true);
+}
+
+#[test]
+#[cfg(nightly)]
+fn tarpaulin_tool_attr() {
+    check_percentage("tool_attr", 0.0f64, false);
+}
+
+#[test]
+#[cfg(nightly)]
+fn filter_with_inner_attributes() {
+    check_percentage("filter_inner_modules", 0.0f64, false);
+}
+
+#[test]
+fn cargo_home_filtering() {
+    let new_home =
+        Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/data/HttptestAndReqwest/new_home");
+    let previous = env::var("CARGO_HOME");
+
+    let mut config = Config::default();
+    config.test_timeout = Duration::from_secs(60);
+    config.set_clean(false);
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path("HttptestAndReqwest");
+    env::set_current_dir(&test_dir).unwrap();
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+
+    env::set_var("CARGO_HOME", new_home.display().to_string());
+    let run = launch_tarpaulin(&config, &None);
+    let _ = fs::remove_dir_all(&new_home);
+    match previous {
+        Ok(s) => env::set_var("CARGO_HOME", s),
+        Err(_) => {
+            let _ = env::remove_var("CARGO_HOME");
+        }
+    }
+    let (res, _) = run.unwrap();
+
+    env::set_current_dir(restore_dir).unwrap();
+
+    assert_eq!(res.iter().count(), 1);
+}
+
+#[test]
+fn rustflags_handling() {
+    check_percentage("rustflags", 1.0f64, true);
+    env::set_var("RUSTFLAGS", "--cfg=foo");
+    let mut config = Config::default();
+    config.set_clean(false);
+
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path("rustflags");
+    env::set_current_dir(&test_dir).unwrap();
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+
+    let res = launch_tarpaulin(&config, &None);
+    env::set_current_dir(&restore_dir).unwrap();
+    env::remove_var("RUSTFLAGS");
+    assert!(res.is_err() || res.unwrap().1 != 0);
+
+    let (_, ret) = launch_tarpaulin(&config, &None).unwrap();
+    env::set_current_dir(&restore_dir).unwrap();
+    assert_eq!(ret, 0);
+}
+
+#[test]
+fn follow_exes_down() {
+    let mut config = Config::default();
+    config.follow_exec = true;
+    config.set_clean(false);
+    check_percentage_with_config("follow_exe", 1.0f64, true, config);
+}
+
+#[test]
+fn handle_module_level_exclude_attrs() {
+    check_percentage("crate_level_ignores", 1.0f64, true);
+}
+
+#[test]
+#[cfg(unix)]
+fn handle_forks() {
+    let mut config = Config::default();
+    config.set_clean(false);
+    config.set_ignore_tests(false);
+    config.post_test_delay = Some(Duration::from_secs(10));
+    // Some false negatives on more recent compilers so lets just aim for >90% and 0 return code
+    check_percentage_with_config("fork-test", 0.85f64, true, config);
+}
+
+#[test]
+fn no_test_args() {
+    let test_dir = get_test_path("no_test_args");
+    let args = vec![
+        "tarpaulin".to_string(),
+        "--root".to_string(),
+        test_dir.display().to_string(),
+        "--implicit-test-threads".to_string(),
+        "--include-tests".to_string(),
+    ];
+    check_percentage_with_cli_args(1.0, true, &args);
+}
+
+#[test]
+fn dot_rs_in_dir_name() {
+    // issue #857
+    let mut config = Config::default();
+    config.set_clean(false);
+    config.set_ignore_tests(false);
+
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path("not_a_file.rs");
+    env::set_current_dir(&test_dir).unwrap();
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+
+    let (res, _ret) = launch_tarpaulin(&config, &None).unwrap();
+    env::set_current_dir(&restore_dir).unwrap();
+
+    assert_eq!(res.files().len(), 1);
+
+    for dir in get_source_walker(&config) {
+        assert!(dir.path().is_file());
+    }
+}
+
+#[test]
+#[cfg(unix)]
+#[cfg(not(tarpaulin))]
+fn kill_used_in_test() {
+    let mut config = Config::default();
+    if config.engine() == TraceEngine::Llvm {
+        println!("Tests using signals are not supported");
+        return;
+    }
+
+    config.follow_exec = true;
+    config.set_clean(false);
+    config.set_ignore_tests(false);
+    // Currently 2 false negatives, but if it was only covering the integration test max coverage
+    // is 75% so this is high enough to prove it works
+    check_percentage_with_config("kill_proc", 0.9f64, true, config);
+}
+
+
+#[test]
+fn doc_test_bootstrap() {
+    let mut config = Config::default();
+    config.verbose = true;
+    config.set_clean(false);
+    config.test_timeout = Duration::from_secs(60);
+    let test_dir = get_test_path("doc_coverage");
+    env::set_current_dir(&test_dir).unwrap();
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+
+    config.run_types = vec![RunType::Doctests];
+
+    env::set_var("RUSTC_BOOTSTRAP", "1");
+
+    let (_res, ret) = launch_tarpaulin(&config, &None).unwrap();
+    assert_eq!(ret, 0);
+}
+
+#[test]
+#[cfg(windows)]
+fn sanitised_paths() {
+    setup_logging(Color::Never, true, true);
+    let test_dir = get_test_path("assigns");
+    let report_dir = test_dir.join("reports");
+    let mut config = Config::default();
+    config.set_engine(TraceEngine::Llvm);
+    config.set_ignore_tests(false);
+    config.set_clean(false);
+    config.generate.push(OutputFile::Lcov);
+    config.generate.push(OutputFile::Html);
+    config.generate.push(OutputFile::Xml);
+    config.generate.push(OutputFile::Json);
+    let _ = fs::remove_dir_all(&report_dir);
+    let _ = fs::create_dir(&report_dir);
+    config.output_directory = Some(report_dir.clone());
+
+    config.test_timeout = Duration::from_secs(60);
+    let restore_dir = env::current_dir().unwrap();
+    let test_dir = get_test_path("assigns");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
+    env::set_current_dir(format!(r#"\\?\{}"#, config.root().display())).unwrap();
+    config.set_manifest(PathBuf::from(format!(r#"\\?\{}"#, config.manifest().display())));
+    config.set_clean(false);
+
+    println!("{:#?}", config);
+    run(&[config]).unwrap();
+
+    env::set_current_dir(restore_dir).unwrap();
+
+    println!("Look at reports");
+    let mut count = 0;
+    let bad_path_regex = Regex::new(r#"\\\\\?\\\w:\\"#).unwrap();
+    for entry in fs::read_dir(&report_dir).unwrap() {
+        let entry = entry.unwrap().path();
+        if !entry.is_dir() {
+            count += 1;
+            println!("Checking: {}", entry.display());
+            let f = fs::File::open(entry).unwrap();
+            if let Ok(s) = io::read_to_string(f) {
+                assert!(!s.is_empty());
+                assert!(bad_path_regex.find(&s).is_none());
+            } else {
+                println!("Not unicode");
+            }
+        }
+    }
+    assert_eq!(count, 4);
+}
+
+}
diff --git a/tests/test_types.rs b/tests/test_types.rs
index 640c573..440b0f1 100644
--- a/tests/test_types.rs
+++ b/tests/test_types.rs
@@ -23,8 +23,9 @@ fn mix_test_types() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("all_test_types");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
     assert_eq!(ret, 0);
@@ -50,8 +51,9 @@ fn only_test_coverage() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("all_test_types");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("only_test_coverage"));
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
@@ -78,8 +80,9 @@ fn only_example_coverage() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("all_test_types");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("only_example_coverage"));
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
@@ -107,8 +110,9 @@ fn only_bench_coverage() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("all_test_types");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("only_bench_coverage"));
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
@@ -136,8 +140,9 @@ fn only_doctest_coverage() {
     let restore_dir = env::current_dir().unwrap();
     let test_dir = get_test_path("all_test_types");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_profraw_folder(PathBuf::from("only_doctest_coverage"));
 
     let (res, ret) = launch_tarpaulin(&config, &None).unwrap();
diff --git a/tests/workspaces.rs b/tests/workspaces.rs
index 43c8b22..150a44c 100644
--- a/tests/workspaces.rs
+++ b/tests/workspaces.rs
@@ -12,8 +12,9 @@ fn package_exclude() {
     let mut config = Config::default();
     let test_dir = get_test_path("workspace");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.set_clean(false);
     config.set_ignore_tests(false);
 
@@ -50,8 +51,9 @@ fn specify_package() {
 
     let test_dir = get_test_path("workspace");
     env::set_current_dir(&test_dir).unwrap();
-    config.manifest = test_dir;
-    config.manifest.push("Cargo.toml");
+    let mut manifest = test_dir;
+    manifest.push("Cargo.toml");
+    config.set_manifest(manifest);
     config.packages = vec!["foo".to_string()];
     let result = launch_tarpaulin(&config, &None);
     let result = result.expect("Test failed").0;
@@ -86,8 +88,8 @@ fn config_relative_pathing() {
     let configs = Config::load_config_file(&test_dir).unwrap();
 
     assert_eq!(configs.len(), 2);
-    assert_eq!(configs[0].manifest, base_path.join("lib/Cargo.toml"));
-    assert_eq!(configs[1].manifest, base_path.join("bin/Cargo.toml"));
+    assert_eq!(configs[0].manifest(), base_path.join("lib/Cargo.toml"));
+    assert_eq!(configs[1].manifest(), base_path.join("bin/Cargo.toml"));
     assert_eq!(configs[1].target_dir(), base_path.join("targ"));
 }