• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<%--
2  ~ Copyright (c) 2016 Google Inc. All Rights Reserved.
3  ~
4  ~ Licensed under the Apache License, Version 2.0 (the "License"); you
5  ~ may not use this file except in compliance with the License. You may
6  ~ obtain a copy of the License at
7  ~
8  ~     http://www.apache.org/licenses/LICENSE-2.0
9  ~
10  ~ Unless required by applicable law or agreed to in writing, software
11  ~ distributed under the License is distributed on an "AS IS" BASIS,
12  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13  ~ implied. See the License for the specific language governing
14  ~ permissions and limitations under the License.
15  --%>
16<%@ page contentType='text/html;charset=UTF-8' language='java' %>
17<%@ taglib prefix='fn' uri='http://java.sun.com/jsp/jstl/functions' %>
18<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core'%>
19
20<html>
21  <%@ include file="header.jsp" %>
22  <link rel="stylesheet" href="/css/show_coverage.css">
23  <script src="https://apis.google.com/js/api.js" type="text/javascript"></script>
24  <body>
25    <script type="text/javascript">
26        var coverageVectors = ${coverageVectors};
27        $(document).ready(function() {
28            // Initialize AJAX for CORS
29            $.ajaxSetup({
30                xhrFields : {
31                    withCredentials: true
32                }
33            });
34
35            // Initialize auth2 client and scope for requests to Gerrit
36            gapi.load('auth2', function() {
37                var auth2 = gapi.auth2.init({
38                    client_id: ${clientId},
39                    scope: ${gerritScope}
40                });
41                auth2.then(displayEntries);
42            });
43        });
44
45        /* Open a window to Gerrit so that user can login.
46           Minimize the previously clicked entry.
47        */
48        var gerritLogin = function(element) {
49            window.open(${gerritURI}, "Ratting", "toolbar=0,status=0");
50            element.click();
51        }
52
53        /* Loads source code for a particular entry and displays it with
54           coverage information as the accordion entry expands.
55        */
56        var onClick = function() {
57            // Remove source code from the accordion entry that was open before
58            var self = $(this);
59            var prev = self.parent().siblings('li.active');
60            if (prev.length > 0) {
61                prev.find('.table-container').empty();
62            }
63            var url = self.parent().attr('url');
64            var i = self.parent().attr('index');
65            var container = self.parent().find('.table-container');
66            container.html('<div class="center-align">Loading...</div>');
67            if (self.parent().hasClass('active')) {
68                // Remove the code from display
69                container.empty();
70            } else {
71                /* Fetch and display the code.
72                   Note: a coverageVector may be shorter than sourceContents due
73                   to non-executable (i.e. comments or language-specific syntax)
74                   lines in the code. Trailing source lines that have no
75                   coverage information are assumed to be non-executable.
76                */
77                $.ajax({
78                    url: url,
79                    dataType: 'text'
80                }).promise().done(function(src) {
81                    src = atob(src);
82                    if (!src) return;
83                    srcLines = src.split('\n');
84                    covered = 0;
85                    total = 0;
86                    var table = $('<table class="table"></table>');
87                    var rows = srcLines.forEach(function(line, j) {
88                        var count = coverageVectors[i][j];
89                        var row = $('<tr></tr>');
90                        if (typeof count == 'undefined' || count < 0) {
91                            count = "--";
92                        } else if (count == 0) {
93                            row.addClass('uncovered');
94                            total += 1;
95                        } else {
96                            row.addClass('covered');
97                            total += 1;
98                        }
99                        row.append('<td class="count">' + String(count) + '</td>');
100                        row.append('<td class="line_no">' + String(j+1) + '</td>');
101                        code = $('<td class="code"></td>');
102                        code.text(String(line));
103                        code.appendTo(row);
104                        row.appendTo(table);
105                    });
106                    container.empty();
107                    container.append(table);
108                }).fail(function(error) {
109                    if (error.status == 0) {  // origin error, refresh cookie
110                        container.empty();
111                        container.html('<div class="center-align">' +
112                                       '<span class="login-button">' +
113                                       'Click to authorize Gerrit access' +
114                                       '</span></div>');
115                        container.find('.login-button').click(function() {
116                            gerritLogin(self);
117                        });
118                    } else {
119                        container.html('<div class="center-align">' +
120                                       'Not found.</div>');
121                    }
122                });
123            }
124        }
125
126        /* Appends a row to the display with test name and aggregated coverage
127           information. On expansion, source code is loaded with coverage
128           highlighted by calling 'onClick'.
129        */
130        var displayEntries = function() {
131            var sourceFilenames = ${sourceFiles};
132            var sectionMap = ${sectionMap};
133            var gerritURI = ${gerritURI};
134            var projects = ${projects};
135            var commits = ${commits};
136            var indicators = ${indicators};
137            Object.keys(sectionMap).forEach(function(section) {
138                var indices = sectionMap[section];
139                var html = String();
140                indices.forEach(function(i) {
141                    var url = gerritURI + '/projects/' +
142                              encodeURIComponent(projects[i]) + '/commits/' +
143                              encodeURIComponent(commits[i]) + '/files/' +
144                              encodeURIComponent(sourceFilenames[i]) +
145                              '/content';
146                    html += '<li url="' + url + '" index="' + i + '">' +
147                            '<div class="collapsible-header">' +
148                            '<i class="material-icons">library_books</i>' +
149                            sourceFilenames[i] + indicators[i] + '</div>';
150                    html += '<div class="collapsible-body row">' +
151                            '<div class="html-container">' +
152                            '<div class="table-container"></div>' +
153                            '</div></div></li>';
154                });
155                if (html) {
156                    html = '<h4 class="section-title"><b>Coverage:</b> ' +
157                           section + '</h4><ul class="collapsible popout" ' +
158                           'data-collapsible="accordion">' + html + '</ul>';
159                    $('#coverage-container').append(html);
160                }
161            });
162            $('.collapsible.popout').collapsible({
163               accordion : true
164            }).find('.collapsible-header').click(onClick);
165        }
166    </script>
167    <div id='coverage-container' class='wide container'>
168    </div>
169    <%@ include file="footer.jsp" %>
170  </body>
171</html>
172