diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-17 18:01:48 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2011-06-17 18:01:57 +0200 |
commit | 9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016 (patch) | |
tree | 226688fc6a941bdc1e86290446ce016f40f7f3bb /plugins/sonar-core-plugin/src | |
parent | c973498cfec4ff8e59ac33e9c9fb150a71ef828a (diff) | |
download | sonarqube-9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016.tar.gz sonarqube-9a7fb4969d31cf0b5f5c3dbafcc19d39b9d86016.zip |
SONAR-2505 support tracking of violations on dry runs
Diffstat (limited to 'plugins/sonar-core-plugin/src')
11 files changed, 707 insertions, 325 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 08817c0ac0b..c14be8d3310 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -214,10 +214,12 @@ public class CorePlugin extends SonarPlugin { extensions.add(DirectoriesDecorator.class); extensions.add(FilesDecorator.class); extensions.add(CloseReviewsDecorator.class); + extensions.add(ReferenceAnalysis.class); // time machine extensions.add(TendencyDecorator.class); extensions.add(VariationDecorator.class); + extensions.add(ViolationTrackingDecorator.class); extensions.add(ViolationPersisterDecorator.class); extensions.add(NewViolationsDecorator.class); extensions.add(TimeMachineConfigurationPersister.class); diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java new file mode 100644 index 00000000000..4a04c1ec810 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ReferenceAnalysis.java @@ -0,0 +1,55 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.sonar.api.BatchExtension; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.Resource; + +import javax.persistence.Query; +import java.util.Collections; +import java.util.List; + +public class ReferenceAnalysis implements BatchExtension { + + private DatabaseSession session; + + public ReferenceAnalysis(DatabaseSession session) { + this.session = session; + } + + public List<RuleFailureModel> getViolations(Resource resource) { + Snapshot snapshot = getSnapshot(resource); + if (snapshot != null) { + return session.getResults(RuleFailureModel.class, "snapshotId", snapshot.getId()); + } + return Collections.emptyList(); + } + + Snapshot getSnapshot(Resource resource) { + Query query = session.createQuery("from " + Snapshot.class.getSimpleName() + " s where s.last=true and s.resourceId=(select r.id from " + + ResourceModel.class.getSimpleName() + " r where r.key=:key)"); + query.setParameter("key", resource.getEffectiveKey()); + return session.getSingleResult(query, null); + } +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java new file mode 100644 index 00000000000..8d6c327e749 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/SourceChecksum.java @@ -0,0 +1,52 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.Lists; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; + +import java.util.List; + +public final class SourceChecksum { + + private static final String SPACE_CHARS = "\t\n\r "; + + private SourceChecksum() { + // only static methods + } + + public static List<String> lineChecksumsOfFile(String file) { + List<String> result = Lists.newArrayList(); + if (file != null) { + String[] lines = file.split("\r?\n|\r", -1); + for (String line : lines) { + result.add(lineChecksum(line)); + } + } + return result; + } + + public static String lineChecksum(String line) { + String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); + return DigestUtils.md5Hex(reducedLine); + } + +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java index b14e7649670..43f7887ca33 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java @@ -19,215 +19,86 @@ */ package org.sonar.plugins.core.timemachine; -import java.util.Collection; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.Decorator; -import org.sonar.api.batch.DecoratorBarriers; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.batch.DependedUpon; -import org.sonar.api.batch.DependsUpon; +import org.sonar.api.batch.*; +import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.RuleFailureModel; -import org.sonar.api.database.model.SnapshotSource; +import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.Violation; -import org.sonar.batch.components.PastViolationsLoader; -import org.sonar.batch.index.ViolationPersister; - -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; +import org.sonar.batch.index.ResourcePersister; import org.sonar.core.NotDryRun; +import java.util.List; + @NotDryRun -@DependsUpon({ DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING }) @DependedUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) public class ViolationPersisterDecorator implements Decorator { - /** - * Those chars would be ignored during generation of checksums. - */ - private static final String SPACE_CHARS = "\t\n\r "; - - private PastViolationsLoader pastViolationsLoader; - private ViolationPersister violationPersister; + private ViolationTrackingDecorator tracker; + private ResourcePersister persister; + private RuleFinder ruleFinder; + private DatabaseSession session; - List<String> checksums; - - public ViolationPersisterDecorator(PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) { - this.pastViolationsLoader = pastViolationsLoader; - this.violationPersister = violationPersister; + public ViolationPersisterDecorator(ViolationTrackingDecorator tracker, ResourcePersister persister, RuleFinder ruleFinder, DatabaseSession session) { + this.tracker = tracker; + this.persister = persister; + this.ruleFinder = ruleFinder; + this.session = session; } public boolean shouldExecuteOnProject(Project project) { return true; } - public void decorate(Resource resource, DecoratorContext context) { - if (context.getViolations().isEmpty()) { - return; - } - // Load new violations - List<Violation> newViolations = context.getViolations(); - - // Load past violations - List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource); - - // Load current source code and calculate checksums for each line - checksums = getChecksums(pastViolationsLoader.getSource(resource)); - - // Map new violations with old ones - Map<Violation, RuleFailureModel> violationMap = mapViolations(newViolations, pastViolations); - - for (Violation newViolation : newViolations) { - String checksum = getChecksumForLine(checksums, newViolation.getLineId()); - violationPersister.saveViolation(context.getProject(), newViolation, violationMap.get(newViolation), checksum); - } - violationPersister.commit(); - // Clear cache - checksums.clear(); - } - - Map<Violation, RuleFailureModel> mapViolations(List<Violation> newViolations, List<RuleFailureModel> pastViolations) { - Map<Violation, RuleFailureModel> violationMap = new IdentityHashMap<Violation, RuleFailureModel>(); - - Multimap<Integer, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); - for (RuleFailureModel pastViolation : pastViolations) { - pastViolationsByRule.put(pastViolation.getRuleId(), pastViolation); - } - - // Try first to match violations on same rule with same line and with same checkum (but not necessarily with same message) - for (Violation newViolation : newViolations) { - mapViolation(newViolation, - findPastViolationWithSameLineAndChecksum(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - - // If each new violation matches an old one we can stop the matching mechanism - if (violationMap.size() != newViolations.size()) { - - // Try then to match violations on same rule with same message and with same checkum - for (Violation newViolation : newViolations) { - if (isNotAlreadyMapped(newViolation, violationMap)) { - mapViolation(newViolation, - findPastViolationWithSameChecksumAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - } - - // Try then to match violations on same rule with same line and with same message - for (Violation newViolation : newViolations) { - if (isNotAlreadyMapped(newViolation, violationMap)) { - mapViolation(newViolation, - findPastViolationWithSameLineAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), - pastViolationsByRule, violationMap); - } - } - } - - return violationMap; - } - - private boolean isNotAlreadyMapped(Violation newViolation, Map<Violation, RuleFailureModel> violationMap) { - return violationMap.get(newViolation) == null; - } - - private RuleFailureModel findPastViolationWithSameLineAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameLine(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; - } - - private RuleFailureModel findPastViolationWithSameChecksumAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameChecksum(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; + @DependsUpon + public Class dependsOnTracker() { + return ViolationTrackingDecorator.class; } - private RuleFailureModel findPastViolationWithSameLineAndChecksum(Violation newViolation, Collection<RuleFailureModel> pastViolations) { - for (RuleFailureModel pastViolation : pastViolations) { - if (isSameLine(newViolation, pastViolation) && isSameChecksum(newViolation, pastViolation)) { - return pastViolation; - } - } - return null; - } - - private boolean isSameChecksum(Violation newViolation, RuleFailureModel pastViolation) { - return pastViolation.getChecksum() != null - && StringUtils.equals(pastViolation.getChecksum(), getChecksumForLine(checksums, newViolation.getLineId())); + public void decorate(Resource resource, DecoratorContext context) { + saveViolations(context.getProject(), context.getViolations()); } - private boolean isSameLine(Violation newViolation, RuleFailureModel pastViolation) { - if (pastViolation.getLine() == null && newViolation.getLineId() == null) { - return true; + void saveViolations(Project project, List<Violation> violations) { + for (Violation violation : violations) { + RuleFailureModel referenceViolation = tracker.getReferenceViolation(violation); + save(project, violation, referenceViolation); } - return ObjectUtils.equals(pastViolation.getLine(), newViolation.getLineId()); + session.commit(); } - private boolean isSameMessage(Violation newViolation, RuleFailureModel pastViolation) { - return StringUtils.equals(RuleFailureModel.abbreviateMessage(newViolation.getMessage()), pastViolation.getMessage()); - } + public void save(Project project, Violation violation, RuleFailureModel referenceViolation) { + Snapshot snapshot = persister.saveResource(project, violation.getResource()); - private void mapViolation(Violation newViolation, RuleFailureModel pastViolation, - Multimap<Integer, RuleFailureModel> pastViolationsByRule, Map<Violation, RuleFailureModel> violationMap) { - if (pastViolation != null) { - pastViolationsByRule.remove(newViolation.getRule().getId(), pastViolation); - violationMap.put(newViolation, pastViolation); + RuleFailureModel model = createModel(violation); + if (referenceViolation != null) { + model.setPermanentId(referenceViolation.getPermanentId()); } - } - - /** - * @return checksums, never null - */ - private List<String> getChecksums(SnapshotSource source) { - return source == null || source.getData() == null ? Collections.<String> emptyList() : getChecksums(source.getData()); - } + model.setSnapshotId(snapshot.getId()); + session.saveWithoutFlush(model); - /** - * @param data - * can't be null - */ - static List<String> getChecksums(String data) { - String[] lines = data.split("\r?\n|\r", -1); - List<String> result = Lists.newArrayList(); - for (String line : lines) { - result.add(getChecksum(line)); + if (model.getPermanentId() == null) { + model.setPermanentId(model.getId()); + session.saveWithoutFlush(model); } - return result; + violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim) } - static String getChecksum(String line) { - String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); - return DigestUtils.md5Hex(reducedLine); - } - /** - * @return checksum or null if checksum not exists for line - */ - private String getChecksumForLine(List<String> checksums, Integer line) { - if (line == null || line < 1 || line > checksums.size()) { - return null; - } - return checksums.get(line - 1); + private RuleFailureModel createModel(Violation violation) { + RuleFailureModel model = new RuleFailureModel(); + Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey()); + model.setRuleId(rule.getId()); + model.setPriority(violation.getSeverity()); + model.setLine(violation.getLineId()); + model.setMessage(violation.getMessage()); + model.setCost(violation.getCost()); + model.setChecksum(violation.getChecksum()); + model.setCreatedAt(violation.getCreatedAt()); + model.setSwitchedOff(violation.isSwitchedOff()); + return model; } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java new file mode 100644 index 00000000000..bab5ee4a374 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java @@ -0,0 +1,197 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.*; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.rules.Violation; + +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +@DependsUpon({DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING}) +@DependedUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) +public class ViolationTrackingDecorator implements Decorator { + private ReferenceAnalysis referenceAnalysis; + private Map<Violation, RuleFailureModel> referenceViolationsMap = Maps.newIdentityHashMap(); + private SonarIndex index; + private Project project; + + public ViolationTrackingDecorator(Project project, ReferenceAnalysis referenceAnalysis, SonarIndex index) { + this.referenceAnalysis = referenceAnalysis; + this.index = index; + this.project = project; + } + + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + public void decorate(Resource resource, DecoratorContext context) { + referenceViolationsMap.clear(); + + if (!context.getViolations().isEmpty()) { + // Load new violations + List<Violation> newViolations = prepareNewViolations(context); + + // Load reference violations + List<RuleFailureModel> referenceViolations = referenceAnalysis.getViolations(resource); + + // Map new violations with old ones + mapViolations(newViolations, referenceViolations); + } + } + + private List<Violation> prepareNewViolations(DecoratorContext context) { + List<Violation> result = Lists.newArrayList(); + List<String> checksums = SourceChecksum.lineChecksumsOfFile(index.getSource(context.getResource())); + for (Violation violation : context.getViolations()) { + violation.setChecksum(getChecksumForLine(checksums, violation.getLineId())); + result.add(violation); + } + return result; + } + + RuleFailureModel getReferenceViolation(Violation violation) { + return referenceViolationsMap.get(violation); + } + + Map<Violation, RuleFailureModel> mapViolations(List<Violation> newViolations, List<RuleFailureModel> pastViolations) { + Multimap<Integer, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); + for (RuleFailureModel pastViolation : pastViolations) { + pastViolationsByRule.put(pastViolation.getRuleId(), pastViolation); + } + + // Try first to match violations on same rule with same line and with same checkum (but not necessarily with same message) + for (Violation newViolation : newViolations) { + mapViolation(newViolation, + findPastViolationWithSameLineAndChecksum(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + + // If each new violation matches an old one we can stop the matching mechanism + if (referenceViolationsMap.size() != newViolations.size()) { + // Try then to match violations on same rule with same message and with same checkum + for (Violation newViolation : newViolations) { + if (isNotAlreadyMapped(newViolation, referenceViolationsMap)) { + mapViolation(newViolation, + findPastViolationWithSameChecksumAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + } + + // Try then to match violations on same rule with same line and with same message + for (Violation newViolation : newViolations) { + if (isNotAlreadyMapped(newViolation, referenceViolationsMap)) { + mapViolation(newViolation, + findPastViolationWithSameLineAndMessage(newViolation, pastViolationsByRule.get(newViolation.getRule().getId())), + pastViolationsByRule, referenceViolationsMap); + } + } + } + return referenceViolationsMap; + } + + private boolean isNotAlreadyMapped(Violation newViolation, Map<Violation, RuleFailureModel> violationMap) { + return !violationMap.containsKey(newViolation); + } + + private RuleFailureModel findPastViolationWithSameLineAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameLine(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private RuleFailureModel findPastViolationWithSameChecksumAndMessage(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameChecksum(newViolation, pastViolation) && isSameMessage(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private RuleFailureModel findPastViolationWithSameLineAndChecksum(Violation newViolation, Collection<RuleFailureModel> pastViolations) { + for (RuleFailureModel pastViolation : pastViolations) { + if (isSameLine(newViolation, pastViolation) && isSameChecksum(newViolation, pastViolation)) { + return pastViolation; + } + } + return null; + } + + private boolean isSameChecksum(Violation newViolation, RuleFailureModel pastViolation) { + return pastViolation.getChecksum() != null + && StringUtils.equals(pastViolation.getChecksum(), newViolation.getChecksum()); + } + + private boolean isSameLine(Violation newViolation, RuleFailureModel pastViolation) { + if (pastViolation.getLine() == null && newViolation.getLineId() == null) { + return true; + } + return ObjectUtils.equals(pastViolation.getLine(), newViolation.getLineId()); + } + + private boolean isSameMessage(Violation newViolation, RuleFailureModel pastViolation) { + return StringUtils.equals(RuleFailureModel.abbreviateMessage(newViolation.getMessage()), pastViolation.getMessage()); + } + + private void mapViolation(Violation newViolation, RuleFailureModel pastViolation, + Multimap<Integer, RuleFailureModel> pastViolationsByRule, Map<Violation, RuleFailureModel> violationMap) { + if (pastViolation != null) { + newViolation.setCreatedAt(pastViolation.getCreatedAt()); + newViolation.setSwitchedOff(pastViolation.isSwitchedOff()); + pastViolationsByRule.remove(newViolation.getRule().getId(), pastViolation); + violationMap.put(newViolation, pastViolation); + } else { + newViolation.setCreatedAt(project.getAnalysisDate()); + } + } + + /** + * @return checksum or null if checksum not exists for line + */ + private String getChecksumForLine(List<String> checksums, Integer line) { + if (line == null || line < 1 || line > checksums.size()) { + return null; + } + return checksums.get(line - 1); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java new file mode 100644 index 00000000000..3c361aa61da --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/SourceChecksumTest.java @@ -0,0 +1,53 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import org.junit.Test; + +import java.util.List; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +public class SourceChecksumTest { + /** + * See http://jira.codehaus.org/browse/SONAR-2358 + */ + @Test + public void shouldGenerateCorrectChecksums() { + List<String> encoding = SourceChecksum.lineChecksumsOfFile("Привет Мир"); + assertThat(encoding.size(), is(1)); + assertThat(encoding.get(0), is("5ba3a45e1299ede07f56e5531351be52")); + } + + @Test + public void shouldSplitLinesAndIgnoreSpaces() { + List<String> crlf = SourceChecksum.lineChecksumsOfFile("Hello\r\nWorld"); + List<String> lf = SourceChecksum.lineChecksumsOfFile("Hello\nWorld"); + List<String> cr = SourceChecksum.lineChecksumsOfFile("Hello\rWorld"); + assertThat(crlf.size(), is(2)); + assertThat(crlf.get(0), not(equalTo(crlf.get(1)))); + assertThat(lf, equalTo(crlf)); + assertThat(cr, equalTo(crlf)); + + assertThat(SourceChecksum.lineChecksum("\tvoid method() {\n"), + equalTo(SourceChecksum.lineChecksum(" void method() {"))); + } +} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java index 96702000de6..ae996a82178 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest.java @@ -19,170 +19,70 @@ */ package org.sonar.plugins.core.timemachine; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -import java.util.List; -import java.util.Map; - import org.junit.Before; import org.junit.Test; import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Project; import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.Violation; +import org.sonar.api.utils.DateUtils; +import org.sonar.batch.index.ResourcePersister; +import org.sonar.core.components.DefaultRuleFinder; +import org.sonar.jpa.test.AbstractDbUnitTestCase; + +import java.util.Arrays; -import com.google.common.collect.Lists; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -public class ViolationPersisterDecoratorTest { +public class ViolationPersisterDecoratorTest extends AbstractDbUnitTestCase { private ViolationPersisterDecorator decorator; + private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header"); + private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null"); + private JavaFile javaFile = new JavaFile("org.foo.Bar"); + Project project = new Project("project"); + private ViolationTrackingDecorator tracker; @Before - public void setUp() { - decorator = new ViolationPersisterDecorator(null, null); - } - - /** - * See http://jira.codehaus.org/browse/SONAR-2358 - */ - @Test - public void shouldGenerateCorrectChecksums() { - List<String> encoding = ViolationPersisterDecorator.getChecksums("Привет Мир"); - assertThat(encoding.size(), is(1)); - assertThat(encoding.get(0), is("5ba3a45e1299ede07f56e5531351be52")); - } - - @Test - public void shouldSplitLinesAndIgnoreSpaces() { - List<String> crlf = ViolationPersisterDecorator.getChecksums("Hello\r\nWorld"); - List<String> lf = ViolationPersisterDecorator.getChecksums("Hello\nWorld"); - List<String> cr = ViolationPersisterDecorator.getChecksums("Hello\rWorld"); - assertThat(crlf.size(), is(2)); - assertThat(crlf.get(0), not(equalTo(crlf.get(1)))); - assertThat(lf, equalTo(crlf)); - assertThat(cr, equalTo(crlf)); - - assertThat(ViolationPersisterDecorator.getChecksum("\tvoid method() {\n"), - equalTo(ViolationPersisterDecorator.getChecksum(" void method() {"))); - } - - @Test - public void checksumShouldHaveGreaterPriorityThanLine() { - RuleFailureModel pastViolation1 = newPastViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation2 = newPastViolation("message", 3, 50, "checksum2"); - - Violation newViolation1 = newViolation("message", 3, 50, "checksum1"); - Violation newViolation2 = newViolation("message", 5, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation1, newViolation2), - Lists.newArrayList(pastViolation1, pastViolation2)); - assertThat(mapping.get(newViolation1), equalTo(pastViolation1)); - assertThat(mapping.get(newViolation2), equalTo(pastViolation2)); - } - - @Test - public void sameRuleAndLineAndChecksumButDifferentMessages() { - Violation newViolation = newViolation("new message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("old message", 1, 50, "checksum1"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + public void before() { + setupData("shared"); + Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); + ResourcePersister resourcePersister = mock(ResourcePersister.class); + when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot); + when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot); + tracker = mock(ViolationTrackingDecorator.class); + decorator = new ViolationPersisterDecorator(tracker, resourcePersister, new DefaultRuleFinder(getSessionFactory()), getSession()); } @Test - public void sameRuleAndLineMessage() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 1, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + public void shouldSaveViolations() { + Violation violation1a = Violation.create(rule1, javaFile) + .setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6).setMessage("the message") + .setChecksum("checksum").setCreatedAt(DateUtils.parseDate("2010-12-25")); + Violation violation1b = Violation.create(rule1, javaFile) + .setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0); + Violation violation2 = Violation.create(rule2, javaFile) + .setSeverity(RulePriority.MINOR).setSwitchedOff(true); + + decorator.saveViolations(project, Arrays.asList(violation1a, violation1b, violation2)); + + checkTables("shouldSaveViolations", "rule_failures"); } @Test - public void pastMeasureHasNoChecksum() { - Violation newViolation = newViolation("message", 1, 50, null); - RuleFailureModel pastViolation = newPastViolation("message", 1, 51, null); + public void shouldCopyPermanentIdFromReferenceViolation() { + RuleFailureModel referenceViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1); + Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); + when(tracker.getReferenceViolation(violation)).thenReturn(referenceViolation); - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void sameRuleAndMessageAndChecksumButDifferentLine() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 2, 50, "checksum1"); + decorator.saveViolations(project, Arrays.asList(violation)); - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); + checkTables("shouldCopyPermanentIdFromReferenceViolation", "rule_failures"); } - - @Test - public void shouldCreateNewViolationWhenSameRuleSameMessageButDifferentLineAndChecksum() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 2, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void shouldNotTrackViolationIfDifferentRule() { - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation("message", 1, 51, "checksum1"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), is(nullValue())); - } - - @Test - public void shouldCompareViolationsWithDatabaseFormat() { - // violation messages are trimmed and can be abbreviated when persisted in database. - // Comparing violation messages must use the same format. - Violation newViolation = newViolation("message", 1, 50, "checksum1"); - RuleFailureModel pastViolation = newPastViolation(" message ", 1, 50, "checksum2"); - - Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(pastViolation)); - assertThat(mapping.get(newViolation), equalTo(pastViolation)); - } - - private Violation newViolation(String message, int lineId, int ruleId) { - Rule rule = Rule.create().setKey("rule"); - rule.setId(ruleId); - return Violation.create(rule, null).setLineId(lineId).setMessage(message); - } - - private Violation newViolation(String message, int lineId, int ruleId, String lineChecksum) { - Violation violation = newViolation(message, lineId, ruleId); - if (decorator.checksums == null) { - decorator.checksums = Lists.newArrayListWithExpectedSize(100); - } - for (int i = decorator.checksums.size() - 1; i < lineId; i++) { - decorator.checksums.add(""); - } - if (lineChecksum != null) { - decorator.checksums.set(lineId - 1, ViolationPersisterDecorator.getChecksum(lineChecksum)); - } - return violation; - } - - private RuleFailureModel newPastViolation(String message, int lineId, int ruleId) { - RuleFailureModel pastViolation = new RuleFailureModel(); - pastViolation.setId(lineId + ruleId); - pastViolation.setLine(lineId); - pastViolation.setMessage(message); - pastViolation.setRuleId(ruleId); - return pastViolation; - } - - private RuleFailureModel newPastViolation(String message, int lineId, int ruleId, String lineChecksum) { - RuleFailureModel pastViolation = newPastViolation(message, lineId, ruleId); - if (lineChecksum != null) { - pastViolation.setChecksum(ViolationPersisterDecorator.getChecksum(lineChecksum)); - } - return pastViolation; - } - } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java new file mode 100644 index 00000000000..848e990ecad --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecoratorTest.java @@ -0,0 +1,176 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.core.timemachine; + +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.database.model.RuleFailureModel; +import org.sonar.api.resources.Project; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.Violation; +import org.sonar.api.utils.DateUtils; + +import java.text.ParseException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ViolationTrackingDecoratorTest { + + private ViolationTrackingDecorator decorator; + private Date analysisDate = DateUtils.parseDate("2010-12-25"); + + @Before + public void setUp() throws ParseException { + Project project = mock(Project.class); + when(project.getAnalysisDate()).thenReturn(analysisDate); + decorator = new ViolationTrackingDecorator(project, null, null); + } + + @Test + public void checksumShouldHaveGreaterPriorityThanLine() { + RuleFailureModel referenceViolation1 = newReferenceViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation2 = newReferenceViolation("message", 3, 50, "checksum2"); + + Violation newViolation1 = newViolation("message", 3, 50, "checksum1"); + Violation newViolation2 = newViolation("message", 5, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation1, newViolation2), + Lists.newArrayList(referenceViolation1, referenceViolation2)); + assertThat(mapping.get(newViolation1), equalTo(referenceViolation1)); + assertThat(mapping.get(newViolation2), equalTo(referenceViolation2)); + } + + @Test + public void sameRuleAndLineAndChecksumButDifferentMessages() { + Violation newViolation = newViolation("new message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("old message", 1, 50, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void sameRuleAndLineMessage() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel refernceViolation = newReferenceViolation("message", 1, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(refernceViolation)); + assertThat(mapping.get(newViolation), equalTo(refernceViolation)); + } + + @Test + public void shouldIgnoreReferenceMeasureWithoutChecksum() { + Violation newViolation = newViolation("message", 1, 50, null); + RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, null); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void sameRuleAndMessageAndChecksumButDifferentLine() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void shouldCreateNewViolationWhenSameRuleSameMessageButDifferentLineAndChecksum() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void shouldNotTrackViolationIfDifferentRule() { + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, "checksum1"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), is(nullValue())); + } + + @Test + public void shouldCompareViolationsWithDatabaseFormat() { + // violation messages are trimmed and can be abbreviated when persisted in database. + // Comparing violation messages must use the same format. + Violation newViolation = newViolation("message", 1, 50, "checksum1"); + RuleFailureModel referenceViolation = newReferenceViolation(" message ", 1, 50, "checksum2"); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation)); + assertThat(mapping.get(newViolation), equalTo(referenceViolation)); + } + + @Test + public void shouldSetDateOfNewViolations() { + Violation newViolation = newViolation("message", 1, 50, "checksum"); + assertThat(newViolation.getCreatedAt(), nullValue()); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Collections.<RuleFailureModel>emptyList()); + assertThat(mapping.size(), is(0)); + assertThat(newViolation.getCreatedAt(), is(analysisDate)); + } + + @Test + public void shouldCopyViolationDate() { + Violation newViolation = newViolation("message", 1, 50, "checksum"); + RuleFailureModel referenceViolation = newReferenceViolation("", 1, 50, "checksum"); + Date referenceDate = DateUtils.parseDate("2009-05-18"); + referenceViolation.setCreatedAt(referenceDate); + assertThat(newViolation.getCreatedAt(), nullValue()); + + Map<Violation, RuleFailureModel> mapping = decorator.mapViolations(Lists.newArrayList(newViolation), Lists.<RuleFailureModel>newArrayList(referenceViolation)); + assertThat(mapping.size(), is(1)); + assertThat(newViolation.getCreatedAt(), is(referenceDate)); + } + + private Violation newViolation(String message, int lineId, int ruleId) { + Rule rule = Rule.create().setKey("rule"); + rule.setId(ruleId); + return Violation.create(rule, null).setLineId(lineId).setMessage(message); + } + + private Violation newViolation(String message, int lineId, int ruleId, String lineChecksum) { + return newViolation(message, lineId, ruleId).setChecksum(lineChecksum); + } + + private RuleFailureModel newReferenceViolation(String message, int lineId, int ruleId, String lineChecksum) { + RuleFailureModel referenceViolation = new RuleFailureModel(); + referenceViolation.setId(lineId + ruleId); + referenceViolation.setLine(lineId); + referenceViolation.setMessage(message); + referenceViolation.setRuleId(ruleId); + referenceViolation.setChecksum(lineChecksum); + return referenceViolation; + } + +} diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shared.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shared.xml new file mode 100644 index 00000000000..90a3f202297 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shared.xml @@ -0,0 +1,24 @@ +<dataset> + + <rules_categories id="1" name="Efficiency" description="[null]"/> + <rules_categories id="6" name="Usability" description="[null]"/> + + <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" + plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" + name="Bar" long_name="org.foo.Bar" description="[null]" + enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> + + <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" + scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" + status="U" islast="false" depth="3" /> + + <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> +</dataset> diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldCopyPermanentIdFromReferenceViolation-result.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldCopyPermanentIdFromReferenceViolation-result.xml new file mode 100644 index 00000000000..fc52aa2bd62 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldCopyPermanentIdFromReferenceViolation-result.xml @@ -0,0 +1,26 @@ +<dataset> + + <rules_categories id="1" name="Efficiency" description="[null]"/> + <rules_categories id="6" name="Usability" description="[null]"/> + + <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" + plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" + name="Bar" long_name="org.foo.Bar" description="[null]" + enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> + + <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" + scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" + status="U" islast="false" depth="3" /> + + <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + + <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="[null]" checksum="[null]"/> +</dataset> diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldSaveViolations-result.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldSaveViolations-result.xml new file mode 100644 index 00000000000..726b925bf12 --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/timemachine/ViolationPersisterDecoratorTest/shouldSaveViolations-result.xml @@ -0,0 +1,26 @@ +<dataset> + <rules_categories id="1" name="Efficiency" description="[null]"/> + <rules_categories id="6" name="Usability" description="[null]"/> + + <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" + plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" + cardinality="SINGLE" parent_id="[null]"/> + + <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" + name="Bar" long_name="org.foo.Bar" description="[null]" + enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> + + <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" + scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" + status="U" islast="false" depth="3" /> + + <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> + <rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2010-12-25 00:00:00.00" checksum="checksum"/> + <rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="[null]" checksum="[null]"/> + <rule_failures switched_off="true" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="[null]" checksum="[null]"/> +</dataset>
\ No newline at end of file |