aboutsummaryrefslogtreecommitdiff
path: root/src/CoverageListing.js
blob: 8b7830c0d19a3308ba8a5d9b502fcddf655ec1a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
 * JaCoCo Report Viewer, a web-based coverage report viewer
 * Copyright (C) 2018  Pacien TRAN-GIRARD
 *                     Adam NAILI
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import React, { Component } from 'react';

export class CoverageListing extends Component {
  constructor(props) {
    super(props);
    this.state = {
      listingContent: null,
      coverageMap: null
    };
  }

  componentDidMount() {
    this._updateState();
  }

  componentDidUpdate(prevProps) {
    if (this.props.fileName === prevProps.fileName &&
        this.props.sourceSet === prevProps.sourceSet &&
        this.props.coverage === prevProps.coverage) return;

    this._updateState();
  }

  _updateState() {
    if (!this.props.sourceSet || !(this.props.fileName in this.props.sourceSet)) {
      this.setState({ listingContent: null });
      return;
    }

    this._updateListingContent();
    this._updateCoverageMap();
  }

  _updateCoverageMap() {
    const coverageMap = this.props.coverage.reduce((map, line) => (map[parseInt(line.$.nr)] = line.$, map), {});
    this.setState({ coverageMap: coverageMap });
  }

  _updateListingContent() {
    this.props.sourceSet[this.props.fileName]
              .async('text')
              .then(content => this.setState({ listingContent: content }));
  }

  _renderNone() {
    return (<div>No source file provided.</div>);
  }

  _nonEmptyString(str) {
    return str ? str : ' '; // workaround for empty <pre> collapsing
  }

  _renderLine(lineContent, lineNumber) {
    if (!(lineNumber in this.state.coverageMap))
      return (<li key={lineNumber}><pre>{lineContent}</pre></li>);
    
    const coverage = this.state.coverageMap[lineNumber];
    const wellCovered = parseInt(coverage.mi) === 0 && parseInt(coverage.mb) === 0;
    return (<li key={lineNumber} well-covered={wellCovered.toString()}><pre>{lineContent}</pre></li>);
  }

  _renderListing() {
    const lines = this.state.listingContent
                            .split('\n')
                            .map(this._nonEmptyString)
                            .map((line, index) => this._renderLine(line, index + 1));

    return (<div className="listing"><ol>{lines}</ol></div>);
  }

  render() {
    return this.state.listingContent ? this._renderListing() : this._renderNone();
  }
}