atlas_coverage_core/
lib.rs

1#[macro_use]
2extern crate serde_derive;
3extern crate serde;
4extern crate serde_json;
5extern crate vlq;
6extern crate xml;
7extern crate globset;
8extern crate lcov_parser;
9extern crate memmap;
10
11pub mod debug;
12pub mod settings;
13
14mod lcov;
15mod lines;
16mod load;
17mod model;
18mod range;
19mod source_map;
20mod vlq_decode;
21mod util;
22
23use std::path::Path;
24
25use lines::calculate_executable_line_mappings;
26use lines::calculate_line_coverage;
27use lines::FileCoverage;
28use lines::ManyCoverage;
29use model::{PuppeteerData, SourceMap};
30use settings::Settings;
31use source_map::*;
32use std::collections::HashMap;
33use std::collections::HashSet;
34use std::env::args;
35use std::io::Write;
36use std::io;
37
38pub fn process_source_map(settings: &Settings, data: PuppeteerData) -> Option<Vec<FileCoverage>> {
39    if let Some(source_mapping_url) = data.get_source_mapping_url() {
40        let source_path = data.url.replace(&settings.public_url_base, &settings.dist_path);
41
42        let source_mapping_url = source_mapping_url.replace("//# sourceMappingURL=", "");
43        let source_mapping_path = Path::new(&source_path)
44            .parent()
45            .unwrap()
46            .join(source_mapping_url);
47
48        println!("Processing source map {}", source_mapping_path.to_string_lossy());
49
50        let source_mapping_path = Path::new(&source_mapping_path);
51        if source_mapping_path.exists() {
52            let source_map: SourceMap = util::deserialize_object(source_mapping_path).unwrap();
53
54            let references = process_references(&settings, &source_map);
55
56            let file_refs = references.iter().map(|s| s.file_path.clone()).collect();
57            let line_refs = calculate_executable_line_mappings(&source_map, references);
58            let mut file_coverage =
59                calculate_line_coverage(data.ranges, line_refs, file_refs, data.text.as_str());
60
61            if let Some(ref reify_against_lcov) = settings.reify_against_lcov {
62                file_coverage = {
63                    eprintln!("Reifying against LCOV file");
64
65                    let mut file_hash_map: HashMap<_,_> = file_coverage.into_iter().map(|v| (v.path.clone(), v)).collect();
66
67                    for line_data in lcov::LcovFilesLines::new(&util::fast_read(&reify_against_lcov).unwrap()) {
68
69                        let our_coverage = file_hash_map.get_mut(&line_data.file_path);
70                        our_coverage.map(|our_coverage| {
71                            let new_lines : HashSet<_> = line_data.lines.into_iter().collect();
72
73                            our_coverage.lines.retain(|v| new_lines.contains(&v.line_number));
74                        });
75                    }
76
77                    file_hash_map.into_iter().map(|(_k,v)| v).collect()
78                }
79            }
80
81            Some(file_coverage)
82        } else {
83            None
84        }
85    } else {
86        None
87    }
88}
89
90pub fn run<P: AsRef<Path>, W: Write>(settings: Settings, json_path: Vec<P>, writer: Option<W>) {
91    let values = load::load_items(json_path);
92    let processed: Vec<_> = values
93        .into_iter()
94        .map(|value| process_source_map(&settings, value))
95        .flat_map(|value| value.into_iter())
96        .flat_map(|value| value.into_iter())
97        .collect();
98
99    let many_coverage = ManyCoverage { files: processed };
100
101    if let Some(writer) = writer {
102        many_coverage.write_xml(writer);
103    } else {
104        let stdout = io::stdout();
105        let handle = stdout.lock();
106
107        many_coverage.write_xml(handle);
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use std::path::Path;
114}