import org.sonar.batch.scan.LastSnapshots;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.db.IssueDto;
-import org.sonar.plugins.core.timemachine.SourceChecksum;
-import org.sonar.plugins.core.timemachine.ViolationTrackingBlocksRecognizer;
-import org.sonar.plugins.core.timemachine.tracking.*;
+import org.sonar.plugins.core.issue.tracking.*;
+import org.sonar.plugins.core.issue.tracking.SourceChecksum;
+import org.sonar.plugins.core.issue.tracking.ViolationTrackingBlocksRecognizer;
import javax.annotation.Nullable;
import java.util.*;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Wraps a {@link Sequence} to assign hash codes to elements.
+ */
+public final class HashedSequence<S extends Sequence> implements Sequence {
+
+ final S base;
+ final int[] hashes;
+
+ public static <S extends Sequence> HashedSequence<S> wrap(S base, SequenceComparator<S> cmp) {
+ int size = base.length();
+ int[] hashes = new int[size];
+ for (int i = 0; i < size; i++) {
+ hashes[i] = cmp.hash(base, i);
+ }
+ return new HashedSequence<S>(base, hashes);
+ }
+
+ private HashedSequence(S base, int[] hashes) {
+ this.base = base;
+ this.hashes = hashes;
+ }
+
+ public int length() {
+ return base.length();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Wrap another {@link SequenceComparator} for use with {@link HashedSequence}.
+ */
+public class HashedSequenceComparator<S extends Sequence> implements SequenceComparator<HashedSequence<S>> {
+
+ private final SequenceComparator<? super S> cmp;
+
+ public HashedSequenceComparator(SequenceComparator<? super S> cmp) {
+ this.cmp = cmp;
+ }
+
+ public boolean equals(HashedSequence<S> a, int ai, HashedSequence<S> b, int bi) {
+ if (a.hashes[ai] == b.hashes[bi]) {
+ return cmp.equals(a.base, ai, b.base, bi);
+ }
+ return false;
+ }
+
+ public int hash(HashedSequence<S> seq, int i) {
+ return seq.hashes[i];
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Wraps a {@link Sequence} to assign hash codes to elements.
+ */
+public class RollingHashSequence<S extends Sequence> implements Sequence {
+
+ final S base;
+ final int[] hashes;
+
+ public static <S extends Sequence> RollingHashSequence<S> wrap(S base, SequenceComparator<S> cmp, int lines) {
+ int size = base.length();
+ int[] hashes = new int[size];
+
+ RollingHashCalculator hashCalulator = new RollingHashCalculator(lines * 2 + 1);
+ for (int i = 0; i <= Math.min(size - 1, lines); i++) {
+ hashCalulator.add(cmp.hash(base, i));
+ }
+ for (int i = 0; i < size; i++) {
+ hashes[i] = hashCalulator.getHash();
+ if (i - lines >= 0) {
+ hashCalulator.remove(cmp.hash(base, i - lines));
+ }
+ if (i + lines + 1 < size) {
+ hashCalulator.add(cmp.hash(base, i + lines + 1));
+ } else {
+ hashCalulator.add(0);
+ }
+ }
+
+ return new RollingHashSequence<S>(base, hashes);
+ }
+
+ private RollingHashSequence(S base, int[] hashes) {
+ this.base = base;
+ this.hashes = hashes;
+ }
+
+ public int length() {
+ return base.length();
+ }
+
+ private static class RollingHashCalculator {
+
+ private static final int PRIME_BASE = 31;
+
+ private final int power;
+ private int hash;
+
+ public RollingHashCalculator(int size) {
+ int pow = 1;
+ for (int i = 0; i < size - 1; i++) {
+ pow = pow * PRIME_BASE;
+ }
+ this.power = pow;
+ }
+
+ public void add(int value) {
+ hash = hash * PRIME_BASE + value;
+ }
+
+ public void remove(int value) {
+ hash = hash - power * value;
+ }
+
+ public int getHash() {
+ return hash;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Wrap another {@link SequenceComparator} for use with {@link RollingHashSequence}.
+ */
+public class RollingHashSequenceComparator<S extends Sequence> implements SequenceComparator<RollingHashSequence<S>> {
+
+ private final SequenceComparator<? super S> cmp;
+
+ public RollingHashSequenceComparator(SequenceComparator<? super S> cmp) {
+ this.cmp = cmp;
+ }
+
+ public boolean equals(RollingHashSequence<S> a, int ai, RollingHashSequence<S> b, int bi) {
+ if (a.hashes[ai] == b.hashes[bi]) {
+ return cmp.equals(a.base, ai, b.base, bi);
+ }
+ return false;
+ }
+
+ public int hash(RollingHashSequence<S> seq, int i) {
+ return seq.hashes[i];
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Arbitrary sequence of elements.
+ */
+public interface Sequence {
+
+ /**
+ * @return total number of items in the sequence
+ */
+ int length();
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Equivalence function for a {@link Sequence}.
+ */
+public interface SequenceComparator<S extends Sequence> {
+
+ /**
+ * Compare two items to determine if they are equivalent.
+ */
+ boolean equals(S a, int ai, S b, int bi);
+
+ /**
+ * Get a hash value for an item in a sequence.
+ *
+ * If two items are equal according to this comparator's
+ * {@link #equals(Sequence, int, Sequence, int)} method,
+ * then this hash method must produce the same integer result for both items.
+ * However not required to have different hash values for different items.
+ */
+ int hash(S seq, int i);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+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
+ }
+
+ /**
+ * @param line line number (first line has number 1)
+ * @return checksum or null if checksum not exists for line
+ */
+ public static String getChecksumForLine(List<String> checksums, Integer line) {
+ if (line == null || line < 1 || line > checksums.size()) {
+ return null;
+ }
+ return checksums.get(line - 1);
+ }
+
+ 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);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Text is a {@link Sequence} of lines.
+ */
+public class StringText implements Sequence {
+
+ final String content;
+
+ /**
+ * Map of line number to starting position within {@link #content}.
+ */
+ final List<Integer> lines;
+
+ public StringText(String str) {
+ this.content = str;
+ this.lines = lineMap(content, 0, content.length());
+ }
+
+ public int length() {
+ return lines.size() - 2;
+ }
+
+ private static List<Integer> lineMap(String buf, int ptr, int end) {
+ List<Integer> lines = Lists.newArrayList();
+ lines.add(Integer.MIN_VALUE);
+ for (; ptr < end; ptr = nextLF(buf, ptr)) {
+ lines.add(ptr);
+ }
+ lines.add(end);
+ return lines;
+ }
+
+ private static int nextLF(String b, int ptr) {
+ return next(b, ptr, '\n');
+ }
+
+ private static int next(final String b, int ptr, final char chrA) {
+ final int sz = b.length();
+ while (ptr < sz) {
+ if (b.charAt(ptr++) == chrA) {
+ return ptr;
+ }
+ }
+ return ptr;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+/**
+ * Equivalence function for {@link StringText}.
+ */
+public abstract class StringTextComparator implements SequenceComparator<StringText> {
+
+ /**
+ * Ignores all whitespace.
+ */
+ public static final StringTextComparator IGNORE_WHITESPACE = new StringTextComparator() {
+
+ public boolean equals(StringText a, int ai, StringText b, int bi) {
+ ai++;
+ bi++;
+ int as = a.lines.get(ai);
+ int bs = b.lines.get(bi);
+ int ae = a.lines.get(ai + 1);
+ int be = b.lines.get(bi + 1);
+ ae = trimTrailingWhitespace(a.content, as, ae);
+ be = trimTrailingWhitespace(b.content, bs, be);
+ while ((as < ae) && (bs < be)) {
+ char ac = a.content.charAt(as);
+ char bc = b.content.charAt(bs);
+ while ((as < ae - 1) && (Character.isWhitespace(ac))) {
+ as++;
+ ac = a.content.charAt(as);
+ }
+ while ((bs < be - 1) && (Character.isWhitespace(bc))) {
+ bs++;
+ bc = b.content.charAt(bs);
+ }
+ if (ac != bc) {
+ return false;
+ }
+ as++;
+ bs++;
+ }
+ return (as == ae) && (bs == be);
+ }
+
+ @Override
+ protected int hashRegion(String content, int start, int end) {
+ int hash = 5381;
+ for (; start < end; start++) {
+ char c = content.charAt(start);
+ if (!Character.isWhitespace(c)) {
+ hash = ((hash << 5) + hash) + (c & 0xff);
+ }
+ }
+ return hash;
+ }
+
+ };
+
+ public int hash(StringText seq, int line) {
+ final int begin = seq.lines.get(line + 1);
+ final int end = seq.lines.get(line + 2);
+ return hashRegion(seq.content, begin, end);
+ }
+
+ protected abstract int hashRegion(String content, int start, int end);
+
+ public static int trimTrailingWhitespace(String content, int start, int end) {
+ end--;
+ while (start <= end && Character.isWhitespace(content.charAt(end))) {
+ end--;
+ }
+ return end + 1;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.plugins.core.issue.tracking.HashedSequence;
+import org.sonar.plugins.core.issue.tracking.HashedSequenceComparator;
+import org.sonar.plugins.core.issue.tracking.StringText;
+import org.sonar.plugins.core.issue.tracking.StringTextComparator;
+
+public class ViolationTrackingBlocksRecognizer {
+
+ private final HashedSequence<StringText> a;
+ private final HashedSequence<StringText> b;
+ private final HashedSequenceComparator<StringText> cmp;
+
+ @VisibleForTesting
+ public ViolationTrackingBlocksRecognizer(String referenceSource, String source) {
+ this.a = HashedSequence.wrap(new StringText(referenceSource), StringTextComparator.IGNORE_WHITESPACE);
+ this.b = HashedSequence.wrap(new StringText(source), StringTextComparator.IGNORE_WHITESPACE);
+ this.cmp = new HashedSequenceComparator<StringText>(StringTextComparator.IGNORE_WHITESPACE);
+ }
+
+ public ViolationTrackingBlocksRecognizer(HashedSequence<StringText> a, HashedSequence<StringText> b, HashedSequenceComparator<StringText> cmp) {
+ this.a = a;
+ this.b = b;
+ this.cmp = cmp;
+ }
+
+ public boolean isValidLineInReference(Integer line) {
+ return (line != null) && (0 <= line - 1) && (line - 1 < a.length());
+ }
+
+ public boolean isValidLineInSource(Integer line) {
+ return (line != null) && (0 <= line - 1) && (line - 1 < b.length());
+ }
+
+ /**
+ * @param startA number of line from first version of text (numbering starts from 0)
+ * @param startB number of line from second version of text (numbering starts from 0)
+ */
+ public int computeLengthOfMaximalBlock(int startA, int startB) {
+ if (!cmp.equals(a, startA, b, startB)) {
+ return 0;
+ }
+ int length = 0;
+ int ai = startA;
+ int bi = startB;
+ while (ai < a.length() && bi < b.length() && cmp.equals(a, ai, b, bi)) {
+ ai++;
+ bi++;
+ length++;
+ }
+ ai = startA;
+ bi = startB;
+ while (ai >= 0 && bi >= 0 && cmp.equals(a, ai, b, bi)) {
+ ai--;
+ bi--;
+ length++;
+ }
+ // Note that position (startA, startB) was counted twice
+ return length - 1;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.plugins.core.issue.tracking;
+
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-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
- }
-
- /**
- * @param line line number (first line has number 1)
- * @return checksum or null if checksum not exists for line
- */
- public static String getChecksumForLine(List<String> checksums, Integer line) {
- if (line == null || line < 1 || line > checksums.size()) {
- return null;
- }
- return checksums.get(line - 1);
- }
-
- 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);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.sonar.plugins.core.timemachine.tracking.HashedSequence;
-import org.sonar.plugins.core.timemachine.tracking.HashedSequenceComparator;
-import org.sonar.plugins.core.timemachine.tracking.StringText;
-import org.sonar.plugins.core.timemachine.tracking.StringTextComparator;
-
-public class ViolationTrackingBlocksRecognizer {
-
- private final HashedSequence<StringText> a;
- private final HashedSequence<StringText> b;
- private final HashedSequenceComparator<StringText> cmp;
-
- @VisibleForTesting
- public ViolationTrackingBlocksRecognizer(String referenceSource, String source) {
- this.a = HashedSequence.wrap(new StringText(referenceSource), StringTextComparator.IGNORE_WHITESPACE);
- this.b = HashedSequence.wrap(new StringText(source), StringTextComparator.IGNORE_WHITESPACE);
- this.cmp = new HashedSequenceComparator<StringText>(StringTextComparator.IGNORE_WHITESPACE);
- }
-
- public ViolationTrackingBlocksRecognizer(HashedSequence<StringText> a, HashedSequence<StringText> b, HashedSequenceComparator<StringText> cmp) {
- this.a = a;
- this.b = b;
- this.cmp = cmp;
- }
-
- public boolean isValidLineInReference(Integer line) {
- return (line != null) && (0 <= line - 1) && (line - 1 < a.length());
- }
-
- public boolean isValidLineInSource(Integer line) {
- return (line != null) && (0 <= line - 1) && (line - 1 < b.length());
- }
-
- /**
- * @param startA number of line from first version of text (numbering starts from 0)
- * @param startB number of line from second version of text (numbering starts from 0)
- */
- public int computeLengthOfMaximalBlock(int startA, int startB) {
- if (!cmp.equals(a, startA, b, startB)) {
- return 0;
- }
- int length = 0;
- int ai = startA;
- int bi = startB;
- while (ai < a.length() && bi < b.length() && cmp.equals(a, ai, b, bi)) {
- ai++;
- bi++;
- length++;
- }
- ai = startA;
- bi = startB;
- while (ai >= 0 && bi >= 0 && cmp.equals(a, ai, b, bi)) {
- ai--;
- bi--;
- length++;
- }
- // Note that position (startA, startB) was counted twice
- return length - 1;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Wraps a {@link Sequence} to assign hash codes to elements.
- */
-public final class HashedSequence<S extends Sequence> implements Sequence {
-
- final S base;
- final int[] hashes;
-
- public static <S extends Sequence> HashedSequence<S> wrap(S base, SequenceComparator<S> cmp) {
- int size = base.length();
- int[] hashes = new int[size];
- for (int i = 0; i < size; i++) {
- hashes[i] = cmp.hash(base, i);
- }
- return new HashedSequence<S>(base, hashes);
- }
-
- private HashedSequence(S base, int[] hashes) {
- this.base = base;
- this.hashes = hashes;
- }
-
- public int length() {
- return base.length();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Wrap another {@link SequenceComparator} for use with {@link HashedSequence}.
- */
-public class HashedSequenceComparator<S extends Sequence> implements SequenceComparator<HashedSequence<S>> {
-
- private final SequenceComparator<? super S> cmp;
-
- public HashedSequenceComparator(SequenceComparator<? super S> cmp) {
- this.cmp = cmp;
- }
-
- public boolean equals(HashedSequence<S> a, int ai, HashedSequence<S> b, int bi) {
- if (a.hashes[ai] == b.hashes[bi]) {
- return cmp.equals(a.base, ai, b.base, bi);
- }
- return false;
- }
-
- public int hash(HashedSequence<S> seq, int i) {
- return seq.hashes[i];
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Wraps a {@link Sequence} to assign hash codes to elements.
- */
-public class RollingHashSequence<S extends Sequence> implements Sequence {
-
- final S base;
- final int[] hashes;
-
- public static <S extends Sequence> RollingHashSequence<S> wrap(S base, SequenceComparator<S> cmp, int lines) {
- int size = base.length();
- int[] hashes = new int[size];
-
- RollingHashCalculator hashCalulator = new RollingHashCalculator(lines * 2 + 1);
- for (int i = 0; i <= Math.min(size - 1, lines); i++) {
- hashCalulator.add(cmp.hash(base, i));
- }
- for (int i = 0; i < size; i++) {
- hashes[i] = hashCalulator.getHash();
- if (i - lines >= 0) {
- hashCalulator.remove(cmp.hash(base, i - lines));
- }
- if (i + lines + 1 < size) {
- hashCalulator.add(cmp.hash(base, i + lines + 1));
- } else {
- hashCalulator.add(0);
- }
- }
-
- return new RollingHashSequence<S>(base, hashes);
- }
-
- private RollingHashSequence(S base, int[] hashes) {
- this.base = base;
- this.hashes = hashes;
- }
-
- public int length() {
- return base.length();
- }
-
- private static class RollingHashCalculator {
-
- private static final int PRIME_BASE = 31;
-
- private final int power;
- private int hash;
-
- public RollingHashCalculator(int size) {
- int pow = 1;
- for (int i = 0; i < size - 1; i++) {
- pow = pow * PRIME_BASE;
- }
- this.power = pow;
- }
-
- public void add(int value) {
- hash = hash * PRIME_BASE + value;
- }
-
- public void remove(int value) {
- hash = hash - power * value;
- }
-
- public int getHash() {
- return hash;
- }
-
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Wrap another {@link SequenceComparator} for use with {@link RollingHashSequence}.
- */
-public class RollingHashSequenceComparator<S extends Sequence> implements SequenceComparator<RollingHashSequence<S>> {
-
- private final SequenceComparator<? super S> cmp;
-
- public RollingHashSequenceComparator(SequenceComparator<? super S> cmp) {
- this.cmp = cmp;
- }
-
- public boolean equals(RollingHashSequence<S> a, int ai, RollingHashSequence<S> b, int bi) {
- if (a.hashes[ai] == b.hashes[bi]) {
- return cmp.equals(a.base, ai, b.base, bi);
- }
- return false;
- }
-
- public int hash(RollingHashSequence<S> seq, int i) {
- return seq.hashes[i];
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Arbitrary sequence of elements.
- */
-public interface Sequence {
-
- /**
- * @return total number of items in the sequence
- */
- int length();
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Equivalence function for a {@link Sequence}.
- */
-public interface SequenceComparator<S extends Sequence> {
-
- /**
- * Compare two items to determine if they are equivalent.
- */
- boolean equals(S a, int ai, S b, int bi);
-
- /**
- * Get a hash value for an item in a sequence.
- *
- * If two items are equal according to this comparator's
- * {@link #equals(Sequence, int, Sequence, int)} method,
- * then this hash method must produce the same integer result for both items.
- * However not required to have different hash values for different items.
- */
- int hash(S seq, int i);
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-import com.google.common.collect.Lists;
-
-import java.util.List;
-
-/**
- * Text is a {@link Sequence} of lines.
- */
-public class StringText implements Sequence {
-
- final String content;
-
- /**
- * Map of line number to starting position within {@link #content}.
- */
- final List<Integer> lines;
-
- public StringText(String str) {
- this.content = str;
- this.lines = lineMap(content, 0, content.length());
- }
-
- public int length() {
- return lines.size() - 2;
- }
-
- private static List<Integer> lineMap(String buf, int ptr, int end) {
- List<Integer> lines = Lists.newArrayList();
- lines.add(Integer.MIN_VALUE);
- for (; ptr < end; ptr = nextLF(buf, ptr)) {
- lines.add(ptr);
- }
- lines.add(end);
- return lines;
- }
-
- private static int nextLF(String b, int ptr) {
- return next(b, ptr, '\n');
- }
-
- private static int next(final String b, int ptr, final char chrA) {
- final int sz = b.length();
- while (ptr < sz) {
- if (b.charAt(ptr++) == chrA) {
- return ptr;
- }
- }
- return ptr;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-/**
- * Equivalence function for {@link StringText}.
- */
-public abstract class StringTextComparator implements SequenceComparator<StringText> {
-
- /**
- * Ignores all whitespace.
- */
- public static final StringTextComparator IGNORE_WHITESPACE = new StringTextComparator() {
-
- public boolean equals(StringText a, int ai, StringText b, int bi) {
- ai++;
- bi++;
- int as = a.lines.get(ai);
- int bs = b.lines.get(bi);
- int ae = a.lines.get(ai + 1);
- int be = b.lines.get(bi + 1);
- ae = trimTrailingWhitespace(a.content, as, ae);
- be = trimTrailingWhitespace(b.content, bs, be);
- while ((as < ae) && (bs < be)) {
- char ac = a.content.charAt(as);
- char bc = b.content.charAt(bs);
- while ((as < ae - 1) && (Character.isWhitespace(ac))) {
- as++;
- ac = a.content.charAt(as);
- }
- while ((bs < be - 1) && (Character.isWhitespace(bc))) {
- bs++;
- bc = b.content.charAt(bs);
- }
- if (ac != bc) {
- return false;
- }
- as++;
- bs++;
- }
- return (as == ae) && (bs == be);
- }
-
- @Override
- protected int hashRegion(String content, int start, int end) {
- int hash = 5381;
- for (; start < end; start++) {
- char c = content.charAt(start);
- if (!Character.isWhitespace(c)) {
- hash = ((hash << 5) + hash) + (c & 0xff);
- }
- }
- return hash;
- }
-
- };
-
- public int hash(StringText seq, int line) {
- final int begin = seq.lines.get(line + 1);
- final int end = seq.lines.get(line + 2);
- return hashRegion(seq.content, begin, end);
- }
-
- protected abstract int hashRegion(String content, int start, int end);
-
- public static int trimTrailingWhitespace(String content, int start, int end) {
- end--;
- while (start <= end && Character.isWhitespace(content.charAt(end))) {
- end--;
- }
- return end + 1;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-@javax.annotation.ParametersAreNonnullByDefault
-package org.sonar.plugins.core.timemachine.tracking;
-
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import org.junit.Test;
+import org.sonar.plugins.core.issue.tracking.RollingHashSequence;
+import org.sonar.plugins.core.issue.tracking.RollingHashSequenceComparator;
+import org.sonar.plugins.core.issue.tracking.StringText;
+import org.sonar.plugins.core.issue.tracking.StringTextComparator;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RollingHashSequenceTest {
+
+ @Test
+ public void test_hash() {
+ StringText seq = new StringText("line0 \n line1 \n line2");
+ StringTextComparator cmp = StringTextComparator.IGNORE_WHITESPACE;
+ RollingHashSequence<StringText> seq2 = RollingHashSequence.wrap(seq, cmp, 1);
+ RollingHashSequenceComparator<StringText> cmp2 = new RollingHashSequenceComparator<StringText>(cmp);
+
+ assertThat(seq2.length()).isEqualTo(3);
+ assertThat(cmp2.hash(seq2, 0)).isEqualTo(cmp.hash(seq, 0) * 31 + cmp.hash(seq, 1));
+ assertThat(cmp2.hash(seq2, 1)).isEqualTo((cmp.hash(seq, 0) * 31 + cmp.hash(seq, 1)) * 31 + cmp.hash(seq, 2));
+ assertThat(cmp2.hash(seq2, 2)).isEqualTo((cmp.hash(seq, 1) * 31 + cmp.hash(seq, 2)) * 31);
+ }
+
+ @Test
+ public void test_equals() {
+ StringTextComparator baseCmp = StringTextComparator.IGNORE_WHITESPACE;
+ RollingHashSequence<StringText> a = RollingHashSequence.wrap(new StringText("line0 \n line1 \n line2"), baseCmp, 1);
+ RollingHashSequence<StringText> b = RollingHashSequence.wrap(new StringText("line0 \n line1 \n line2 \n line3"), baseCmp, 1);
+ RollingHashSequenceComparator<StringText> cmp = new RollingHashSequenceComparator<StringText>(baseCmp);
+
+ assertThat(cmp.equals(a, 0, b, 0)).isTrue();
+ assertThat(cmp.equals(a, 1, b, 1)).isTrue();
+ assertThat(cmp.equals(a, 2, b, 2)).isFalse();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import org.junit.Test;
+import org.sonar.plugins.core.issue.tracking.SourceChecksum;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class SourceChecksumTest {
+ @Test
+ public void shouldGetChecksumForLine() {
+ List<String> checksums = SourceChecksum.lineChecksumsOfFile("line");
+ assertThat(SourceChecksum.getChecksumForLine(checksums, null)).isNull();
+ assertThat(SourceChecksum.getChecksumForLine(checksums, 0)).isNull();
+ assertThat(SourceChecksum.getChecksumForLine(checksums, 1)).isNotNull();
+ assertThat(SourceChecksum.getChecksumForLine(checksums, 2)).isNull();
+ }
+
+ /**
+ * See http://jira.codehaus.org/browse/SONAR-2358
+ */
+ @Test
+ public void shouldGenerateCorrectChecksums() {
+ List<String> encoding = SourceChecksum.lineChecksumsOfFile("Привет Мир");
+ assertThat(encoding).hasSize(1);
+ assertThat(encoding.get(0)).isEqualTo("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).hasSize(2);
+ assertThat(crlf.get(0)).isNotEqualTo(crlf.get(1));
+ assertThat(lf).isEqualTo(crlf);
+ assertThat(cr).isEqualTo(crlf);
+
+ assertThat(SourceChecksum.lineChecksum("\tvoid method() {\n")).isEqualTo(SourceChecksum.lineChecksum(" void method() {"));
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import org.junit.Test;
+import org.sonar.plugins.core.issue.tracking.StringText;
+import org.sonar.plugins.core.issue.tracking.StringTextComparator;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+
+public class StringTextComparatorTest {
+
+ @Test
+ public void testEquals() {
+ StringTextComparator cmp = StringTextComparator.IGNORE_WHITESPACE;
+
+ StringText a = new StringText("abc\nabc\na bc");
+ StringText b = new StringText("abc\nabc d\nab c");
+
+ assertThat(cmp.equals(a, 0, b, 0)).as("abc == abc").isTrue();
+ assertThat(cmp.equals(a, 1, b, 1)).as("abc != abc d").isFalse();
+ assertThat(cmp.equals(a, 2, b, 2)).as("a bc == ab c").isTrue();
+ assertThat(cmp.hash(a, 0)).isEqualTo(cmp.hash(b, 0));
+ assertThat(cmp.hash(a, 2)).isEqualTo(cmp.hash(b, 2));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import org.junit.Test;
+import org.sonar.plugins.core.issue.tracking.StringText;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class StringTextTest {
+
+ @Test
+ public void testEmpty() {
+ StringText r = new StringText("");
+ assertThat(r.length()).isEqualTo(0);
+ }
+
+ @Test
+ public void testTwoLines() {
+ StringText r = new StringText("a\nb");
+ assertThat(r.length()).isEqualTo(2);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.core.issue.tracking;
+
+import org.junit.Test;
+import org.sonar.plugins.core.issue.tracking.ViolationTrackingBlocksRecognizer;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ViolationTrackingBlocksRecognizerTest {
+
+ @Test
+ public void test() {
+ assertThat(compute(t("abcde"), t("abcde"), 3, 3)).isEqualTo(5);
+ assertThat(compute(t("abcde"), t("abcd"), 3, 3)).isEqualTo(4);
+ assertThat(compute(t("bcde"), t("abcde"), 3, 3)).isEqualTo(0);
+ assertThat(compute(t("bcde"), t("abcde"), 2, 3)).isEqualTo(4);
+ }
+
+ private static int compute(String a, String b, int ai, int bi) {
+ ViolationTrackingBlocksRecognizer rec = new ViolationTrackingBlocksRecognizer(a, b);
+ return rec.computeLengthOfMaximalBlock(ai, bi);
+ }
+
+ private static String t(String text) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < text.length(); i++) {
+ sb.append(text.charAt(i)).append('\n');
+ }
+ return sb.toString();
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine;
-
-import org.junit.Test;
-
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class SourceChecksumTest {
- @Test
- public void shouldGetChecksumForLine() {
- List<String> checksums = SourceChecksum.lineChecksumsOfFile("line");
- assertThat(SourceChecksum.getChecksumForLine(checksums, null)).isNull();
- assertThat(SourceChecksum.getChecksumForLine(checksums, 0)).isNull();
- assertThat(SourceChecksum.getChecksumForLine(checksums, 1)).isNotNull();
- assertThat(SourceChecksum.getChecksumForLine(checksums, 2)).isNull();
- }
-
- /**
- * See http://jira.codehaus.org/browse/SONAR-2358
- */
- @Test
- public void shouldGenerateCorrectChecksums() {
- List<String> encoding = SourceChecksum.lineChecksumsOfFile("Привет Мир");
- assertThat(encoding).hasSize(1);
- assertThat(encoding.get(0)).isEqualTo("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).hasSize(2);
- assertThat(crlf.get(0)).isNotEqualTo(crlf.get(1));
- assertThat(lf).isEqualTo(crlf);
- assertThat(cr).isEqualTo(crlf);
-
- assertThat(SourceChecksum.lineChecksum("\tvoid method() {\n")).isEqualTo(SourceChecksum.lineChecksum(" void method() {"));
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class ViolationTrackingBlocksRecognizerTest {
-
- @Test
- public void test() {
- assertThat(compute(t("abcde"), t("abcde"), 3, 3)).isEqualTo(5);
- assertThat(compute(t("abcde"), t("abcd"), 3, 3)).isEqualTo(4);
- assertThat(compute(t("bcde"), t("abcde"), 3, 3)).isEqualTo(0);
- assertThat(compute(t("bcde"), t("abcde"), 2, 3)).isEqualTo(4);
- }
-
- private static int compute(String a, String b, int ai, int bi) {
- ViolationTrackingBlocksRecognizer rec = new ViolationTrackingBlocksRecognizer(a, b);
- return rec.computeLengthOfMaximalBlock(ai, bi);
- }
-
- private static String t(String text) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < text.length(); i++) {
- sb.append(text.charAt(i)).append('\n');
- }
- return sb.toString();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RollingHashSequenceTest {
-
- @Test
- public void test_hash() {
- StringText seq = new StringText("line0 \n line1 \n line2");
- StringTextComparator cmp = StringTextComparator.IGNORE_WHITESPACE;
- RollingHashSequence<StringText> seq2 = RollingHashSequence.wrap(seq, cmp, 1);
- RollingHashSequenceComparator<StringText> cmp2 = new RollingHashSequenceComparator<StringText>(cmp);
-
- assertThat(seq2.length()).isEqualTo(3);
- assertThat(cmp2.hash(seq2, 0)).isEqualTo(cmp.hash(seq, 0) * 31 + cmp.hash(seq, 1));
- assertThat(cmp2.hash(seq2, 1)).isEqualTo((cmp.hash(seq, 0) * 31 + cmp.hash(seq, 1)) * 31 + cmp.hash(seq, 2));
- assertThat(cmp2.hash(seq2, 2)).isEqualTo((cmp.hash(seq, 1) * 31 + cmp.hash(seq, 2)) * 31);
- }
-
- @Test
- public void test_equals() {
- StringTextComparator baseCmp = StringTextComparator.IGNORE_WHITESPACE;
- RollingHashSequence<StringText> a = RollingHashSequence.wrap(new StringText("line0 \n line1 \n line2"), baseCmp, 1);
- RollingHashSequence<StringText> b = RollingHashSequence.wrap(new StringText("line0 \n line1 \n line2 \n line3"), baseCmp, 1);
- RollingHashSequenceComparator<StringText> cmp = new RollingHashSequenceComparator<StringText>(baseCmp);
-
- assertThat(cmp.equals(a, 0, b, 0)).isTrue();
- assertThat(cmp.equals(a, 1, b, 1)).isTrue();
- assertThat(cmp.equals(a, 2, b, 2)).isFalse();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-
-public class StringTextComparatorTest {
-
- @Test
- public void testEquals() {
- StringTextComparator cmp = StringTextComparator.IGNORE_WHITESPACE;
-
- StringText a = new StringText("abc\nabc\na bc");
- StringText b = new StringText("abc\nabc d\nab c");
-
- assertThat(cmp.equals(a, 0, b, 0)).as("abc == abc").isTrue();
- assertThat(cmp.equals(a, 1, b, 1)).as("abc != abc d").isFalse();
- assertThat(cmp.equals(a, 2, b, 2)).as("a bc == ab c").isTrue();
- assertThat(cmp.hash(a, 0)).isEqualTo(cmp.hash(b, 0));
- assertThat(cmp.hash(a, 2)).isEqualTo(cmp.hash(b, 2));
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.core.timemachine.tracking;
-
-import org.junit.Test;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class StringTextTest {
-
- @Test
- public void testEmpty() {
- StringText r = new StringText("");
- assertThat(r.length()).isEqualTo(0);
- }
-
- @Test
- public void testTwoLines() {
- StringText r = new StringText("a\nb");
- assertThat(r.length()).isEqualTo(2);
- }
-
-}
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.PersistenceManager;
import org.sonar.batch.index.ScanPersister;
-import org.sonar.batch.report.SonarReport;
+import org.sonar.batch.scan.JsonReport;
import org.sonar.batch.scan.filesystem.FileSystemLogger;
import org.sonar.batch.scan.maven.MavenPhaseExecutor;
import org.sonar.batch.scan.maven.MavenPluginsConfigurator;
private ProjectInitializer pi;
private ScanPersister[] persisters;
private FileSystemLogger fsLogger;
- private final SonarReport sonarReport;
+ private final JsonReport jsonReport;
public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
- ScanPersister[] persisters, FileSystemLogger fsLogger, SonarReport sonarReport) {
+ ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
this.phases = phases;
this.decoratorsExecutor = decoratorsExecutor;
this.mavenPhaseExecutor = mavenPhaseExecutor;
this.pi = pi;
this.persisters = persisters;
this.fsLogger = fsLogger;
- this.sonarReport = sonarReport;
+ this.jsonReport = jsonReport;
}
public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, ProjectInitializer pi, ScanPersister[] persisters, FileSystemLogger fsLogger, SonarReport sonarReport) {
+ EventBus eventBus, ProjectInitializer pi, ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
this(phases, decoratorsExecutor, mavenPhaseExecutor, mavenPluginsConfigurator, initializersExecutor, postJobsExecutor,
- sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, persisters, fsLogger, sonarReport);
+ sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, persisters, fsLogger, jsonReport);
}
/**
persistenceManager.setDelayedMode(false);
if (module.isRoot()) {
- sonarReport.execute();
+ jsonReport.execute();
LOGGER.info("Store results in database");
for (ScanPersister persister : persisters) {
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.sonar.batch.report;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.io.Closeables;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.config.Settings;
-import org.sonar.api.platform.Server;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.SonarException;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.issue.ScanIssues;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.issue.DefaultIssue;
-
-import java.io.*;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Set;
-
-import static com.google.common.collect.Sets.newHashSet;
-
-/**
- * @since 3.6
- */
-
-public class SonarReport implements BatchComponent {
-
- private static final Logger LOG = LoggerFactory.getLogger(SonarReport.class);
- private final Settings settings;
- private final ModuleFileSystem fileSystem;
- private final Server server;
- private final RuleI18nManager ruleI18nManager;
- private final IssueCache issueCache;
-
- public SonarReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleI18nManager ruleI18nManager, IssueCache issueCache) {
- this.settings = settings;
- this.fileSystem = fileSystem;
- this.server = server;
- this.ruleI18nManager = ruleI18nManager;
- this.issueCache = issueCache;
- }
-
- public void execute() {
- if (settings.getBoolean(CoreProperties.DRY_RUN)) {
- exportResults();
- }
- }
-
- private void exportResults() {
- File exportFile = new File(fileSystem.workingDir(), settings.getString("sonar.report.export.path"));
-
- LOG.info("Exporting report results to " + exportFile.getAbsolutePath());
- Writer output = null;
- try {
- output = new BufferedWriter(new FileWriter(exportFile));
- createJson().writeJSONString(output);
- } catch (IOException e) {
- throw new SonarException("Unable to write report results in file " + exportFile.getAbsolutePath(), e);
- } finally {
- Closeables.closeQuietly(output);
- }
- }
-
- @VisibleForTesting
- JSONObject createJson(){
- Set<RuleKey> ruleKeyList = newHashSet();
- Set<String> componentKeyList = newHashSet();
-
- JSONObject json = new JSONObject();
- put(json, "version", server.getVersion());
-
- addIssues(json, ruleKeyList, componentKeyList);
- addComponents(json, componentKeyList);
- addRules(json, ruleKeyList);
- return json;
- }
-
- private void addIssues(JSONObject root, Collection<RuleKey> ruleKeyList, Collection<String> componentKeyList) {
- JSONArray json = new JSONArray();
- for (DefaultIssue issue : getIssues()) {
- JSONObject jsonIssue = new JSONObject();
- put(jsonIssue, "key", issue.key());
- put(jsonIssue, "component", issue.componentKey());
- put(jsonIssue, "line", issue.line());
- put(jsonIssue, "message", issue.message());
- put(jsonIssue, "severity", issue.severity());
- put(jsonIssue, "rule", issue.ruleKey());
- put(jsonIssue, "status", issue.status());
- put(jsonIssue, "resolution", issue.resolution());
- put(jsonIssue, "isNew", issue.isNew());
- put(jsonIssue, "reporter", issue.reporter());
- put(jsonIssue, "assignee", issue.assignee());
- put(jsonIssue, "effortToFix", issue.effortToFix());
- put(jsonIssue, "creationDate", issue.creationDate());
- put(jsonIssue, "updateDate", issue.updateDate());
- put(jsonIssue, "closeDate", issue.closeDate());
- json.add(jsonIssue);
-
- componentKeyList.add(issue.componentKey());
- ruleKeyList.add(issue.ruleKey());
- }
- root.put("issues", json);
- }
-
- private void addComponents(JSONObject root, Collection<String> componentKeyList) {
- JSONArray json = new JSONArray();
- for (String componentKey : componentKeyList) {
- JSONObject jsonComponent = new JSONObject();
- // TODO add module key
- put(jsonComponent, "key", componentKey);
- json.add(jsonComponent);
- }
- root.put("components", json);
- }
-
- private void addRules(JSONObject root, Collection<RuleKey> ruleKeyList) {
- JSONArray json = new JSONArray();
- for (RuleKey ruleKey : ruleKeyList) {
- JSONObject jsonRuleKey = new JSONObject();
- put(jsonRuleKey, "key", ruleKey);
- put(jsonRuleKey, "rule", ruleKey.rule());
- put(jsonRuleKey, "repository", ruleKey.repository());
- put(jsonRuleKey, "name", getRuleName(ruleKey));
- json.add(jsonRuleKey);
- }
- root.put("rules", json);
- }
-
- private void put(JSONObject json, String key, Object value) {
- if (value != null) {
- json.put(key, value);
- }
- }
-
- private void put(JSONObject json, String key, RuleKey ruleKey) {
- if (ruleKey != null) {
- json.put(key, ruleKey.toString());
- }
- }
-
- private void put(JSONObject json, String key, Date date) {
- if (date != null) {
- json.put(key, DateUtils.formatDateTime(date));
- }
- }
-
- private String getRuleName(RuleKey ruleKey) {
- return ruleI18nManager.getName(ruleKey.repository(), ruleKey.rule(), Locale.getDefault());
- }
-
- @VisibleForTesting
- Collection<DefaultIssue> getIssues() {
- return issueCache.all();
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.batch.scan;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.io.Closeables;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.platform.Server;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.issue.DefaultIssue;
+
+import java.io.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Set;
+
+import static com.google.common.collect.Sets.newHashSet;
+
+/**
+ * @since 3.6
+ */
+
+public class JsonReport implements BatchComponent {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JsonReport.class);
+ private final Settings settings;
+ private final ModuleFileSystem fileSystem;
+ private final Server server;
+ private final RuleI18nManager ruleI18nManager;
+ private final IssueCache issueCache;
+
+ public JsonReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleI18nManager ruleI18nManager, IssueCache issueCache) {
+ this.settings = settings;
+ this.fileSystem = fileSystem;
+ this.server = server;
+ this.ruleI18nManager = ruleI18nManager;
+ this.issueCache = issueCache;
+ }
+
+ public void execute() {
+ if (settings.getBoolean(CoreProperties.DRY_RUN)) {
+ exportResults();
+ }
+ }
+
+ private void exportResults() {
+ File exportFile = new File(fileSystem.workingDir(), settings.getString("sonar.report.export.path"));
+
+ LOG.info("Exporting report results to " + exportFile.getAbsolutePath());
+ Writer output = null;
+ try {
+ output = new BufferedWriter(new FileWriter(exportFile));
+ createJson().writeJSONString(output);
+ } catch (IOException e) {
+ throw new SonarException("Unable to write report results in file " + exportFile.getAbsolutePath(), e);
+ } finally {
+ Closeables.closeQuietly(output);
+ }
+ }
+
+ @VisibleForTesting
+ JSONObject createJson(){
+ Set<RuleKey> ruleKeyList = newHashSet();
+ Set<String> componentKeyList = newHashSet();
+
+ JSONObject json = new JSONObject();
+ put(json, "version", server.getVersion());
+
+ addIssues(json, ruleKeyList, componentKeyList);
+ addComponents(json, componentKeyList);
+ addRules(json, ruleKeyList);
+ return json;
+ }
+
+ private void addIssues(JSONObject root, Collection<RuleKey> ruleKeyList, Collection<String> componentKeyList) {
+ JSONArray json = new JSONArray();
+ for (DefaultIssue issue : getIssues()) {
+ JSONObject jsonIssue = new JSONObject();
+ put(jsonIssue, "key", issue.key());
+ put(jsonIssue, "component", issue.componentKey());
+ put(jsonIssue, "line", issue.line());
+ put(jsonIssue, "message", issue.message());
+ put(jsonIssue, "severity", issue.severity());
+ put(jsonIssue, "rule", issue.ruleKey());
+ put(jsonIssue, "status", issue.status());
+ put(jsonIssue, "resolution", issue.resolution());
+ put(jsonIssue, "isNew", issue.isNew());
+ put(jsonIssue, "reporter", issue.reporter());
+ put(jsonIssue, "assignee", issue.assignee());
+ put(jsonIssue, "effortToFix", issue.effortToFix());
+ put(jsonIssue, "creationDate", issue.creationDate());
+ put(jsonIssue, "updateDate", issue.updateDate());
+ put(jsonIssue, "closeDate", issue.closeDate());
+ json.add(jsonIssue);
+
+ componentKeyList.add(issue.componentKey());
+ ruleKeyList.add(issue.ruleKey());
+ }
+ root.put("issues", json);
+ }
+
+ private void addComponents(JSONObject root, Collection<String> componentKeyList) {
+ JSONArray json = new JSONArray();
+ for (String componentKey : componentKeyList) {
+ JSONObject jsonComponent = new JSONObject();
+ // TODO add module key
+ put(jsonComponent, "key", componentKey);
+ json.add(jsonComponent);
+ }
+ root.put("components", json);
+ }
+
+ private void addRules(JSONObject root, Collection<RuleKey> ruleKeyList) {
+ JSONArray json = new JSONArray();
+ for (RuleKey ruleKey : ruleKeyList) {
+ JSONObject jsonRuleKey = new JSONObject();
+ put(jsonRuleKey, "key", ruleKey);
+ put(jsonRuleKey, "rule", ruleKey.rule());
+ put(jsonRuleKey, "repository", ruleKey.repository());
+ put(jsonRuleKey, "name", getRuleName(ruleKey));
+ json.add(jsonRuleKey);
+ }
+ root.put("rules", json);
+ }
+
+ private void put(JSONObject json, String key, Object value) {
+ if (value != null) {
+ json.put(key, value);
+ }
+ }
+
+ private void put(JSONObject json, String key, RuleKey ruleKey) {
+ if (ruleKey != null) {
+ json.put(key, ruleKey.toString());
+ }
+ }
+
+ private void put(JSONObject json, String key, Date date) {
+ if (date != null) {
+ json.put(key, DateUtils.formatDateTime(date));
+ }
+ }
+
+ private String getRuleName(RuleKey ruleKey) {
+ return ruleI18nManager.getName(ruleKey.repository(), ruleKey.rule(), Locale.getDefault());
+ }
+
+ @VisibleForTesting
+ Collection<DefaultIssue> getIssues() {
+ return issueCache.all();
+ }
+}
import org.sonar.batch.local.DryRunExporter;
import org.sonar.batch.phases.PhaseExecutor;
import org.sonar.batch.phases.PhasesTimeProfiler;
-import org.sonar.batch.report.SonarReport;
import org.sonar.batch.scan.filesystem.*;
import org.sonar.core.component.ScanPerspectives;
ViolationFilters.class,
ResourceFilters.class,
DryRunExporter.class,
- SonarReport.class,
+ JsonReport.class,
new ProfileProvider(),
// issues
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.sonar.batch.report;
-
-import com.google.common.collect.Lists;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.platform.Server;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.issue.DefaultIssue;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Locale;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class SonarReportTest {
-
- @org.junit.Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
- SonarReport sonarReport;
- Resource resource = mock(Resource.class);
- ModuleFileSystem fileSystem = mock(ModuleFileSystem.class);
- Server server = mock(Server.class);
- RuleI18nManager ruleI18nManager = mock(RuleI18nManager.class);
- Settings settings;
- IssueCache issueCache = mock(IssueCache.class);
-
- @Before
- public void before() {
- when(resource.getEffectiveKey()).thenReturn("Action.java");
- when(server.getVersion()).thenReturn("3.6");
-
- settings = new Settings();
- settings.setProperty(CoreProperties.DRY_RUN, true);
- sonarReport = new SonarReport(settings, fileSystem, server, ruleI18nManager, issueCache);
- }
-
- @Test
- public void should_export_json() {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("Action.java")
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
- .setNew(false);
-
- when(sonarReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
-
- JSONObject json = sonarReport.createJson();
- assertThat(json.values()).hasSize(4);
-
- assertThat(json.get("version")).isEqualTo("3.6");
-
- assertThat(json.get("components")).isNotNull();
- JSONArray components = (JSONArray) json.get("components");
- assertThat(components).hasSize(1);
-
- assertThat(json.get("issues")).isNotNull();
- JSONArray issues = (JSONArray) json.get("issues");
- assertThat(issues).hasSize(1);
-
- assertThat(json.get("rules")).isNotNull();
- JSONArray rules = (JSONArray) json.get("rules");
- assertThat(rules).hasSize(1);
- }
-
- @Test
- public void should_export_components() {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("Action.java")
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
- .setNew(false);
-
- when(sonarReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
-
- JSONObject json = sonarReport.createJson();
- assertThat(json.get("version")).isEqualTo("3.6");
-
- assertThat(json.get("components")).isNotNull();
- JSONArray components = (JSONArray) json.get("components");
- assertThat(components).hasSize(1);
- JSONObject jsonComponent = (JSONObject) components.get(0);
- assertThat(jsonComponent.values()).hasSize(1);
- assertThat(jsonComponent.get("key")).isEqualTo("Action.java");
- }
-
- @Test
- public void should_export_issues() {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("Action.java")
- .setMessage("SystemPrintln")
- .setSeverity("MINOR")
- .setStatus(Issue.STATUS_CLOSED)
- .setResolution(Issue.RESOLUTION_FALSE_POSITIVE)
- .setLine(1)
- .setEffortToFix(3.14)
- .setReporter("julien")
- .setAssignee("simon")
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
- .setCreationDate(DateUtils.parseDate("2013-04-24"))
- .setUpdateDate(DateUtils.parseDate("2013-04-25"))
- .setCloseDate(DateUtils.parseDate("2013-04-26"))
- .setNew(false);
-
- when(sonarReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
-
- JSONObject json = sonarReport.createJson();
- assertThat(json.get("issues")).isNotNull();
- JSONArray issues = (JSONArray) json.get("issues");
- assertThat(issues).hasSize(1);
- JSONObject jsonIssue = (JSONObject) issues.get(0);
- assertThat(jsonIssue.values()).hasSize(15);
-
- assertThat(jsonIssue.get("key")).isEqualTo("200");
- assertThat(jsonIssue.get("component")).isEqualTo("Action.java");
- assertThat(jsonIssue.get("line")).isEqualTo(1);
- assertThat(jsonIssue.get("message")).isEqualTo("SystemPrintln");
- assertThat(jsonIssue.get("severity")).isEqualTo("MINOR");
- assertThat(jsonIssue.get("rule")).isEqualTo("squid:AvoidCycle");
- assertThat(jsonIssue.get("status")).isEqualTo("CLOSED");
- assertThat(jsonIssue.get("resolution")).isEqualTo("FALSE-POSITIVE");
- assertThat(jsonIssue.get("assignee")).isEqualTo("simon");
- assertThat(jsonIssue.get("effortToFix")).isEqualTo(3.14);
- assertThat(jsonIssue.get("reporter")).isEqualTo("julien");
- assertThat(jsonIssue.get("isNew")).isEqualTo(false);
- assertThat((String) jsonIssue.get("creationDate")).contains("2013-04-24T00:00");
- assertThat((String) jsonIssue.get("updateDate")).contains("2013-04-25T00:00");
- assertThat((String) jsonIssue.get("closeDate")).contains("2013-04-26T00:00");
- }
-
- @Test
- public void should_export_rules() {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("Action.java")
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"));
-
- when(ruleI18nManager.getName("squid", "AvoidCycle", Locale.getDefault())).thenReturn("Avoid Cycle");
- when(sonarReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
-
- JSONObject root = sonarReport.createJson();
-
- assertThat(root.get("rules")).isNotNull();
- JSONArray rules = (JSONArray) root.get("rules");
- assertThat(rules).hasSize(1);
- JSONObject json = (JSONObject) rules.get(0);
- assertThat(json.values()).hasSize(4);
-
- assertThat(json.get("key")).isEqualTo("squid:AvoidCycle");
- assertThat(json.get("rule")).isEqualTo("AvoidCycle");
- assertThat(json.get("repository")).isEqualTo("squid");
- assertThat(json.get("name")).isEqualTo("Avoid Cycle");
- }
-
- @Test
- public void should_export_issues_with_no_line() {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("Action.java")
- .setLine(null)
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"));
-
- when(sonarReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
-
- JSONObject json = sonarReport.createJson();
- assertThat(json.get("issues")).isNotNull();
-
- JSONArray issues = (JSONArray) json.get("issues");
- JSONObject jsonIssue = (JSONObject) issues.get(0);
- assertThat(jsonIssue.get("key")).isEqualTo("200");
- assertThat(jsonIssue.containsKey("line")).isFalse();
- }
-
- @Test
- public void should_ignore_resources_without_issue() {
- when(sonarReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
-
- JSONObject json = sonarReport.createJson();
- assertThat(json.get("version")).isEqualTo("3.6");
-
- assertThat(json.get("components")).isNotNull();
- JSONArray components = (JSONArray) json.get("components");
- assertThat(components).isEmpty();
-
- assertThat(json.get("issues")).isNotNull();
- JSONArray issues = (JSONArray) json.get("issues");
- assertThat(issues).isEmpty();
- }
-
- @Test
- public void should_export_issues_to_file() throws IOException {
- File sonarDirectory = temporaryFolder.newFolder("sonar");
-
- Rule rule = Rule.create("squid", "AvoidCycle");
- when(ruleI18nManager.getName(rule, Locale.getDefault())).thenReturn("Avoid Cycle");
- when(sonarReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
-
- settings.setProperty("sonar.report.export.path", "output.json");
- when(fileSystem.workingDir()).thenReturn(sonarDirectory);
-
- sonarReport.execute();
-
- assertThat(new File(sonarDirectory, "output.json")).exists();
- }
-
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.batch.scan;
+
+import com.google.common.collect.Lists;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.platform.Server;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.scan.JsonReport;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.issue.DefaultIssue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JsonReportTest {
+
+ @org.junit.Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ JsonReport jsonReport;
+ Resource resource = mock(Resource.class);
+ ModuleFileSystem fileSystem = mock(ModuleFileSystem.class);
+ Server server = mock(Server.class);
+ RuleI18nManager ruleI18nManager = mock(RuleI18nManager.class);
+ Settings settings;
+ IssueCache issueCache = mock(IssueCache.class);
+
+ @Before
+ public void before() {
+ when(resource.getEffectiveKey()).thenReturn("Action.java");
+ when(server.getVersion()).thenReturn("3.6");
+
+ settings = new Settings();
+ settings.setProperty(CoreProperties.DRY_RUN, true);
+ jsonReport = new JsonReport(settings, fileSystem, server, ruleI18nManager, issueCache);
+ }
+
+ @Test
+ public void should_export_json() {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("Action.java")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+ .setNew(false);
+
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+
+ JSONObject json = jsonReport.createJson();
+ assertThat(json.values()).hasSize(4);
+
+ assertThat(json.get("version")).isEqualTo("3.6");
+
+ assertThat(json.get("components")).isNotNull();
+ JSONArray components = (JSONArray) json.get("components");
+ assertThat(components).hasSize(1);
+
+ assertThat(json.get("issues")).isNotNull();
+ JSONArray issues = (JSONArray) json.get("issues");
+ assertThat(issues).hasSize(1);
+
+ assertThat(json.get("rules")).isNotNull();
+ JSONArray rules = (JSONArray) json.get("rules");
+ assertThat(rules).hasSize(1);
+ }
+
+ @Test
+ public void should_export_components() {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("Action.java")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+ .setNew(false);
+
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+
+ JSONObject json = jsonReport.createJson();
+ assertThat(json.get("version")).isEqualTo("3.6");
+
+ assertThat(json.get("components")).isNotNull();
+ JSONArray components = (JSONArray) json.get("components");
+ assertThat(components).hasSize(1);
+ JSONObject jsonComponent = (JSONObject) components.get(0);
+ assertThat(jsonComponent.values()).hasSize(1);
+ assertThat(jsonComponent.get("key")).isEqualTo("Action.java");
+ }
+
+ @Test
+ public void should_export_issues() {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("Action.java")
+ .setMessage("SystemPrintln")
+ .setSeverity("MINOR")
+ .setStatus(Issue.STATUS_CLOSED)
+ .setResolution(Issue.RESOLUTION_FALSE_POSITIVE)
+ .setLine(1)
+ .setEffortToFix(3.14)
+ .setReporter("julien")
+ .setAssignee("simon")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+ .setCreationDate(DateUtils.parseDate("2013-04-24"))
+ .setUpdateDate(DateUtils.parseDate("2013-04-25"))
+ .setCloseDate(DateUtils.parseDate("2013-04-26"))
+ .setNew(false);
+
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+
+ JSONObject json = jsonReport.createJson();
+ assertThat(json.get("issues")).isNotNull();
+ JSONArray issues = (JSONArray) json.get("issues");
+ assertThat(issues).hasSize(1);
+ JSONObject jsonIssue = (JSONObject) issues.get(0);
+ assertThat(jsonIssue.values()).hasSize(15);
+
+ assertThat(jsonIssue.get("key")).isEqualTo("200");
+ assertThat(jsonIssue.get("component")).isEqualTo("Action.java");
+ assertThat(jsonIssue.get("line")).isEqualTo(1);
+ assertThat(jsonIssue.get("message")).isEqualTo("SystemPrintln");
+ assertThat(jsonIssue.get("severity")).isEqualTo("MINOR");
+ assertThat(jsonIssue.get("rule")).isEqualTo("squid:AvoidCycle");
+ assertThat(jsonIssue.get("status")).isEqualTo("CLOSED");
+ assertThat(jsonIssue.get("resolution")).isEqualTo("FALSE-POSITIVE");
+ assertThat(jsonIssue.get("assignee")).isEqualTo("simon");
+ assertThat(jsonIssue.get("effortToFix")).isEqualTo(3.14);
+ assertThat(jsonIssue.get("reporter")).isEqualTo("julien");
+ assertThat(jsonIssue.get("isNew")).isEqualTo(false);
+ assertThat((String) jsonIssue.get("creationDate")).contains("2013-04-24T00:00");
+ assertThat((String) jsonIssue.get("updateDate")).contains("2013-04-25T00:00");
+ assertThat((String) jsonIssue.get("closeDate")).contains("2013-04-26T00:00");
+ }
+
+ @Test
+ public void should_export_rules() {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("Action.java")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"));
+
+ when(ruleI18nManager.getName("squid", "AvoidCycle", Locale.getDefault())).thenReturn("Avoid Cycle");
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+
+ JSONObject root = jsonReport.createJson();
+
+ assertThat(root.get("rules")).isNotNull();
+ JSONArray rules = (JSONArray) root.get("rules");
+ assertThat(rules).hasSize(1);
+ JSONObject json = (JSONObject) rules.get(0);
+ assertThat(json.values()).hasSize(4);
+
+ assertThat(json.get("key")).isEqualTo("squid:AvoidCycle");
+ assertThat(json.get("rule")).isEqualTo("AvoidCycle");
+ assertThat(json.get("repository")).isEqualTo("squid");
+ assertThat(json.get("name")).isEqualTo("Avoid Cycle");
+ }
+
+ @Test
+ public void should_export_issues_with_no_line() {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("Action.java")
+ .setLine(null)
+ .setRuleKey(RuleKey.of("squid", "AvoidCycle"));
+
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+
+ JSONObject json = jsonReport.createJson();
+ assertThat(json.get("issues")).isNotNull();
+
+ JSONArray issues = (JSONArray) json.get("issues");
+ JSONObject jsonIssue = (JSONObject) issues.get(0);
+ assertThat(jsonIssue.get("key")).isEqualTo("200");
+ assertThat(jsonIssue.containsKey("line")).isFalse();
+ }
+
+ @Test
+ public void should_ignore_resources_without_issue() {
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+
+ JSONObject json = jsonReport.createJson();
+ assertThat(json.get("version")).isEqualTo("3.6");
+
+ assertThat(json.get("components")).isNotNull();
+ JSONArray components = (JSONArray) json.get("components");
+ assertThat(components).isEmpty();
+
+ assertThat(json.get("issues")).isNotNull();
+ JSONArray issues = (JSONArray) json.get("issues");
+ assertThat(issues).isEmpty();
+ }
+
+ @Test
+ public void should_export_issues_to_file() throws IOException {
+ File sonarDirectory = temporaryFolder.newFolder("sonar");
+
+ Rule rule = Rule.create("squid", "AvoidCycle");
+ when(ruleI18nManager.getName(rule, Locale.getDefault())).thenReturn("Avoid Cycle");
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+
+ settings.setProperty("sonar.report.export.path", "output.json");
+ when(fileSystem.workingDir()).thenReturn(sonarDirectory);
+
+ jsonReport.execute();
+
+ assertThat(new File(sonarDirectory, "output.json")).exists();
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.review;
-
-import com.google.common.base.Preconditions;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-
-import javax.annotation.Nullable;
-import java.util.Date;
-
-/**
- * @since 2.13
- */
-public final class ReviewDto {
-
- public static final String STATUS_OPEN = "OPEN";
- public static final String STATUS_REOPENED = "REOPENED";
- public static final String STATUS_RESOLVED = "RESOLVED";
- public static final String STATUS_CLOSED = "CLOSED";
-
- public static final String RESOLUTION_FALSE_POSITIVE = "FALSE-POSITIVE";
- public static final String RESOLUTION_FIXED = "FIXED";
-
- private Long id;
- private Integer userId;
- private Long assigneeId;
- private String title;
- private String status;
- private String resolution;
- private Integer violationPermanentId;
- private Integer projectId;
- private Integer resourceId;
- private Integer line;
- private Date createdAt;
- private Date updatedAt;
- private String severity;
- private Integer ruleId;
- private boolean manualViolation;
- private boolean manualSeverity;
- private Integer actionPlanId;
- private String data;
-
- public Long getId() {
- return id;
- }
-
- public ReviewDto setId(Long id) {
- this.id = id;
- return this;
- }
-
- public Integer getUserId() {
- return userId;
- }
-
- public ReviewDto setUserId(Integer userId) {
- this.userId = userId;
- return this;
- }
-
- public Long getAssigneeId() {
- return assigneeId;
- }
-
- public ReviewDto setAssigneeId(@Nullable Long assigneeId) {
- this.assigneeId = assigneeId;
- return this;
- }
-
- public String getTitle() {
- return title;
- }
-
- public ReviewDto setTitle(String title) {
- this.title = title;
- return this;
- }
-
- public String getStatus() {
- return status;
- }
-
- public ReviewDto setStatus(@Nullable String status) {
- this.status = status;
- return this;
- }
-
- public String getResolution() {
- return resolution;
- }
-
- public ReviewDto setResolution(@Nullable String resolution) {
- this.resolution = resolution;
- return this;
- }
-
- public Integer getViolationPermanentId() {
- return violationPermanentId;
- }
-
- public ReviewDto setViolationPermanentId(Integer violationPermanentId) {
- this.violationPermanentId = violationPermanentId;
- return this;
- }
-
- public Integer getProjectId() {
- return projectId;
- }
-
- public ReviewDto setProjectId(Integer projectId) {
- this.projectId = projectId;
- return this;
- }
-
- public Integer getResourceId() {
- return resourceId;
- }
-
- public ReviewDto setResourceId(Integer resourceId) {
- this.resourceId = resourceId;
- return this;
- }
-
- public Integer getLine() {
- return line;
- }
-
- public ReviewDto setLine(@Nullable Integer line) {
- this.line = line;
- return this;
- }
-
- public Date getCreatedAt() {
- return createdAt;
- }
-
- public ReviewDto setCreatedAt(Date createdAt) {
- this.createdAt = createdAt;
- return this;
- }
-
- public Date getUpdatedAt() {
- return updatedAt;
- }
-
- public ReviewDto setUpdatedAt(Date updatedAt) {
- this.updatedAt = updatedAt;
- return this;
- }
-
- public String getSeverity() {
- return severity;
- }
-
- public ReviewDto setSeverity(@Nullable String severity) {
- this.severity = severity;
- return this;
- }
-
- public Integer getRuleId() {
- return ruleId;
- }
-
- public ReviewDto setRuleId(Integer ruleId) {
- this.ruleId = ruleId;
- return this;
- }
-
- public boolean getManualViolation() {
- return manualViolation;
- }
-
- public boolean isManualViolation() {
- return manualViolation;
- }
-
- public ReviewDto setManualViolation(boolean b) {
- this.manualViolation = b;
- return this;
- }
-
- public boolean getManualSeverity() {
- return manualSeverity;
- }
-
- public ReviewDto setManualSeverity(boolean b) {
- this.manualSeverity = b;
- return this;
- }
-
- public boolean isManualSeverity() {
- return manualSeverity;
- }
-
- public Integer getActionPlanId() {
- return actionPlanId;
- }
-
- public ReviewDto setActionPlanId(@Nullable Integer i) {
- this.actionPlanId = i;
- return this;
- }
-
- public String getData() {
- return data;
- }
-
- public ReviewDto setData(String s) {
- Preconditions.checkArgument(s == null || s.length() <= 4000,
- "Review data must not exceed 4000 characters: " + s);
- this.data = s;
- return this;
- }
-
- @Override
- public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- ReviewDto reviewDto = (ReviewDto) o;
- return !(id != null ? !id.equals(reviewDto.id) : reviewDto.id != null);
- }
-
- @Override
- public int hashCode() {
- return id != null ? id.hashCode() : 0;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.workflow;
-
-import com.google.common.collect.ImmutableMap;
-import org.sonar.api.workflow.Review;
-import org.sonar.api.workflow.internal.DefaultReview;
-
-import java.util.Map;
-
-public final class ImmutableReview implements Review {
- private final Long violationId;
- private final Long reviewId;
- private final String ruleRepositoryKey;
- private final String ruleKey;
- private final String ruleName;
- private final Long line;
- private final boolean switchedOff;
- private final boolean manual;
- private final String message;
- private final String status;
- private final String resolution;
- private final String severity;
- private final Map<String, String> properties;
-
- /**
- * Warning : implementation is still mutable.
- */
- public ImmutableReview(DefaultReview review) {
- this.line = review.getLine();
- this.manual = review.isManual();
- this.message = review.getMessage();
- this.properties = ImmutableMap.copyOf(review.getProperties());
- this.resolution = review.getResolution();
- this.reviewId = review.getReviewId();
- this.ruleKey = review.getRuleKey();
- this.ruleRepositoryKey = review.getRuleRepositoryKey();
- this.ruleName = review.getRuleName();
- this.severity = review.getSeverity();
- this.status = review.getStatus();
- this.switchedOff = review.isSwitchedOff();
- this.violationId = review.getViolationId();
- }
-
- public Long getViolationId() {
- return violationId;
- }
-
- public Long getReviewId() {
- return reviewId;
- }
-
- public String getRuleName() {
- return ruleName;
- }
-
- public String getRuleRepositoryKey() {
- return ruleRepositoryKey;
- }
-
- public String getRuleKey() {
- return ruleKey;
- }
-
- public Long getLine() {
- return line;
- }
-
- public boolean isSwitchedOff() {
- return switchedOff;
- }
-
- public boolean isManual() {
- return manual;
- }
-
- public String getMessage() {
- return message;
- }
-
- public String getStatus() {
- return status;
- }
-
- public String getResolution() {
- return resolution;
- }
-
- public String getSeverity() {
- return severity;
- }
-
- public Map<String, String> getProperties() {
- return properties;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.workflow;
-
-import org.sonar.api.config.Settings;
-import org.sonar.api.workflow.internal.DefaultReview;
-import java.util.List;
-
-public interface ReviewStore {
- void store(DefaultReview review);
-
- void completeProjectSettings(Long projectId, Settings settings, List<String> propertyKeys);
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.workflow;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Lists;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.config.Settings;
-import org.sonar.api.workflow.Review;
-import org.sonar.api.workflow.WorkflowContext;
-import org.sonar.api.workflow.condition.Condition;
-import org.sonar.api.workflow.function.Function;
-import org.sonar.api.workflow.internal.DefaultReview;
-import org.sonar.api.workflow.internal.DefaultWorkflow;
-import org.sonar.api.workflow.internal.DefaultWorkflowContext;
-import org.sonar.api.workflow.screen.Screen;
-
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.Map;
-
-public class WorkflowEngine implements ServerComponent {
-
- private final DefaultWorkflow workflow;
- private final ReviewStore store;
- private final Settings settings;
-
- public WorkflowEngine(DefaultWorkflow workflow, ReviewStore store, Settings settings) {
- this.workflow = workflow;
- this.store = store;
- this.settings = settings;
- }
-
- /**
- * @return non-null list of screens per review#violationId
- */
- public ListMultimap<Long, Screen> listAvailableScreens(DefaultReview[] reviews, DefaultWorkflowContext context, boolean verifyConditions) {
- ListMultimap<Long, Screen> result = ArrayListMultimap.create();
-
- completeProjectSettings(context);
-
- for (Map.Entry<String, Screen> entry : workflow.getScreensByCommand().entrySet()) {
- String commandKey = entry.getKey();
- if (!verifyConditions || verifyConditionsQuietly(null, context, workflow.getContextConditions(commandKey))) {
- for (DefaultReview review : reviews) {
- if (!verifyConditions || verifyConditionsQuietly(review, context, workflow.getReviewConditions(commandKey))) {
- result.put(review.getViolationId(), entry.getValue());
- }
- }
- }
- }
- return result;
- }
-
- public List<Screen> listAvailableScreens(Review review, DefaultWorkflowContext context, boolean verifyConditions) {
- List<Screen> result = Lists.newArrayList();
- completeProjectSettings(context);
- for (Map.Entry<String, Screen> entry : workflow.getScreensByCommand().entrySet()) {
- String commandKey = entry.getKey();
- if (!verifyConditions || verifyConditionsQuietly(review, context, workflow.getConditions(commandKey))) {
- result.add(entry.getValue());
-
- }
- }
- return result;
- }
-
- /**
- * @return the optional (nullable) screen associated to the command
- */
- public Screen getScreen(String commandKey) {
- return workflow.getScreen(commandKey);
- }
-
- public void execute(String commandKey, DefaultReview review, DefaultWorkflowContext context, Map<String, String> parameters) {
- Preconditions.checkArgument(!Strings.isNullOrEmpty(commandKey), "Missing command");
- Preconditions.checkArgument(workflow.hasCommand(commandKey), "Unknown command: " + commandKey);
-
- completeProjectSettings(context);
-
- verifyConditions(review, context, workflow.getConditions(commandKey));
-
- Map<String, String> immutableParameters = ImmutableMap.copyOf(parameters);
-
- // TODO execute functions are change state before functions that consume state (like "create-jira-issue")
- Review initialReview = new ImmutableReview(review);
- for (Function function : workflow.getFunctions(commandKey)) {
- function.doExecute(review, initialReview, context, immutableParameters);
- }
-
- // should it be extracted to a core function ?
- store.store(review);
-
- // TODO notify listeners
- }
-
- private boolean verifyConditionsQuietly(@Nullable Review review, WorkflowContext context, List<Condition> conditions) {
- for (Condition condition : conditions) {
- if (!condition.doVerify(review, context)) {
- return false;
- }
- }
- return true;
- }
-
- private void verifyConditions(@Nullable Review review, WorkflowContext context, List<Condition> conditions) {
- for (Condition condition : conditions) {
- if (!condition.doVerify(review, context)) {
- throw new IllegalStateException("Condition is not respected: " + condition.toString());
- }
- }
- }
-
- private void completeProjectSettings(DefaultWorkflowContext context) {
- Settings projectSettings = new Settings(settings);
- List<String> propertyKeys = workflow.getProjectPropertyKeys();
- store.completeProjectSettings(context.getProjectId(), projectSettings, propertyKeys);
- context.setSettings(projectSettings);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.core.workflow;
-
-import javax.annotation.ParametersAreNonnullByDefault;
\ No newline at end of file
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.core.workflow;
-
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Maps;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.config.Settings;
-import org.sonar.api.workflow.internal.DefaultWorkflow;
-import org.sonar.api.workflow.Review;
-import org.sonar.api.workflow.WorkflowContext;
-import org.sonar.api.workflow.condition.Condition;
-import org.sonar.api.workflow.condition.HasProjectPropertyCondition;
-import org.sonar.api.workflow.function.Function;
-import org.sonar.api.workflow.internal.DefaultReview;
-import org.sonar.api.workflow.internal.DefaultWorkflowContext;
-import org.sonar.api.workflow.screen.CommentScreen;
-import org.sonar.api.workflow.screen.Screen;
-import org.sonar.core.workflow.ImmutableReview;
-import org.sonar.core.workflow.ReviewStore;
-import org.sonar.core.workflow.WorkflowEngine;
-
-import java.util.List;
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.junit.matchers.JUnitMatchers.hasItem;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
-
-public class WorkflowEngineTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void listAvailableScreensForReview_empty() {
- WorkflowEngine engine = new WorkflowEngine(new DefaultWorkflow(), mock(ReviewStore.class), new Settings());
- List<Screen> screens = engine.listAvailableScreens(new DefaultReview(), new DefaultWorkflowContext(), true);
- assertThat(screens).isEmpty();
- }
-
- @Test
- public void listAvailableScreensForReview() {
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("command-without-screen");
- workflow.addCommand("resolve");
- CommentScreen screen = new CommentScreen();
- workflow.setScreen("resolve", screen);
-
- WorkflowEngine engine = new WorkflowEngine(workflow, mock(ReviewStore.class), new Settings());
- List<Screen> screens = engine.listAvailableScreens(new DefaultReview(), new DefaultWorkflowContext(), true);
- assertThat(screens).containsExactly(screen);
- }
-
- @Test
- public void listAvailableScreensForReview_verify_conditions() {
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("resolve");
- Condition condition = mock(Condition.class);
- when(condition.doVerify(any(Review.class), any(WorkflowContext.class))).thenReturn(false);
- workflow.addCondition("resolve", condition);
- workflow.setScreen("resolve", new CommentScreen());
-
- WorkflowEngine engine = new WorkflowEngine(workflow, mock(ReviewStore.class), new Settings());
- DefaultReview review = new DefaultReview();
- DefaultWorkflowContext context = new DefaultWorkflowContext();
- assertThat(engine.listAvailableScreens(review, context, true)).isEmpty();
-
- verify(condition).doVerify(review, context);
- }
-
- @Test
- public void listAvailableScreensForReviews_empty() {
- WorkflowEngine engine = new WorkflowEngine(new DefaultWorkflow(), mock(ReviewStore.class), new Settings());
- ListMultimap<Long, Screen> screens = engine.listAvailableScreens(
- new DefaultReview[]{new DefaultReview().setViolationId(1000L), new DefaultReview().setViolationId(2000L)},
- new DefaultWorkflowContext(), true);
- assertThat(screens.size()).isEqualTo(0);
- }
-
- @Test
- public void listAvailableScreensForReviews() {
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("command-without-screen");
- workflow.addCommand("resolve");
- CommentScreen screen = new CommentScreen();
- workflow.setScreen("resolve", screen);
- WorkflowEngine engine = new WorkflowEngine(workflow, mock(ReviewStore.class), new Settings());
- ListMultimap<Long, Screen> screens = engine.listAvailableScreens(
- new DefaultReview[]{new DefaultReview().setViolationId(1000L), new DefaultReview().setViolationId(2000L)},
- new DefaultWorkflowContext(), true);
- assertThat(screens.size()).isEqualTo(2);
- assertThat(screens.get(1000L)).containsExactly(screen);
- assertThat(screens.get(2000L)).containsExactly(screen);
- }
-
- @Test
- public void listAvailableScreensForReviews_load_project_properties() {
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("resolve");
- workflow.addCondition("resolve", new HasProjectPropertyCondition("foo"));
-
- ReviewStore store = mock(ReviewStore.class);
- WorkflowEngine engine = new WorkflowEngine(workflow, store, new Settings());
-
- engine.listAvailableScreens(
- new DefaultReview[]{new DefaultReview().setViolationId(1000L), new DefaultReview().setViolationId(2000L)},
- new DefaultWorkflowContext().setProjectId(300L),
- true);
-
- verify(store).completeProjectSettings(eq(300L), any(Settings.class), (List<String>) argThat(hasItem("foo")));
- }
-
- @Test
- public void execute_conditions_pass() {
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("resolve");
- workflow.addCondition("resolve", new HasProjectPropertyCondition("foo"));
- Function function = mock(Function.class);
- workflow.addFunction("resolve", function);
-
- ReviewStore store = mock(ReviewStore.class);
- Settings settings = new Settings();
- settings.setProperty("foo", "bar");
- WorkflowEngine engine = new WorkflowEngine(workflow, store, settings);
-
- DefaultReview review = new DefaultReview().setViolationId(1000L);
- Map<String, String> parameters = Maps.newHashMap();
- DefaultWorkflowContext context = new DefaultWorkflowContext().setProjectId(300L);
-
- engine.execute("resolve", review, context, parameters);
-
- verify(store).completeProjectSettings(eq(300L), any(Settings.class), (List<String>) argThat(hasItem("foo")));
- verify(function).doExecute(eq(review), any(ImmutableReview.class), eq(context), eq(parameters));
- }
-
- @Test
- public void execute_fail_if_conditions_dont_pass() {
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Condition is not respected: Property foo must be set");
-
- DefaultWorkflow workflow = new DefaultWorkflow();
- workflow.addCommand("resolve");
- workflow.addCondition("resolve", new HasProjectPropertyCondition("foo"));
- Function function = mock(Function.class);
- workflow.addFunction("resolve", function);
-
- ReviewStore store = mock(ReviewStore.class);
- Settings settings = new Settings();// missing property 'foo'
- WorkflowEngine engine = new WorkflowEngine(workflow, store, settings);
-
- DefaultReview review = new DefaultReview().setViolationId(1000L);
- Map<String, String> parameters = Maps.newHashMap();
- DefaultWorkflowContext context = new DefaultWorkflowContext().setProjectId(300L);
-
- engine.execute("resolve", review, context, parameters);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.notifications.reviews;
-
-import com.google.common.collect.Sets;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.notifications.NotificationManager;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @since 2.10
- */
-public class ReviewsNotificationManager implements ServerComponent {
-
- private NotificationManager notificationManager;
-
- public ReviewsNotificationManager(NotificationManager notificationManager) {
- this.notificationManager = notificationManager;
- }
-
- /**
- * @param reviewId reviewId id of review, which was modified
- * @param author author of change (username)
- * @param oldValues map of old values
- * @param newValues map of new values
- */
- public void notifyChanged(Long reviewId, String author, Map<String, String> oldValues, Map<String, String> newValues) {
- Notification notification = new Notification("review-changed")
- .setDefaultMessage("Review #" + reviewId + " has changed.")
- .setFieldValue("reviewId", String.valueOf(reviewId))
- .setFieldValue("project", newValues.get("project"))
- .setFieldValue("projectId", newValues.get("projectId"))
- .setFieldValue("resource", newValues.get("resource"))
- .setFieldValue("title", newValues.get("title"))
- .setFieldValue("author", author)
- .setFieldValue("creator", newValues.get("creator"))
- .setFieldValue("severity", newValues.get("severity"))
- .setFieldValue("assignee", newValues.get("assignee"));
- Set<String> fields = Sets.newHashSet();
- fields.addAll(oldValues.keySet());
- fields.addAll(newValues.keySet());
- for (String field : fields) {
- String oldValue = oldValues.get(field);
- String newValue = newValues.get(field);
- if (!StringUtils.equals(oldValue, newValue)) {
- notification.setFieldValue("new." + field, newValue);
- notification.setFieldValue("old." + field, oldValue);
- }
- }
- notificationManager.scheduleForSending(notification);
- }
-
-}
import org.sonar.core.timemachine.Periods;
import org.sonar.core.user.DefaultUserFinder;
import org.sonar.core.user.HibernateUserFinder;
-import org.sonar.core.workflow.WorkflowEngine;
import org.sonar.jpa.dao.MeasuresDao;
import org.sonar.jpa.dao.ProfilesDao;
import org.sonar.jpa.dao.RulesDao;
import org.sonar.server.issue.*;
import org.sonar.server.notifications.NotificationCenter;
import org.sonar.server.notifications.NotificationService;
-import org.sonar.server.notifications.reviews.ReviewsNotificationManager;
import org.sonar.server.plugins.*;
import org.sonar.server.qualitymodel.DefaultModelManager;
import org.sonar.server.rule.RubyRuleService;
private void startServiceComponents() {
servicesContainer = coreContainer.createChild();
servicesContainer.addSingleton(DefaultWorkflow.class);
- servicesContainer.addSingleton(WorkflowEngine.class);
servicesContainer.addSingleton(HttpDownloader.class);
servicesContainer.addSingleton(UriReader.class);
servicesContainer.addSingleton(UpdateCenterClient.class);
servicesContainer.addSingleton(NotificationService.class);
servicesContainer.addSingleton(NotificationCenter.class);
servicesContainer.addSingleton(DefaultNotificationManager.class);
- servicesContainer.addSingleton(ReviewsNotificationManager.class);
// graphs and perspective related classes
servicesContainer.addSingleton(TestablePerspectiveLoader.class);
*/
package org.sonar.server.ui;
-import com.google.common.collect.ListMultimap;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.License;
import org.sonar.api.test.Testable;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.api.web.*;
-import org.sonar.api.workflow.Review;
-import org.sonar.api.workflow.internal.DefaultReview;
-import org.sonar.api.workflow.internal.DefaultWorkflowContext;
-import org.sonar.api.workflow.screen.Screen;
import org.sonar.core.component.SnapshotPerspectives;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.measure.MeasureFilterEngine;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.core.resource.ResourceKeyUpdaterDao;
import org.sonar.core.timemachine.Periods;
-import org.sonar.core.workflow.WorkflowEngine;
import org.sonar.server.configuration.Backup;
import org.sonar.server.configuration.ProfilesManager;
-import org.sonar.server.notifications.reviews.ReviewsNotificationManager;
import org.sonar.server.platform.*;
import org.sonar.server.plugins.*;
import org.sonar.server.rules.ProfilesConsole;
return get(Settings.class).getString(CoreProperties.SONAR_HOME);
}
- public ReviewsNotificationManager getReviewsNotificationManager() {
- return get(ReviewsNotificationManager.class);
- }
-
public ComponentContainer getContainer() {
return Platform.getInstance().getContainer();
}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.notifications.reviews;
-
-import com.google.common.collect.Maps;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.notifications.NotificationManager;
-
-import java.util.Map;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-
-public class ReviewsNotificationManagerTest {
-
- private Notification notification;
- private ReviewsNotificationManager manager;
-
- @Before
- public void setUp() {
- NotificationManager delegate = mock(NotificationManager.class);
- doAnswer(new Answer() {
- public Object answer(InvocationOnMock invocation) throws Throwable {
- notification = (Notification) invocation.getArguments()[0];
- return null;
- }
- }).when(delegate).scheduleForSending(any(Notification.class));
- manager = new ReviewsNotificationManager(delegate);
- }
-
- @Test
- public void shouldScheduleNotification() {
- Map<String, String> oldValues = Maps.newHashMap();
- Map<String, String> newValues = Maps.newHashMap();
- newValues.put("project", "Sonar");
- newValues.put("projectId", "42");
- newValues.put("resource", "org.sonar.server.ui.DefaultPages");
- newValues.put("title", "Utility classes should not have a public or default constructor.");
- newValues.put("creator", "olivier");
- newValues.put("assignee", "godin");
- oldValues.put("assignee", "simon");
- manager.notifyChanged(1L, "freddy", oldValues, newValues);
- assertThat(notification, notNullValue());
- assertThat(notification.getType(), is("review-changed"));
- assertThat(notification.getDefaultMessage(), is("Review #1 has changed."));
- assertThat(notification.getFieldValue("reviewId"), is("1"));
- assertThat(notification.getFieldValue("author"), is("freddy"));
- assertThat(notification.getFieldValue("project"), is("Sonar"));
- assertThat(notification.getFieldValue("projectId"), is("42"));
- assertThat(notification.getFieldValue("resource"), is("org.sonar.server.ui.DefaultPages"));
- assertThat(notification.getFieldValue("title"), is("Utility classes should not have a public or default constructor."));
- assertThat(notification.getFieldValue("creator"), is("olivier"));
- assertThat(notification.getFieldValue("assignee"), is("godin"));
- assertThat(notification.getFieldValue("old.assignee"), is("simon"));
- assertThat(notification.getFieldValue("new.assignee"), is("godin"));
- }
-
-}