1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.eluder.coveralls.maven.plugin.domain;
25
26 import com.fasterxml.jackson.annotation.JsonIgnore;
27 import com.fasterxml.jackson.annotation.JsonProperty;
28
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.ListIterator;
33 import java.util.Objects;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37 public final class Source implements JsonObject {
38
39 private static final long serialVersionUID = 1L;
40
41 private static final Pattern NEWLINE = Pattern.compile("\r\n|\r|\n");
42
43
44 String name;
45 String digest;
46 Integer[] coverage;
47 List<Branch> branches;
48 String classifier;
49
50 public Source(final String name, final String source, final String digest) {
51 this(name, getLines(source), digest, null);
52 }
53
54 public Source(final String name, final int lines, final String digest, final String classifier) {
55 this.name = name;
56 this.digest = digest;
57 this.coverage = new Integer[lines];
58 this.classifier = classifier;
59 this.branches = new ArrayList<>();
60 }
61
62 @JsonIgnore
63 public String getName() {
64 return name;
65 }
66
67 @JsonProperty("name")
68 public String getFullName() {
69 return name;
70
71
72
73 }
74
75 @JsonProperty("source_digest")
76 public String getDigest() {
77 return digest;
78 }
79
80 @JsonProperty("coverage")
81 public Integer[] getCoverage() {
82 return coverage;
83 }
84
85 @JsonProperty("branches")
86 public Integer[] getBranches() {
87 final List<Integer> branchesRaw = new ArrayList<>(branches.size() * 4);
88 for (final Branch b : branches) {
89 branchesRaw.add(b.getLineNumber());
90 branchesRaw.add(b.getBlockNumber());
91 branchesRaw.add(b.getBranchNumber());
92 branchesRaw.add(b.getHits());
93 }
94 return branchesRaw.toArray(new Integer[branchesRaw.size()]);
95 }
96
97 public List<Branch> getBranchesList() {
98 return Collections.unmodifiableList(branches);
99 }
100
101 @JsonIgnore
102 public String getClassifier() {
103 return classifier;
104 }
105
106 public void setClassifier(final String classifier) {
107 this.classifier = classifier;
108 }
109
110 private void checkLineRange(final int lineNumber) {
111 int index = lineNumber - 1;
112 if (index >= this.coverage.length) {
113 throw new IllegalArgumentException("Line number " + lineNumber + " is greater than the source file " + name + " size");
114 }
115 }
116
117 public void addCoverage(final int lineNumber, final Integer coverage) {
118 checkLineRange(lineNumber);
119 this.coverage[lineNumber - 1] = coverage;
120 }
121
122 public void addBranchCoverage(final int lineNumber,
123 final int blockNumber,
124 final int branchNumber,
125 final int hits) {
126 addBranchCoverage(false, lineNumber, blockNumber, branchNumber, hits);
127 }
128
129 private void addBranchCoverage(final boolean merge,
130 final int lineNumber,
131 final int blockNumber,
132 final int branchNumber,
133 final int hits) {
134 checkLineRange(lineNumber);
135 int hitSum = hits;
136 final ListIterator<Branch> it = this.branches.listIterator();
137 while (it.hasNext()) {
138 final Branch b = it.next();
139 if (b.getLineNumber() == lineNumber &&
140 b.getBlockNumber() == blockNumber &&
141 b.getBranchNumber() == branchNumber) {
142 it.remove();
143 if (merge) {
144 hitSum += b.getHits();
145 }
146 }
147 }
148 this.branches.add(new Branch(lineNumber, blockNumber, branchNumber, hitSum));
149 }
150
151 public Source merge(final Source source) {
152 Source copy = new Source(this.name, this.coverage.length, this.digest, this.classifier);
153 System.arraycopy(this.coverage, 0, copy.coverage, 0, this.coverage.length);
154 copy.branches.addAll(this.branches);
155 if (copy.equals(source)) {
156 for (int i = 0; i < copy.coverage.length; i++) {
157 if (source.coverage[i] != null) {
158 int base = copy.coverage[i] != null ? copy.coverage[i] : 0;
159 copy.coverage[i] = base + source.coverage[i];
160 }
161 }
162 for (final Branch b : source.branches) {
163 copy.addBranchCoverage(true,
164 b.getLineNumber(),
165 b.getBlockNumber(),
166 b.getBranchNumber(),
167 b.getHits());
168 }
169 }
170 return copy;
171 }
172
173 @Override
174 public boolean equals(final Object obj) {
175 if (!(obj instanceof Source)) {
176 return false;
177 }
178 Source other = (Source) obj;
179 return (Objects.equals(this.name, other.name) &&
180 Objects.equals(this.digest, other.digest) &&
181 this.coverage.length == other.coverage.length);
182 }
183
184 @Override
185 public int hashCode() {
186 return Objects.hash(this.name, this.digest, this.coverage.length);
187 }
188
189 private static int getLines(final String source) {
190 int lines = 1;
191 Matcher matcher = NEWLINE.matcher(source);
192 while (matcher.find()) {
193 lines++;
194 }
195 return lines;
196 }
197 }