import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
public class IssueTracking implements BatchComponent {
if (issues.isEmpty()) {
return;
}
+ FileHashes hashedSource = sourceHashHolder.getHashedSource();
for (DefaultIssue issue : issues) {
Integer line = issue.line();
if (line != null) {
- issue.setChecksum(sourceHashHolder.getHashedSource().getHash(line));
+ // Extra verification if some plugin managed to create issue on a wrong line
+ Preconditions.checkState(line <= hashedSource.length(), "Invalid line number for issue %s. File has only %s line(s)", issue, hashedSource.length());
+ issue.setChecksum(hashedSource.getHash(line));
}
}
}
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
+import java.io.*;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.ArrayList;
*/
public class FileMetadata implements BatchComponent {
- private static final Logger LOG = LoggerFactory.getLogger(FileMetadata.class);
+ private static final Logger LOG = Loggers.get(FileMetadata.class);
private static final char LINE_FEED = '\n';
private static final char CARRIAGE_RETURN = '\r';
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.issue.Issue;
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
IssueTracking tracking;
Resource project;
SourceHashHolder sourceHashHolder;
assertThat(result.matching(newIssue)).isEqualTo(referenceIssue);
}
+ @Test
+ public void check_valid_line() throws Exception {
+ initLastHashes("example2-v1", "example2-v2");
+
+ DefaultIssue newIssue = newDefaultIssue("1 branch need to be covered", 200, RuleKey.of("squid", "AvoidCycle"), null);
+
+ thrown
+ .expectMessage("Invalid line number for issue DefaultIssue[key=<null>,componentUuid=<null>,componentKey=<null>,moduleUuid=<null>,moduleUuidPath=<null>,projectUuid=<null>,projectKey=<null>,ruleKey=squid:AvoidCycle,language=<null>,severity=<null>,manualSeverity=false,message=1 branch need to be covered,line=200,effortToFix=<null>,debt=<null>,status=OPEN,resolution=<null>,reporter=<null>,assignee=<null>,checksum=<null>,attributes=<null>,authorLogin=<null>,actionPlanKey=<null>,comments=<null>,tags=<null>,creationDate=<null>,updateDate=<null>,closeDate=<null>,currentChange=<null>,changes=<null>,isNew=true,endOfLife=false,onDisabledRule=false,isChanged=false,sendNotifications=false,selectedAt=<null>]. File has only 17 line(s)");
+
+ tracking.track(sourceHashHolder, Collections.<ServerIssue>emptyList(), newArrayList(newIssue));
+ }
+
/**
* SONAR-3072
*/
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.batch.scan.filesystem.FileMetadata.LineHashConsumer;
import javax.annotation.Nullable;
private AnalysisMode mode = mock(AnalysisMode.class);
+ @Rule
+ public LogTester logTester = new LogTester();
+
@Test
public void empty_file() throws Exception {
File tempFile = temp.newFile();
assertThat(hash1).isNotEqualTo(hash2);
}
+ @Test
+ public void binary_file_with_unmappable_character() throws Exception {
+ File woff = new File(this.getClass().getResource("glyphicons-halflings-regular.woff").toURI());
+
+ FileMetadata.Metadata metadata = new FileMetadata(mode).read(woff, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(135);
+ assertThat(metadata.nonBlankLines).isEqualTo(134);
+ assertThat(metadata.hash).isNotEmpty();
+ assertThat(metadata.empty).isFalse();
+
+ assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains("Invalid character encountered in file");
+ assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains(
+ "glyphicons-halflings-regular.woff at line 1 for encoding UTF-8. Please fix file content or configure the encoding to be used using property 'sonar.sourceEncoding'.");
+ }
+
}