lcov_parser/report/
function.rs

1// Copyright (c) 2015-2016 lcov-parser developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use std::io;
10use std::cmp::PartialEq;
11use std::collections::btree_map:: { BTreeMap };
12use std::convert::{ From };
13use std::fmt:: { Display, Formatter, Result };
14use record:: { FunctionName as FunctionNameRecord, FunctionData };
15use merger::ops:: { TryMerge, MergeResult, FunctionError };
16use record:: { RecordWrite };
17use report::summary:: { Summary };
18use report::attribute:: { ExecutionCount, FunctionName, LineNumber };
19use report::counter:: { Hit, HitFoundCounter, FoundCounter, HitCounter };
20
21
22#[derive(Debug, Clone)]
23pub struct Functions {
24    functions: BTreeMap<FunctionName, Function>
25}
26
27impl Functions {
28    pub fn new() -> Self {
29        Functions {
30            functions: BTreeMap::new()
31        }
32    }
33}
34
35impl_summary!(Functions, functions<FunctionName, Function>);
36
37impl HitCounter for Functions {
38    fn hit_count(&self) -> usize {
39        self.iter()
40            .filter(|&(_, function)| function.is_hit() )
41            .count()
42    }
43}
44
45impl FoundCounter for Functions {
46    fn found_count(&self) -> usize {
47        self.functions.len()
48    }
49}
50
51impl HitFoundCounter for Functions {
52}
53
54
55impl RecordWrite for Functions {
56    fn write_records<T: io::Write>(&self, output: &mut T) -> io::Result<()> {
57        write!(output, "{}", self)
58    }
59}
60
61impl Display for Functions {
62    fn fmt(&self, f: &mut Formatter) -> Result {
63        if self.is_empty() {
64            return Ok(());
65        }
66        for (_, function) in self.iter() {
67            writeln!(f, "FN:{},{}", function.line_number(), function.name())?;
68            writeln!(f, "FNDA:{},{}", function.execution_count(), function.name())?;
69        }
70        writeln!(f, "FNF:{}", self.hit_count())?;
71        writeln!(f, "FNH:{}", self.found_count())?;
72        Ok(())
73    }
74}
75
76
77
78impl<'a> TryMerge<&'a FunctionData> for Functions {
79    type Err = FunctionError;
80
81    fn try_merge(&mut self, function_data: &'a FunctionData) -> MergeResult<Self::Err> {
82        if !self.functions.contains_key(&function_data.name) {
83            self.functions.insert(
84                function_data.name.clone(),
85                Function::from(function_data)
86            );
87            return Ok(());
88        }
89        let function = self.functions.get_mut(&function_data.name).unwrap();
90        function.try_merge(function_data)
91    }
92}
93
94
95impl<'a> TryMerge<&'a FunctionNameRecord> for Functions {
96    type Err = FunctionError;
97
98    fn try_merge(&mut self, function_name: &'a FunctionNameRecord) -> MergeResult<Self::Err> {
99        if !self.functions.contains_key(&function_name.name) {
100            self.functions.insert(
101                function_name.name.clone(),
102                Function::from(function_name)
103            );
104            return Ok(());
105        }
106        let function = self.functions.get_mut(&function_name.name).unwrap();
107        function.try_merge(function_name)
108    }
109}
110
111impl_try_merge_self_summary!(Functions:functions, FunctionError);
112
113
114#[derive(Debug, Clone)]
115pub struct Function {
116    name: FunctionName,
117    line_number: LineNumber,
118    execution_count: ExecutionCount
119}
120
121impl Function {
122    pub fn new(
123        name: FunctionName,
124        line_number: LineNumber,
125        execution_count: ExecutionCount,
126    ) -> Self {
127        Function {
128            name: name,
129            line_number: line_number,
130            execution_count: execution_count
131        }
132    }
133    pub fn name(&self) -> &FunctionName {
134        &self.name
135    }
136    pub fn line_number(&self) -> &LineNumber {
137        &self.line_number
138    }
139    pub fn execution_count(&self) -> &ExecutionCount {
140        &self.execution_count
141    }
142    pub fn is_hit(&self) -> bool {
143        self.execution_count.is_hit()
144    }
145}
146
147impl<'a> From<&'a FunctionData> for Function {
148    fn from(function_data: &'a FunctionData) -> Self {
149        Function::new(
150            function_data.name.clone(),
151            0,
152            function_data.count
153        )
154    }
155}
156
157
158impl<'a> From<&'a FunctionNameRecord> for Function {
159    fn from(function_name: &'a FunctionNameRecord) -> Self {
160        Function::new(
161            function_name.name.clone(),
162            function_name.line,
163            0
164        )
165    }
166}
167
168impl PartialEq for Function {
169    fn eq(&self, other: &Self) -> bool {
170        &self.name == other.name() && &self.line_number == other.line_number()
171    }
172}
173
174impl<'a> TryMerge<&'a FunctionNameRecord> for Function {
175    type Err = FunctionError;
176
177    fn try_merge(&mut self, other: &'a FunctionNameRecord) -> MergeResult<Self::Err> {
178        if self.name != other.name {
179            return Err(FunctionError::Mismatch(
180                self.name.clone(),
181                other.name.clone()
182            ));
183        }
184        self.name = other.name.clone();
185        self.line_number = other.line;
186        Ok(())
187    }
188}
189
190
191
192impl<'a> TryMerge<&'a FunctionData> for Function {
193    type Err = FunctionError;
194
195    fn try_merge(&mut self, other: &'a FunctionData) -> MergeResult<Self::Err> {
196        if self.name != other.name {
197            return Err(FunctionError::Mismatch(
198                self.name.clone(),
199                other.name.clone()
200            ));
201        }
202        self.execution_count += other.count;
203        Ok(())
204    }
205}
206
207
208impl<'a> TryMerge<&'a Function> for Function {
209    type Err = FunctionError;
210
211    fn try_merge(&mut self, other: &'a Function) -> MergeResult<Self::Err> {
212        if self.name() != other.name() {
213            return Err(FunctionError::Mismatch(
214                self.name.clone(),
215                other.name().clone()
216            ));
217        }
218        self.execution_count += *other.execution_count();
219        Ok(())
220    }
221}
222
223
224
225
226#[cfg(test)]
227mod tests {
228    use record:: { FunctionData };
229    use report::function:: { Function, Functions };
230    use report::summary:: { Summary };
231    use report::counter:: { FoundCounter, HitCounter };
232    use merger::ops::*;
233
234    #[test]
235    fn add_function_data() {
236        let mut functions = Functions::new();
237        functions.try_merge(&FunctionData { name: "main".to_string(), count: 1 }).unwrap();
238        functions.try_merge(&FunctionData { name: "main".to_string(), count: 1 }).unwrap();
239
240        let result = functions.clone();
241        assert_eq!( result.get(&"main".to_string()), Some( &Function::new("main".to_string(), 0, 1)));
242    }
243
244    #[test]
245    fn add_functions_data() {
246        let mut functions = Functions::new();
247        functions.try_merge(&FunctionData { name: "main".to_string(), count: 1 }).unwrap();
248
249        let ref cloned_functions = functions.clone();
250        functions.try_merge(cloned_functions).unwrap();
251
252        assert_eq!( functions.get(&"main".to_string()), Some( &Function::new("main".to_string(), 0, 2)));
253    }
254
255    #[test]
256    fn hit_count_and_found_count() {
257        let mut functions = Functions::new();
258        functions.try_merge(&FunctionData { name: "main".to_string(), count: 1 }).unwrap();
259        functions.try_merge(&FunctionData { name: "main".to_string(), count: 0 }).unwrap();
260        functions.try_merge(&FunctionData { name: "foo".to_string(), count: 0 }).unwrap();
261
262        assert_eq!( functions.hit_count(), 1 );
263        assert_eq!( functions.found_count(), 2 );
264    }
265}