From 108dc916996e3075eb21c6ae1bbc7c9a24f09ab0 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 16 Apr 2013 13:24:54 +0200 Subject: [PATCH] SONAR-3755 the perspective Issuable should not be available on Java classes and methods --- ...ScanIssuable.java => DefaultIssuable.java} | 4 +- ...uableFactory.java => IssuableFactory.java} | 18 ++++- .../sonar/batch/issue/IssuesDecorator.java | 10 ++- .../sonar/batch/scan/ModuleScanContainer.java | 4 +- .../scan/source/HighlightableBuilder.java | 27 ++++++- .../java/org/sonar/batch/index/CacheTest.java | 30 +++++++ .../batch/issue/IssuableFactoryTest.java | 79 +++++++++++++++++++ .../scan/source/HighlightableBuilderTest.java | 35 ++++++-- .../core/component/PerspectiveBuilder.java | 3 + .../core/component/ResourceComponent.java | 12 ++- .../core/component/ScanPerspectives.java | 1 + .../component/PerspectiveBuilderTest.java | 44 +++++++++++ 12 files changed, 244 insertions(+), 23 deletions(-) rename sonar-batch/src/main/java/org/sonar/batch/issue/{ScanIssuable.java => DefaultIssuable.java} (92%) rename sonar-batch/src/main/java/org/sonar/batch/issue/{ScanIssuableFactory.java => IssuableFactory.java} (69%) create mode 100644 sonar-batch/src/test/java/org/sonar/batch/index/CacheTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java create mode 100644 sonar-core/src/test/java/org/sonar/core/component/PerspectiveBuilderTest.java diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuable.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java similarity index 92% rename from sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuable.java rename to sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java index 974443163f4..e22b25758ea 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java @@ -29,12 +29,12 @@ import java.util.Collection; /** * @since 3.6 */ -public class ScanIssuable implements Issuable { +public class DefaultIssuable implements Issuable { private final ModuleIssues moduleIssues; private final Component component; - ScanIssuable(Component component, ModuleIssues moduleIssues) { + DefaultIssuable(Component component, ModuleIssues moduleIssues) { this.component = component; this.moduleIssues = moduleIssues; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuableFactory.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java similarity index 69% rename from sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuableFactory.java rename to sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java index 91fd9a44eaa..01b95a05cbc 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssuableFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java @@ -21,19 +21,31 @@ package org.sonar.batch.issue; import org.sonar.api.component.Component; import org.sonar.api.issue.Issuable; +import org.sonar.api.resources.Scopes; import org.sonar.core.component.PerspectiveBuilder; +import org.sonar.core.component.ResourceComponent; -public class ScanIssuableFactory extends PerspectiveBuilder { +import javax.annotation.CheckForNull; + +public class IssuableFactory extends PerspectiveBuilder { private final ModuleIssues moduleIssues; - public ScanIssuableFactory(ModuleIssues moduleIssues) { + public IssuableFactory(ModuleIssues moduleIssues) { super(Issuable.class); this.moduleIssues = moduleIssues; } + @CheckForNull @Override protected Issuable loadPerspective(Class perspectiveClass, Component component) { - return new ScanIssuable(component, moduleIssues); + boolean supported = true; + if (component instanceof ResourceComponent) { + supported = Scopes.isHigherThanOrEquals(((ResourceComponent) component).scope(), Scopes.FILE); + } + if (supported) { + return new DefaultIssuable(component, moduleIssues); + } + return null; } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuesDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuesDecorator.java index c54d552830f..280ad46e1e9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuesDecorator.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuesDecorator.java @@ -65,10 +65,12 @@ public class IssuesDecorator implements Decorator { public void decorate(Resource resource, DecoratorContext context) { Issuable issuable = perspectives.as(Issuable.class, resource); - Collection issues = issuable.issues(); - computeTotalIssues(context, issues); - computeIssuesPerSeverities(context, issues); - computeIssuesPerRules(context, issues); + if (issuable != null) { + Collection issues = issuable.issues(); + computeTotalIssues(context, issues); + computeIssuesPerSeverities(context, issues); + computeIssuesPerRules(context, issues); + } } private void computeTotalIssues(DecoratorContext context, Collection issues) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java index 855e40be342..4970de6ce97 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java @@ -46,6 +46,7 @@ import org.sonar.batch.components.TimeMachineConfiguration; import org.sonar.batch.events.EventBus; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.ResourcePersister; +import org.sonar.batch.issue.IssuableFactory; import org.sonar.batch.issue.ModuleIssues; import org.sonar.batch.local.DryRunExporter; import org.sonar.batch.phases.PhaseExecutor; @@ -56,7 +57,6 @@ import org.sonar.batch.scan.filesystem.FileSystemLogger; import org.sonar.batch.scan.filesystem.LanguageFilters; import org.sonar.batch.scan.filesystem.ModuleFileSystemProvider; import org.sonar.core.component.ScanPerspectives; -import org.sonar.batch.issue.ScanIssuableFactory; import org.sonar.batch.scan.source.HighlightableBuilder; public class ModuleScanContainer extends ComponentContainer { @@ -121,7 +121,7 @@ public class ModuleScanContainer extends ComponentContainer { new ProfileProvider(), ModuleIssues.class, - ScanIssuableFactory.class, + IssuableFactory.class, HighlightableBuilder.class, ScanPerspectives.class diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/source/HighlightableBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/source/HighlightableBuilder.java index a25c39d114f..7b891015d76 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/source/HighlightableBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/source/HighlightableBuilder.java @@ -19,24 +19,43 @@ */ package org.sonar.batch.scan.source; +import com.google.common.collect.ImmutableSet; import org.sonar.api.component.Component; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Scopes; import org.sonar.api.scan.source.Highlightable; import org.sonar.core.component.PerspectiveBuilder; +import org.sonar.core.component.ResourceComponent; + +import javax.annotation.CheckForNull; +import java.util.Set; /** * @since 3.6 */ public class HighlightableBuilder extends PerspectiveBuilder { - private final SyntaxHighlightingCache syntaxHighlightingCache; + private static final Set SUPPORTED_QUALIFIERS = ImmutableSet.of(Qualifiers.FILE, Qualifiers.CLASS, Qualifiers.UNIT_TEST_FILE); + private final SyntaxHighlightingCache cache; + - public HighlightableBuilder(SyntaxHighlightingCache syntaxHighlightingCache) { + public HighlightableBuilder(SyntaxHighlightingCache cache) { super(Highlightable.class); - this.syntaxHighlightingCache = syntaxHighlightingCache; + this.cache = cache; } + @CheckForNull @Override protected Highlightable loadPerspective(Class perspectiveClass, Component component) { - return new DefaultHighlightable(component, syntaxHighlightingCache); + boolean supported = SUPPORTED_QUALIFIERS.contains(component.qualifier()); + if (supported && component instanceof ResourceComponent) { + // temporary hack waiting for the removal of JavaClass. + // JavaClass has the same qualifier than JavaFile, so they have to distinguished by their scope + supported = Scopes.FILE.equals(((ResourceComponent) component).scope()); + } + if (supported) { + return new DefaultHighlightable(component, cache); + } + return null; } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/CacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/CacheTest.java new file mode 100644 index 00000000000..6abf8691e29 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/index/CacheTest.java @@ -0,0 +1,30 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.index; + +import org.junit.Test; + +public class CacheTest { + @Test + public void test_put() throws Exception { + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java new file mode 100644 index 00000000000..6f3187d1f7c --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java @@ -0,0 +1,79 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.issue; + +import org.junit.Test; +import org.sonar.api.component.Component; +import org.sonar.api.issue.Issuable; +import org.sonar.api.resources.File; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Project; +import org.sonar.core.component.ResourceComponent; +import org.sonar.java.api.JavaClass; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class IssuableFactoryTest { + + ModuleIssues moduleIssues = mock(ModuleIssues.class); + + @Test + public void file_should_be_issuable() throws Exception { + IssuableFactory factory = new IssuableFactory(moduleIssues); + Component component = new ResourceComponent(new File("foo/bar.c")); + Issuable issuable = factory.loadPerspective(Issuable.class, component); + + assertThat(issuable).isNotNull(); + assertThat(issuable.component()).isSameAs(component); + assertThat(issuable.issues()).isEmpty(); + } + + @Test + public void project_should_be_issuable() throws Exception { + IssuableFactory factory = new IssuableFactory(moduleIssues); + Component component = new ResourceComponent(new Project("Foo")); + Issuable issuable = factory.loadPerspective(Issuable.class, component); + + assertThat(issuable).isNotNull(); + assertThat(issuable.component()).isSameAs(component); + assertThat(issuable.issues()).isEmpty(); + } + + @Test + public void java_file_should_be_issuable() throws Exception { + IssuableFactory factory = new IssuableFactory(moduleIssues); + Component component = new ResourceComponent(new JavaFile("bar.Foo")); + Issuable issuable = factory.loadPerspective(Issuable.class, component); + + assertThat(issuable).isNotNull(); + assertThat(issuable.component()).isSameAs(component); + assertThat(issuable.issues()).isEmpty(); + } + + @Test + public void java_class_should_not_be_issuable() throws Exception { + IssuableFactory factory = new IssuableFactory(moduleIssues); + Component component = new ResourceComponent(JavaClass.create("bar", "Foo")); + Issuable issuable = factory.loadPerspective(Issuable.class, component); + + assertThat(issuable).isNull(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/source/HighlightableBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/source/HighlightableBuilderTest.java index 95fccc235dc..3b8009cd160 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/source/HighlightableBuilderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/source/HighlightableBuilderTest.java @@ -21,22 +21,47 @@ package org.sonar.batch.scan.source; import org.junit.Test; import org.sonar.api.component.Component; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; import org.sonar.api.scan.source.Highlightable; +import org.sonar.core.component.ResourceComponent; +import org.sonar.java.api.JavaClass; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; public class HighlightableBuilderTest { + SyntaxHighlightingCache cache = mock(SyntaxHighlightingCache.class); + @Test public void should_load_default_perspective() throws Exception { + Component component = new ResourceComponent(new File("foo/bar.c")); + + HighlightableBuilder builder = new HighlightableBuilder(cache); + Highlightable perspective = builder.loadPerspective(Highlightable.class, component); + + assertThat(perspective).isNotNull().isInstanceOf(DefaultHighlightable.class); + assertThat(perspective.component()).isSameAs(component); + } + + @Test + public void project_should_not_be_highlightable() { + Component component = new ResourceComponent(new Project("Foo")); + + HighlightableBuilder builder = new HighlightableBuilder(cache); + Highlightable perspective = builder.loadPerspective(Highlightable.class, component); - Component mockComponent = mock(Component.class); - SyntaxHighlightingCache highlightingCache = mock(SyntaxHighlightingCache.class); + assertThat(perspective).isNull(); + } + + @Test + public void java_class_should_not_be_highlightable() { + Component component = new ResourceComponent(JavaClass.create("foo", "Bar")); - HighlightableBuilder builder = new HighlightableBuilder(highlightingCache); - Highlightable perspective = builder.loadPerspective(Highlightable.class, mockComponent); + HighlightableBuilder builder = new HighlightableBuilder(cache); + Highlightable perspective = builder.loadPerspective(Highlightable.class, component); - assertThat(perspective).isInstanceOf(DefaultHighlightable.class); + assertThat(perspective).isNull(); } } diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java index 1577ce5dec0..8d5967da3c6 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java @@ -24,6 +24,8 @@ import org.sonar.api.ServerComponent; import org.sonar.api.component.Component; import org.sonar.api.component.Perspective; +import javax.annotation.CheckForNull; + public abstract class PerspectiveBuilder implements BatchComponent, ServerComponent { private final Class perspectiveClass; @@ -36,5 +38,6 @@ public abstract class PerspectiveBuilder implements Batch return perspectiveClass; } + @CheckForNull protected abstract T loadPerspective(Class perspectiveClass, Component component); } diff --git a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java index 15063473161..1679509bceb 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java @@ -25,26 +25,28 @@ import org.sonar.api.resources.Resource; import javax.annotation.Nullable; -class ResourceComponent implements Component { +public class ResourceComponent implements Component { private String key; private String name; private String longName; private String qualifier; + private String scope; private Long snapshotId; private Long resourceId; - ResourceComponent(Resource resource, @Nullable Snapshot snapshot) { + public ResourceComponent(Resource resource, @Nullable Snapshot snapshot) { this.key = resource.getEffectiveKey(); this.name = resource.getName(); this.longName = resource.getLongName(); this.qualifier = resource.getQualifier(); + this.scope = resource.getScope(); if (snapshot != null && snapshot.getId() != null) { this.snapshotId = snapshot.getId().longValue(); this.resourceId = snapshot.getResourceId().longValue(); } } - ResourceComponent(Resource resource) { + public ResourceComponent(Resource resource) { this(resource, null); } @@ -65,6 +67,10 @@ class ResourceComponent implements Component { return qualifier; } + public String scope() { + return scope; + } + public Long snapshotId() { return snapshotId; } diff --git a/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java b/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java index 6cd29abf004..3b3d818b858 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java @@ -53,6 +53,7 @@ public class ScanPerspectives implements ResourcePerspectives, BatchComponent { return builder.loadPerspective(perspectiveClass, component); } + @CheckForNull public

P as(Class

perspectiveClass, Resource resource) { Resource indexedResource = resourceIndex.getResource(resource); if (indexedResource != null) { diff --git a/sonar-core/src/test/java/org/sonar/core/component/PerspectiveBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/component/PerspectiveBuilderTest.java new file mode 100644 index 00000000000..d95060db53c --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/component/PerspectiveBuilderTest.java @@ -0,0 +1,44 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.component; + +import org.junit.Test; +import org.sonar.api.component.Component; +import org.sonar.api.component.Perspective; + +import static org.fest.assertions.Assertions.assertThat; + +public class PerspectiveBuilderTest { + @Test + public void testGetPerspectiveClass() throws Exception { + PerspectiveBuilder builder = new PerspectiveBuilder(FakePerspective.class) { + @Override + protected FakePerspective loadPerspective(Class perspectiveClass, Component component) { + return null; + } + }; + + assertThat(builder.getPerspectiveClass()).isEqualTo(FakePerspective.class); + } + + static interface FakePerspective extends Perspective { + + } +} -- 2.39.5