lcov_parser/report/
function.rs1use 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}