# lcov

[![maintenance status: passively-maintained](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen.svg)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section)
[![license](https://img.shields.io/crates/l/lcov.svg)](#license)
[![crates.io](https://img.shields.io/crates/v/lcov.svg)](https://crates.io/crates/lcov)
[![docs.rs](https://docs.rs/lcov/badge.svg)](https://docs.rs/lcov/)
[![rust 1.56.1+ badge](https://img.shields.io/badge/rust-1.56.1+-93450a.svg)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field)
[![Rust CI](https://github.com/gifnksm/lcov/actions/workflows/rust-ci.yml/badge.svg)](https://github.com/gifnksm/lcov/actions/workflows/rust-ci.yml)
[![codecov](https://codecov.io/gh/gifnksm/lcov/branch/master/graph/badge.svg?token=uXsi5eu0RD)](https://codecov.io/gh/gifnksm/lcov)

LCOV tracefile parser/merger/filter in pure Rust.

[LCOV] is a graphical front-end for coverage testing tool [gcov].
It collects gcov data for multiple source files and stores them into the file called as "tracefile".

The purpose of this crate is to operate the LCOV tracefile faster than [the original LCOV Perl
implementation][LCOV GitHub].

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
lcov = "0.8.1"
```

## Performance

See [the README of `lcov-util`][readme-lcov-util].

## Data structure

In this crate, the data structure corresponding to each line of the LCOV tracefile is called
"LCOV record" and is represented as [`Record`].
Each line of the LCOV tracefile is composed of a string representing a kind of the record,
a colon, a comma-separated field list:

```lcov
<KIND>:<field#0>,<field#1>,...<field#N>
```

LCOV record kind is represented as a variant of [`Record`] or [`RecordKind`].
Each fields of an LCOV record are represented as fields of a struct-like variant of [`Record`].

For details of the LCOV tracefile syntax, see [the manpage of geninfo][geninfo(1)].

## Examples

Parsing an LCOV tracefile:

```rust
use lcov::{Record, RecordKind, Reader};

// `Reader` is an iterator that iterates over `Result<lcov::Record, E>` read from the input buffer.
let mut reader = Reader::open_file("tests/fixtures/report.info")?;

// Collect the read records into a vector.
let records = reader.collect::<Result<Vec<_>, _>>()?;
assert_eq!(records[0], Record::TestName { name: "".into() });
assert_eq!(records[1].kind(), RecordKind::SourceFile);

// Outputs the read records in LCOV tracefile format.
for record in records {
    println!("{}", record);
}
```

Creating an LCOV report from `String`:

```rust
use lcov::{Reader, Record};

let input = "\
TN:test_name
SF:/path/to/source/file.rs
DA:1,2
DA:3,0
DA:5,6
LF:3
LH:2
end_of_record
";

// `&[u8]` implements `BufRead`, so you can pass it as an argument to `Reader::new`.
let mut reader = Reader::new(input.as_bytes());

let records = reader.collect::<Result<Vec<_>, _>>()?;
assert_eq!(records[0], Record::TestName { name: "test_name".into() });
assert_eq!(records[1], Record::SourceFile { path: "/path/to/source/file.rs".into() });

// Creates an `String` in tracefile format. In this example, it is the same as `input`.
let output = records.into_iter().map(|rec| format!("{}\n", rec)).collect::<String>();
assert_eq!(input, output);
```

Merging tracefiles:

```rust
use lcov::{Record, RecordKind, Report};

// Creates an empty `Report`.
let mut report = Report::new();

// Merges a first file.
report.merge(Report::from_file("tests/fixtures/report.init.info")?)?;

// Merges a second file.
report.merge(Report::from_file("tests/fixtures/report.run.info")?)?;

// Outputs the merge result in LCOV tracefile format.
for record in report.into_records() {
    println!("{}", record);
}
```

[LCOV]: http://ltp.sourceforge.net/coverage/lcov.php
[gcov]: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
[LCOV GitHub]: https://github.com/linux-test-project/lcov
[geninfo(1)]: http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
[readme-lcov-util]: https://github.com/gifnksm/lcov/README.md
[`Record`]: enum.Record.html
[`RecordKind`]: enum.RecordKind.html

## Minimum supported Rust version (MSRV)

The minimum supported Rust version is **Rust 1.56.1**.
At least the last 3 versions of stable Rust are supported at any given time.

While a crate is pre-release status (0.x.x) it may have its MSRV bumped in a patch release.
Once a crate has reached 1.x, any MSRV bump will be accompanied with a new minor version.

## License

This project is licensed under either of

* Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
* MIT license ([LICENSE-MIT](../LICENSE-MIT) or <http://opensource.org/licenses/MIT>)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in lcov by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
