Skip to content

Commit

Permalink
Fix code coverage to include coverage from doctests
Browse files Browse the repository at this point in the history
This replaces tarpaulin with llvm-cov which seems to be much
faster, works across platforms, and should be more reliable moving
forward since it uses rustc native coverage information.

Use of nightly compiler is required due to unstable features
<rust-lang/rust#84605> and
<rust-lang/rust#56925>.
  • Loading branch information
csnover committed Aug 13, 2022
1 parent a020745 commit 4eebbd9
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 38 deletions.
28 changes: 22 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,27 +88,43 @@ jobs:
coverage:
name: Code coverage
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: 1
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
toolchain: nightly
override: true
- name: Run tarpaulin
uses: actions-rs/[email protected]
components: llvm-tools-preview
- name: Install llvm-cov
uses: taiki-e/install-action@v1
with:
args: >
--workspace --manifest-path binrw/Cargo.toml
--exclude-files binrw/tests
tool: cargo-llvm-cov
- name: Generate coverage data
run: >
cargo llvm-cov --doctests
--ignore-filename-regex 'binrw/tests'
--no-report
&&
cargo llvm-cov --all-features
--ignore-filename-regex 'binrw/tests'
--no-report
- name: Show coverage results
run: cargo llvm-cov --doctests --no-run
# https://github.com/actions/runner/issues/520
- name: Determine whether codecov.io secret is available
id: has_codecov
run: echo '::set-output name=result::${{ secrets.CODECOV_TOKEN }}'
- name: Generate coverage file
run: cargo llvm-cov --doctests --no-run --lcov --output-path lcov.info
if: steps.has_codecov.outputs.result != 0
- name: Upload to codecov.io
uses: codecov/codecov-action@v1
with:
files: lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
if: steps.has_codecov.outputs.result != 0
4 changes: 2 additions & 2 deletions binrw/src/error/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ impl fmt::Display for Backtrace {

self.fmt_no_bars(f)?;

#[cfg(not(nightly))]
#[cfg(any(not(nightly), coverage))]
writeln!(
f,
"\n ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸\n"
)?;

#[cfg(nightly)]
#[cfg(all(nightly, not(coverage)))]
writeln!(
f,
" ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸\n"
Expand Down
1 change: 1 addition & 0 deletions binrw/tests/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// stabilised and https://github.com/dtolnay/trybuild/issues/6 is fixed, running
// these tests all the time makes sense.
#[rustversion::nightly]
#[cfg(not(coverage))]
#[test]
fn ui() {
let t = trybuild::TestCases::new();
Expand Down
8 changes: 4 additions & 4 deletions binrw_derive/src/binread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use crate::{
use quote::quote;
use syn::DeriveInput;

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_struct_attrs(attrs: &mut Vec<syn::Attribute>) {
attrs.retain(|attr| !is_binwrite_attr(attr) && !is_binread_attr(attr));
}

// TODO: make this work for `#[binrw::binwrite]` somehow?
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn has_attr(input: &DeriveInput, attr_name: &str) -> bool {
input.attrs.iter().any(|attr| {
attr.path
Expand All @@ -21,7 +21,7 @@ fn has_attr(input: &DeriveInput, attr_name: &str) -> bool {
})
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub(crate) fn derive_from_attribute(mut derive_input: DeriveInput) -> proc_macro2::TokenStream {
let (binread_input, generated_impl) = derive_from_input(&derive_input, false);
let binread_input = binread_input.ok();
Expand Down Expand Up @@ -70,7 +70,7 @@ pub(crate) fn derive_from_input(
(binread_input, generated_impl)
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_field_attrs(
binread_input: &Option<read::Input>,
variant_index: usize,
Expand Down
6 changes: 3 additions & 3 deletions binrw_derive/src/binrw_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ use crate::parser::{
read, read::is_binread_attr, write, write::is_binwrite_attr, ParseResult, TempableField,
};

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_struct_attrs(attrs: &mut Vec<syn::Attribute>) {
attrs.retain(|attr| !is_binwrite_attr(attr) && !is_binread_attr(attr));
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub(crate) fn derive_from_attribute(mut derive_input: DeriveInput) -> proc_macro2::TokenStream {
let mut binread_input = read::Input::from_input(&derive_input, false);
let mut binwrite_input = write::Input::from_input(&derive_input, false);
Expand Down Expand Up @@ -125,7 +125,7 @@ fn set_fields_temporary<S: TempableField>(fields: &mut [S], temporary_names: &Ha
}
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_field_attrs(
binread_input: &Option<read::Input>,
binwrite_input: &Option<write::Input>,
Expand Down
8 changes: 4 additions & 4 deletions binrw_derive/src/binwrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use crate::{
use quote::quote;
use syn::DeriveInput;

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_struct_attrs(attrs: &mut Vec<syn::Attribute>) {
attrs.retain(|attr| !is_binwrite_attr(attr) && !is_binread_attr(attr));
}

// TODO: make this work for `#[binrw::binread]` somehow?
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn has_attr(input: &DeriveInput, attr_name: &str) -> bool {
input.attrs.iter().any(|attr| {
attr.path
Expand All @@ -21,7 +21,7 @@ fn has_attr(input: &DeriveInput, attr_name: &str) -> bool {
})
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub(crate) fn derive_from_attribute(mut derive_input: DeriveInput) -> proc_macro2::TokenStream {
let (binwrite_input, generated_impl) = derive_from_input(&derive_input, false);
let binwrite_input = binwrite_input.ok();
Expand Down Expand Up @@ -71,7 +71,7 @@ pub(crate) fn derive_from_input(
(binwrite_input, generated_impl)
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
fn clean_field_attrs(
binwrite_input: &Option<write::Input>,
variant_index: usize,
Expand Down
6 changes: 3 additions & 3 deletions binrw_derive/src/codegen/read_options/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use quote::{quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::Ident;

#[cfg(nightly)]
#[cfg(all(nightly, not(coverage)))]
use crate::backtrace::BacktraceFrame;

pub(super) fn generate_unit_struct(
Expand Down Expand Up @@ -441,13 +441,13 @@ impl<'field> FieldGenerator<'field> {
}

fn map_err_context(&self, name: Option<&Ident>, variant_name: Option<&str>) -> TokenStream {
#[cfg(nightly)]
#[cfg(all(nightly, not(coverage)))]
let code = {
let code = BacktraceFrame::from_field(self.field).to_string();
quote!(Some(#code))
};

#[cfg(not(nightly))]
#[cfg(any(not(nightly), coverage))]
let code = quote!(None);

match self.field.err_context.as_ref() {
Expand Down
29 changes: 15 additions & 14 deletions binrw_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
clippy::large_enum_variant,
clippy::redundant_closure_for_method_calls
)]
#![cfg_attr(nightly, feature(proc_macro_span))]
#![cfg_attr(all(nightly, not(coverage)), feature(proc_macro_span))]
#![cfg_attr(all(nightly, coverage), feature(no_coverage))]

#[cfg(nightly)]
#[cfg(all(nightly, not(coverage)))]
mod backtrace;
mod binread;
mod binrw_attr;
Expand All @@ -24,35 +25,35 @@ use proc_macro::TokenStream;
use syn::{parse_macro_input, spanned::Spanned, DeriveInput};

#[proc_macro_derive(BinRead, attributes(binread, br, brw))]
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub fn derive_binread_trait(input: TokenStream) -> TokenStream {
binread::derive_from_input(&parse_macro_input!(input as DeriveInput), true)
.1
.into()
}

#[proc_macro_attribute]
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub fn binread(_: TokenStream, input: TokenStream) -> TokenStream {
binread::derive_from_attribute(parse_macro_input!(input as DeriveInput)).into()
}

#[proc_macro_derive(BinWrite, attributes(binwrite, bw, brw))]
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub fn derive_binwrite_trait(input: TokenStream) -> TokenStream {
binwrite::derive_from_input(&parse_macro_input!(input as DeriveInput), true)
.1
.into()
}

#[proc_macro_attribute]
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub fn binwrite(_: TokenStream, input: TokenStream) -> TokenStream {
binwrite::derive_from_attribute(parse_macro_input!(input as DeriveInput)).into()
}

#[proc_macro_attribute]
#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
pub fn binrw(_: TokenStream, input: TokenStream) -> TokenStream {
binrw_attr::derive_from_attribute(parse_macro_input!(input as DeriveInput)).into()
}
Expand Down Expand Up @@ -126,17 +127,17 @@ fn binrw_named_args(input: DeriveInput) -> proc_macro2::TokenStream {
.generate(false)
}

#[cfg(not(tarpaulin_include))]
#[cfg_attr(coverage_nightly, no_coverage)]
#[proc_macro_derive(BinrwNamedArgs, attributes(named_args))]
pub fn derive_binrw_named_args(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
binrw_named_args(input).into()
}

#[cfg(test)]
#[cfg(tarpaulin)]
#[cfg(coverage)]
#[test]
fn derive_code_coverage_for_tarpaulin() {
fn derive_code_coverage_for_tool() {
use runtime_macros_derive::emulate_derive_expansion_fallible;
use std::{env, fs};

Expand Down Expand Up @@ -166,9 +167,9 @@ fn derive_code_coverage_for_tarpaulin() {
}

#[cfg(test)]
#[cfg(tarpaulin)]
#[cfg(coverage)]
#[test]
fn derive_binwrite_code_coverage_for_tarpaulin() {
fn derive_binwrite_code_coverage_for_tool() {
use runtime_macros_derive::emulate_derive_expansion_fallible;
use std::{env, fs};

Expand Down Expand Up @@ -196,9 +197,9 @@ fn derive_binwrite_code_coverage_for_tarpaulin() {
}

#[cfg(test)]
#[cfg(tarpaulin)]
#[cfg(coverage)]
#[test]
fn derive_named_args_code_coverage_for_tarpaulin() {
fn derive_named_args_code_coverage_for_tool() {
use runtime_macros_derive::emulate_derive_expansion_fallible;
use std::fs;
let file = fs::File::open("../binrw/tests/builder.rs").unwrap();
Expand Down
2 changes: 1 addition & 1 deletion binrw_derive/src/parser/types/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl Inner {
&self.1
}

#[cfg(nightly)] // Not actually nightly, but only used by nightly mod syntax_highlighting
#[cfg(all(nightly, not(coverage)))] // Not actually nightly, but only used by nightly mod syntax_highlighting
pub(crate) fn into_match_value(self) -> TokenStream {
self.1
}
Expand Down
2 changes: 1 addition & 1 deletion binrw_derive/src/parser/types/spanned_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl<T> SpannedValue<T> {
Self { value, span }
}

#[cfg(nightly)] // Not actually nightly, but only used by nightly mod syntax_highlighting
#[cfg(all(nightly, not(coverage)))] // Not actually nightly, but only used by nightly mod syntax_highlighting
pub(crate) fn into_value(self) -> T {
self.value
}
Expand Down

0 comments on commit 4eebbd9

Please sign in to comment.