1
1
use flate2:: read:: GzDecoder ;
2
- use serde:: Deserialize ;
2
+ use serde:: { Deserialize , Deserializer } ;
3
3
use std:: cmp:: Ordering ;
4
4
use std:: collections:: { btree_map, hash_map, BTreeMap } ;
5
5
use std:: fmt;
@@ -341,6 +341,7 @@ struct GcovFile {
341
341
struct GcovLine {
342
342
line_number : u32 ,
343
343
function_name : Option < String > ,
344
+ #[ serde( deserialize_with = "deserialize_counter" ) ]
344
345
count : u64 ,
345
346
unexecuted_block : bool ,
346
347
branches : Vec < GcovBr > ,
@@ -349,6 +350,7 @@ struct GcovLine {
349
350
#[ derive( Debug , Deserialize ) ]
350
351
#[ allow( dead_code) ]
351
352
struct GcovBr {
353
+ #[ serde( deserialize_with = "deserialize_counter" ) ]
352
354
count : u64 ,
353
355
throw : bool ,
354
356
fallthrough : bool ,
@@ -365,9 +367,33 @@ struct GcovFunction {
365
367
end_column : u32 ,
366
368
blocks : u32 ,
367
369
blocks_executed : u32 ,
370
+ #[ serde( deserialize_with = "deserialize_counter" ) ]
368
371
execution_count : u64 ,
369
372
}
370
373
374
+ // JSON sometimes surprises us with floats where we expected integers, use
375
+ // a custom deserializer to ensure all the counters are converted to u64.
376
+ pub fn deserialize_counter < ' de , D > ( deserializer : D ) -> Result < u64 , D :: Error >
377
+ where
378
+ D : Deserializer < ' de > ,
379
+ {
380
+ let n: serde_json:: Number = Deserialize :: deserialize ( deserializer) ?;
381
+ if n. is_f64 ( ) {
382
+ let value: f64 = n. as_f64 ( ) . unwrap ( ) ;
383
+ if ( value >= 0.0 ) && ( value <= u64:: MAX as f64 ) {
384
+ return Ok ( value as u64 ) ;
385
+ }
386
+ }
387
+
388
+ match n. as_u64 ( ) {
389
+ Some ( value) => Ok ( value) ,
390
+ None => Err ( serde:: de:: Error :: custom ( format ! (
391
+ "Unable to parse u64 from {}" ,
392
+ n
393
+ ) ) ) ,
394
+ }
395
+ }
396
+
371
397
pub fn parse_gcov_gz ( gcov_path : & Path ) -> Result < Vec < ( String , CovResult ) > , ParserError > {
372
398
let f = File :: open ( & gcov_path)
373
399
. unwrap_or_else ( |_| panic ! ( "Failed to open gcov file {}" , gcov_path. display( ) ) ) ;
@@ -1717,6 +1743,187 @@ mod tests {
1717
1743
assert ! ( func. executed) ;
1718
1744
}
1719
1745
1746
+ #[ test]
1747
+ fn test_parser_gcov_gz ( ) {
1748
+ let results = parse_gcov_gz ( Path :: new (
1749
+ "./test/mozillavpn_serverconnection.gcno.gcov.json.gz" ,
1750
+ ) )
1751
+ . unwrap ( ) ;
1752
+ assert_eq ! ( results. len( ) , 37 ) ;
1753
+ let ( ref source_name, ref result) = results[ 0 ] ;
1754
+
1755
+ assert_eq ! ( source_name, "server/serverconnection.cpp" ) ;
1756
+
1757
+ assert_eq ! (
1758
+ result. lines,
1759
+ [
1760
+ ( 32 , 0 ) ,
1761
+ ( 33 , 0 ) ,
1762
+ ( 35 , 0 ) ,
1763
+ ( 36 , 0 ) ,
1764
+ ( 37 , 0 ) ,
1765
+ ( 38 , 0 ) ,
1766
+ ( 40 , 0 ) ,
1767
+ ( 41 , 0 ) ,
1768
+ ( 42 , 0 ) ,
1769
+ ( 43 , 0 ) ,
1770
+ ( 44 , 0 ) ,
1771
+ ( 45 , 0 ) ,
1772
+ ( 46 , 0 ) ,
1773
+ ( 48 , 0 ) ,
1774
+ ( 49 , 0 ) ,
1775
+ ( 50 , 0 ) ,
1776
+ ( 51 , 0 ) ,
1777
+ ( 52 , 0 ) ,
1778
+ ( 55 , 0 ) ,
1779
+ ( 56 , 0 ) ,
1780
+ ( 57 , 0 ) ,
1781
+ ( 58 , 0 ) ,
1782
+ ( 59 , 0 ) ,
1783
+ ( 61 , 0 ) ,
1784
+ ( 62 , 0 ) ,
1785
+ ( 63 , 0 ) ,
1786
+ ( 66 , 0 ) ,
1787
+ ( 67 , 0 ) ,
1788
+ ( 68 , 0 ) ,
1789
+ ( 71 , 0 ) ,
1790
+ ( 74 , 0 ) ,
1791
+ ( 75 , 0 ) ,
1792
+ ( 78 , 0 ) ,
1793
+ ( 79 , 0 ) ,
1794
+ ( 82 , 0 ) ,
1795
+ ( 83 , 0 ) ,
1796
+ ( 85 , 0 ) ,
1797
+ ( 86 , 0 ) ,
1798
+ ( 87 , 0 ) ,
1799
+ ( 88 , 0 ) ,
1800
+ ( 90 , 0 ) ,
1801
+ ( 91 , 0 ) ,
1802
+ ( 94 , 0 ) ,
1803
+ ( 95 , 0 ) ,
1804
+ ( 96 , 0 ) ,
1805
+ ( 97 , 0 ) ,
1806
+ ( 101 , 0 ) ,
1807
+ ( 102 , 0 ) ,
1808
+ ( 103 , 0 ) ,
1809
+ ( 104 , 0 ) ,
1810
+ ( 107 , 0 ) ,
1811
+ ( 112 , 0 ) ,
1812
+ ( 113 , 0 ) ,
1813
+ ( 114 , 0 ) ,
1814
+ ( 118 , 0 ) ,
1815
+ ( 119 , 0 ) ,
1816
+ ( 120 , 0 ) ,
1817
+ ( 124 , 0 ) ,
1818
+ ( 125 , 0 ) ,
1819
+ ( 126 , 0 ) ,
1820
+ ( 129 , 0 ) ,
1821
+ ( 130 , 0 ) ,
1822
+ ( 131 , 0 ) ,
1823
+ ( 135 , 0 ) ,
1824
+ ( 136 , 0 ) ,
1825
+ ( 137 , 0 ) ,
1826
+ ( 138 , 0 ) ,
1827
+ ( 139 , 0 ) ,
1828
+ ( 142 , 0 ) ,
1829
+ ( 143 , 0 ) ,
1830
+ ( 144 , 0 ) ,
1831
+ ( 148 , 0 ) ,
1832
+ ( 149 , 0 ) ,
1833
+ ( 150 , 0 ) ,
1834
+ ( 151 , 0 ) ,
1835
+ ( 157 , 0 ) ,
1836
+ ( 158 , 0 ) ,
1837
+ ( 159 , 0 ) ,
1838
+ ( 164 , 0 ) ,
1839
+ ( 169 , 0 ) ,
1840
+ ( 171 , 0 ) ,
1841
+ ( 172 , 0 ) ,
1842
+ ( 175 , 0 ) ,
1843
+ ( 176 , 0 ) ,
1844
+ ( 178 , 0 ) ,
1845
+ ( 179 , 0 ) ,
1846
+ ( 181 , 0 ) ,
1847
+ ( 183 , 0 ) ,
1848
+ ( 184 , 0 ) ,
1849
+ ( 185 , 0 ) ,
1850
+ ( 186 , 0 ) ,
1851
+ ( 188 , 0 ) ,
1852
+ ( 189 , 0 ) ,
1853
+ ( 190 , 0 ) ,
1854
+ ( 193 , 0 ) ,
1855
+ ( 194 , 0 ) ,
1856
+ ( 195 , 0 ) ,
1857
+ ( 196 , 0 ) ,
1858
+ ( 199 , 0 ) ,
1859
+ ( 200 , 0 ) ,
1860
+ ( 202 , 0 ) ,
1861
+ ( 203 , 0 ) ,
1862
+ ( 205 , 0 ) ,
1863
+ ( 206 , 0 ) ,
1864
+ ( 207 , 0 ) ,
1865
+ ( 210 , 0 ) ,
1866
+ ( 216 , 0 ) ,
1867
+ ( 217 , 0 ) ,
1868
+ ( 220 , 0 ) ,
1869
+ ( 221 , 0 ) ,
1870
+ ( 223 , 0 ) ,
1871
+ ( 225 , 0 ) ,
1872
+ ( 226 , 0 ) ,
1873
+ ( 227 , 0 ) ,
1874
+ ( 230 , 0 ) ,
1875
+ ( 231 , 0 ) ,
1876
+ ( 234 , 0 ) ,
1877
+ ( 237 , 0 ) ,
1878
+ ( 238 , 0 ) ,
1879
+ ( 239 , 0 ) ,
1880
+ ( 241 , 0 ) ,
1881
+ ( 242 , 0 ) ,
1882
+ ( 243 , 0 ) ,
1883
+ ( 245 , 0 ) ,
1884
+ ( 247 , 0 ) ,
1885
+ ( 248 , 0 ) ,
1886
+ ( 249 , 0 ) ,
1887
+ ( 251 , 0 ) ,
1888
+ ( 252 , 0 ) ,
1889
+ ( 254 , 0 ) ,
1890
+ ( 255 , 0 ) ,
1891
+ ( 256 , 0 ) ,
1892
+ ( 257 , 0 ) ,
1893
+ ( 258 , 0 ) ,
1894
+ ( 260 , 0 ) ,
1895
+ ( 261 , 0 ) ,
1896
+ ( 262 , 0 ) ,
1897
+ ( 263 , 0 ) ,
1898
+ ( 264 , 0 ) ,
1899
+ ( 267 , 0 ) ,
1900
+ ( 268 , 0 ) ,
1901
+ ( 270 , 0 ) ,
1902
+ ( 271 , 0 ) ,
1903
+ ( 272 , 0 ) ,
1904
+ ( 273 , 0 ) ,
1905
+ ( 274 , 0 ) ,
1906
+ ( 275 , 0 ) ,
1907
+ ( 279 , 0 )
1908
+ ]
1909
+ . iter( )
1910
+ . cloned( )
1911
+ . collect( )
1912
+ ) ;
1913
+
1914
+ assert_eq ! ( result. branches, [ ] . iter( ) . cloned( ) . collect( ) ) ;
1915
+
1916
+ assert ! ( result
1917
+ . functions
1918
+ . contains_key( "ServerConnection::readData()" ) ) ;
1919
+ let func = result
1920
+ . functions
1921
+ . get ( "ServerConnection::readData()" )
1922
+ . unwrap ( ) ;
1923
+ assert_eq ! ( func. start, 188 ) ;
1924
+ assert ! ( !func. executed) ;
1925
+ }
1926
+
1720
1927
#[ test]
1721
1928
fn test_parser_jacoco_xml_basic ( ) {
1722
1929
let mut lines: BTreeMap < u32 , u64 > = BTreeMap :: new ( ) ;
0 commit comments