From a3521edd7c7cc726e5aa2161e8cc0f76ecd571dc Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Vilain Date: Thu, 4 Apr 2013 15:50:09 +0200 Subject: [PATCH] (SONAR-3893) Improve the highlighter API to not depend on sonar-channel and allow to work on multi-line tokens --- .../component/GraphPerspectiveBuilder.java | 84 +++++++++++++++++++ .../core/component/PerspectiveBuilder.java | 19 +---- .../sonar/core/component/ScanGraphStore.java | 50 ++++++----- .../core/component/ScanPerspectives.java | 24 +----- .../core/component/SnapshotPerspectives.java | 6 +- .../core/source/DefaultHighlightable.java | 49 +++++++++++ .../core/source/HighlightableBuilder.java | 36 ++++++++ .../org/sonar/core/test/TestPlanBuilder.java | 31 ++----- .../org/sonar/core/test/TestableBuilder.java | 31 ++----- .../core/source/DefaultHighlightableTest.java | 57 +++++++++++++ .../core/source/HighlightableBuilderTest.java | 41 +++++++++ .../sonar/core/test/TestPlanBuilderTest.java | 8 +- .../sonar/core/test/TestableBuilderTest.java | 7 +- .../sonar/api/scan/source/Highlightable.java | 27 ++++++ .../scan/source/HighlightableTextType.java | 39 +++++++++ .../scan/source/SyntaxHighlightingRule.java | 49 +++++++++++ .../source/SyntaxHighlightingRuleSet.java | 63 ++++++++++++++ .../source/SyntaxHighlightingRuleSetTest.java | 53 ++++++++++++ 18 files changed, 564 insertions(+), 110 deletions(-) create mode 100644 sonar-core/src/main/java/org/sonar/core/component/GraphPerspectiveBuilder.java create mode 100644 sonar-core/src/main/java/org/sonar/core/source/DefaultHighlightable.java create mode 100644 sonar-core/src/main/java/org/sonar/core/source/HighlightableBuilder.java create mode 100644 sonar-core/src/test/java/org/sonar/core/source/DefaultHighlightableTest.java create mode 100644 sonar-core/src/test/java/org/sonar/core/source/HighlightableBuilderTest.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/source/Highlightable.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/source/HighlightableTextType.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRule.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSet.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSetTest.java diff --git a/sonar-core/src/main/java/org/sonar/core/component/GraphPerspectiveBuilder.java b/sonar-core/src/main/java/org/sonar/core/component/GraphPerspectiveBuilder.java new file mode 100644 index 00000000000..30f9fe07197 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/component/GraphPerspectiveBuilder.java @@ -0,0 +1,84 @@ +/* + * 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 com.tinkerpop.blueprints.Direction; +import com.tinkerpop.blueprints.Vertex; +import org.sonar.api.component.Component; +import org.sonar.api.component.Perspective; +import org.sonar.core.graph.BeanVertex; +import org.sonar.core.graph.EdgePath; +import org.sonar.core.graph.GraphUtil; + +public abstract class GraphPerspectiveBuilder extends PerspectiveBuilder { + + protected final ScanGraph graph; + protected final EdgePath path; + protected final String perspectiveKey; + + protected GraphPerspectiveBuilder(ScanGraph graph, String perspectiveKey, Class perspectiveClass, EdgePath path) { + super(perspectiveClass); + this.graph = graph; + this.path = path; + this.perspectiveKey = perspectiveKey; + } + + public T load(ComponentVertex component) { + Vertex perspectiveVertex = GraphUtil.singleAdjacent(component.element(), Direction.OUT, getPerspectiveKey()); + if (perspectiveVertex != null) { + return (T) component.beanGraph().wrap(perspectiveVertex, getBeanClass()); + } + return null; + } + + public T create(ComponentVertex component) { + return (T) component.beanGraph().createAdjacentVertex(component, getBeanClass(), getPerspectiveKey()); + } + + public EdgePath path() { + return path; + } + + @Override + protected T loadPerspective(Class perspectiveClass, Component component) { + ComponentVertex vertex; + if (component instanceof ComponentVertex) { + vertex = (ComponentVertex) component; + } else { + vertex = graph.getComponent(component.key()); + } + + if (vertex != null) { + T perspective = load(vertex); + if (perspective == null) { + perspective = create(vertex); + } + return perspective; + } + return null; + } + + + protected String getPerspectiveKey() { + return perspectiveKey; + } + + protected abstract Class getBeanClass(); +} 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 0a66905e077..a605ed40170 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 @@ -21,34 +21,21 @@ package org.sonar.core.component; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import org.sonar.api.component.Component; import org.sonar.api.component.Perspective; -import org.sonar.core.graph.EdgePath; - -import javax.annotation.CheckForNull; public abstract class PerspectiveBuilder implements BatchComponent, ServerComponent { - private final String perspectiveKey; private final Class perspectiveClass; - protected PerspectiveBuilder(String perspectiveKey, Class perspectiveClass) { - this.perspectiveKey = perspectiveKey; + protected PerspectiveBuilder(Class perspectiveClass) { this.perspectiveClass = perspectiveClass; } - protected String getPerspectiveKey() { - return perspectiveKey; - } - protected Class getPerspectiveClass() { return perspectiveClass; } - @CheckForNull - public abstract T load(ComponentVertex component); - - public abstract T create(ComponentVertex component); - - public abstract EdgePath path(); + protected abstract T loadPerspective(Class perspectiveClass, Component component); } diff --git a/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java b/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java index 44590d76ef6..f527cf00e22 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java @@ -50,25 +50,7 @@ public class ScanGraphStore { GraphDtoMapper mapper = session.getMapper(GraphDtoMapper.class); try { for (ComponentVertex component : projectGraph.getComponents()) { - Long snapshotId = (Long) component.element().getProperty("sid"); - if (snapshotId != null) { - for (PerspectiveBuilder builder : builders) { - Perspective perspective = builder.load(component); - if (perspective != null) { - Graph subGraph = SubGraph.extract(component.element(), builder.path()); - String data = write(subGraph); - mapper.insert(new GraphDto() - .setData(data) - .setFormat("graphson") - .setPerspective(builder.getPerspectiveKey()) - .setVersion(1) - .setResourceId((Long) component.element().getProperty("rid")) - .setSnapshotId(snapshotId) - .setRootVertexId(component.element().getId().toString()) - ); - } - } - } + persistComponentGraph(mapper, component); } session.commit(); } finally { @@ -76,6 +58,36 @@ public class ScanGraphStore { } } + private void persistComponentGraph(GraphDtoMapper mapper, ComponentVertex component) { + Long snapshotId = (Long) component.element().getProperty("sid"); + if (snapshotId != null) { + for (PerspectiveBuilder builder : builders) { + if(builder instanceof GraphPerspectiveBuilder) { + GraphPerspectiveBuilder graphPerspectiveBuilder = (GraphPerspectiveBuilder)builder; + Perspective perspective = graphPerspectiveBuilder.load(component); + if (perspective != null) { + serializePerspectiveData(mapper, component, snapshotId, graphPerspectiveBuilder); + } + } + } + } + } + + private void serializePerspectiveData(GraphDtoMapper mapper, ComponentVertex component, Long snapshotId, + GraphPerspectiveBuilder builder) { + Graph subGraph = SubGraph.extract(component.element(), builder.path()); + String data = write(subGraph); + mapper.insert(new GraphDto() + .setData(data) + .setFormat("graphson") + .setPerspective(builder.getPerspectiveKey()) + .setVersion(1) + .setResourceId((Long) component.element().getProperty("rid")) + .setSnapshotId(snapshotId) + .setRootVertexId(component.element().getId().toString()) + ); + } + private String write(Graph graph) { StringWriter output = new StringWriter(); try { 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 c9dc3368c52..6cd29abf004 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 @@ -32,12 +32,11 @@ import javax.annotation.CheckForNull; import java.util.Map; public class ScanPerspectives implements ResourcePerspectives, BatchComponent { - private final ScanGraph graph; + private final Map, PerspectiveBuilder> builders = Maps.newHashMap(); private final SonarIndex resourceIndex; - public ScanPerspectives(ScanGraph graph, PerspectiveBuilder[] builders, SonarIndex resourceIndex) { - this.graph = graph; + public ScanPerspectives(PerspectiveBuilder[] builders, SonarIndex resourceIndex) { this.resourceIndex = resourceIndex; for (PerspectiveBuilder builder : builders) { // TODO check duplications @@ -50,23 +49,8 @@ public class ScanPerspectives implements ResourcePerspectives, BatchComponent { if (component.key() == null) { return null; } - - ComponentVertex vertex; - if (component instanceof ComponentVertex) { - vertex = (ComponentVertex) component; - } else { - vertex = graph.getComponent(component.key()); - } - - if (vertex != null) { - PerspectiveBuilder

builder = builderFor(perspectiveClass); - P perspective = builder.load(vertex); - if (perspective == null) { - perspective = builder.create(vertex); - } - return perspective; - } - return null; + PerspectiveBuilder

builder = builderFor(perspectiveClass); + return builder.loadPerspective(perspectiveClass, component); } public

P as(Class

perspectiveClass, Resource resource) { diff --git a/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java b/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java index fb615caaaf8..d64ee818d93 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java +++ b/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java @@ -47,7 +47,7 @@ public class SnapshotPerspectives implements ServerComponent { @CheckForNull public T as(Class perspectiveClass, String componentKey) { - PerspectiveBuilder builder = (PerspectiveBuilder) builders.get(perspectiveClass); + GraphPerspectiveBuilder builder = (GraphPerspectiveBuilder) builders.get(perspectiveClass); if (builder == null) { throw new IllegalStateException(); } @@ -57,7 +57,7 @@ public class SnapshotPerspectives implements ServerComponent { @CheckForNull public T as(Class perspectiveClass, long snapshotId) { - PerspectiveBuilder builder = (PerspectiveBuilder) builders.get(perspectiveClass); + GraphPerspectiveBuilder builder = (GraphPerspectiveBuilder) builders.get(perspectiveClass); if (builder == null) { throw new IllegalStateException(); } @@ -69,7 +69,7 @@ public class SnapshotPerspectives implements ServerComponent { T result = null; if (graphDto != null) { SnapshotGraph graph = read(graphDto.getData(), graphDto.getRootVertexId()); - result = builder.load(graph.wrap(graph.getComponentRoot(), ComponentVertex.class)); + result = ((GraphPerspectiveBuilder)builder).load(graph.wrap(graph.getComponentRoot(), ComponentVertex.class)); } return result; } diff --git a/sonar-core/src/main/java/org/sonar/core/source/DefaultHighlightable.java b/sonar-core/src/main/java/org/sonar/core/source/DefaultHighlightable.java new file mode 100644 index 00000000000..006fa22be3a --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/source/DefaultHighlightable.java @@ -0,0 +1,49 @@ +/* + * 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.source; + +import org.sonar.api.component.Component; +import org.sonar.api.scan.source.Highlightable; +import org.sonar.api.scan.source.SyntaxHighlightingRuleSet; + +public class DefaultHighlightable implements Highlightable { + + private final Component component; + private final SyntaxHighlightingRuleSet.Builder highlightingRulesBuilder; + + public DefaultHighlightable(Component component) { + highlightingRulesBuilder = new SyntaxHighlightingRuleSet.Builder(); + this.component = component; + } + + @Override + public SyntaxHighlightingRuleSet.Builder highlightText(int startOffset, int endOffset, String typeOfText) { + return highlightingRulesBuilder.registerHighlightingRule(startOffset, endOffset, typeOfText); + } + + @Override + public Component component() { + throw new UnsupportedOperationException("Unexpected call to component API"); + } + + public SyntaxHighlightingRuleSet getHighlightingRules() { + return highlightingRulesBuilder.build(); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/source/HighlightableBuilder.java b/sonar-core/src/main/java/org/sonar/core/source/HighlightableBuilder.java new file mode 100644 index 00000000000..ba823be360e --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/source/HighlightableBuilder.java @@ -0,0 +1,36 @@ +/* + * 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.source; + +import org.sonar.api.component.Component; +import org.sonar.api.scan.source.Highlightable; +import org.sonar.core.component.PerspectiveBuilder; + +public class HighlightableBuilder extends PerspectiveBuilder { + + public HighlightableBuilder() { + super(Highlightable.class); + } + + @Override + protected Highlightable loadPerspective(Class perspectiveClass, Component component) { + return new DefaultHighlightable(component); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java b/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java index 3084d6e3891..8d4df5eb4a1 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java @@ -20,14 +20,13 @@ package org.sonar.core.test; import com.tinkerpop.blueprints.Direction; -import com.tinkerpop.blueprints.Vertex; import org.sonar.api.test.MutableTestPlan; -import org.sonar.core.component.ComponentVertex; -import org.sonar.core.component.PerspectiveBuilder; +import org.sonar.core.component.GraphPerspectiveBuilder; +import org.sonar.core.component.ScanGraph; +import org.sonar.core.graph.BeanVertex; import org.sonar.core.graph.EdgePath; -import org.sonar.core.graph.GraphUtil; -public class TestPlanBuilder extends PerspectiveBuilder { +public class TestPlanBuilder extends GraphPerspectiveBuilder { static final String PERSPECTIVE_KEY = "testplan"; @@ -38,26 +37,12 @@ public class TestPlanBuilder extends PerspectiveBuilder { Direction.IN, "testable" ); - public TestPlanBuilder() { - super(PERSPECTIVE_KEY, MutableTestPlan.class); + public TestPlanBuilder(ScanGraph graph) { + super(graph, PERSPECTIVE_KEY, MutableTestPlan.class, PATH); } @Override - public MutableTestPlan load(ComponentVertex component) { - Vertex planVertex = GraphUtil.singleAdjacent(component.element(), Direction.OUT, PERSPECTIVE_KEY); - if (planVertex != null) { - return component.beanGraph().wrap(planVertex, DefaultTestPlan.class); - } - return null; - } - - @Override - public MutableTestPlan create(ComponentVertex component) { - return component.beanGraph().createAdjacentVertex(component, DefaultTestPlan.class, PERSPECTIVE_KEY); - } - - @Override - public EdgePath path() { - return PATH; + protected Class getBeanClass() { + return DefaultTestPlan.class; } } diff --git a/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java b/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java index a7a86813213..5b1b5aec4c4 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java @@ -20,14 +20,13 @@ package org.sonar.core.test; import com.tinkerpop.blueprints.Direction; -import com.tinkerpop.blueprints.Vertex; import org.sonar.api.test.MutableTestable; -import org.sonar.core.component.ComponentVertex; +import org.sonar.core.component.GraphPerspectiveBuilder; +import org.sonar.core.component.ScanGraph; +import org.sonar.core.graph.BeanVertex; import org.sonar.core.graph.EdgePath; -import org.sonar.core.component.PerspectiveBuilder; -import org.sonar.core.graph.GraphUtil; -public class TestableBuilder extends PerspectiveBuilder { +public class TestableBuilder extends GraphPerspectiveBuilder { static final String PERSPECTIVE_KEY = "testable"; @@ -38,26 +37,12 @@ public class TestableBuilder extends PerspectiveBuilder { Direction.IN,"testplan" ); - public TestableBuilder() { - super(PERSPECTIVE_KEY, MutableTestable.class); + public TestableBuilder(ScanGraph graph) { + super(graph, PERSPECTIVE_KEY, MutableTestable.class, PATH); } @Override - public MutableTestable load(ComponentVertex component) { - Vertex perspectiveVertex = GraphUtil.singleAdjacent(component.element(), Direction.OUT, PERSPECTIVE_KEY); - if (perspectiveVertex != null) { - return component.beanGraph().wrap(perspectiveVertex, DefaultTestable.class); - } - return null; - } - - @Override - public MutableTestable create(ComponentVertex component) { - return component.beanGraph().createAdjacentVertex(component, DefaultTestable.class, PERSPECTIVE_KEY); - } - - @Override - public EdgePath path() { - return PATH; + protected Class getBeanClass() { + return DefaultTestable.class; } } diff --git a/sonar-core/src/test/java/org/sonar/core/source/DefaultHighlightableTest.java b/sonar-core/src/test/java/org/sonar/core/source/DefaultHighlightableTest.java new file mode 100644 index 00000000000..9990218d2ee --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/source/DefaultHighlightableTest.java @@ -0,0 +1,57 @@ +/* + * 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.source; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.component.Component; +import org.sonar.api.scan.source.HighlightableTextType; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class DefaultHighlightableTest { + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Test + public void should_register_highlighting_rule() throws Exception { + + Component mockComponent = mock(Component.class); + + DefaultHighlightable highlightable = new DefaultHighlightable(mockComponent); + highlightable.highlightText(1, 10, HighlightableTextType.KEYWORD); + + assertThat(highlightable.getHighlightingRules().getSyntaxHighlightingRuleSet()).hasSize(1); + } + + @Test + public void should_reject_any_call_to_component() throws Exception { + + Component mockComponent = mock(Component.class); + + throwable.expect(UnsupportedOperationException.class); + + DefaultHighlightable highlightable = new DefaultHighlightable(mockComponent); + highlightable.component(); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/source/HighlightableBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/source/HighlightableBuilderTest.java new file mode 100644 index 00000000000..427feb7ce9e --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/source/HighlightableBuilderTest.java @@ -0,0 +1,41 @@ +/* + * 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.source; + +import org.junit.Test; +import org.sonar.api.component.Component; +import org.sonar.api.scan.source.Highlightable; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class HighlightableBuilderTest { + + @Test + public void should_load_default_perspective() throws Exception { + + Component mockComponent = mock(Component.class); + + HighlightableBuilder builder = new HighlightableBuilder(); + Highlightable perspective = builder.loadPerspective(Highlightable.class, mockComponent); + + assertThat(perspective).isInstanceOf(DefaultHighlightable.class); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/test/TestPlanBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/test/TestPlanBuilderTest.java index fa493c879f0..4c03a6f457e 100644 --- a/sonar-core/src/test/java/org/sonar/core/test/TestPlanBuilderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/test/TestPlanBuilderTest.java @@ -30,15 +30,17 @@ import static org.fest.assertions.Assertions.assertThat; public class TestPlanBuilderTest { @Test public void test_path() { - TestPlanBuilder builder = new TestPlanBuilder(); + + ScanGraph graph = ScanGraph.create(); + TestPlanBuilder builder = new TestPlanBuilder(graph); assertThat(builder.path().getElements()).isNotEmpty(); } @Test public void should_not_load_missing_perspective() { - TestPlanBuilder builder = new TestPlanBuilder(); ScanGraph graph = ScanGraph.create(); + TestPlanBuilder builder = new TestPlanBuilder(graph); ComponentVertex file = graph.addComponent(MockSourceFile.createMain("org.foo.Bar")); assertThat(builder.load(file)).isNull(); @@ -46,8 +48,8 @@ public class TestPlanBuilderTest { @Test public void should_create_perspective() { - TestPlanBuilder builder = new TestPlanBuilder(); ScanGraph graph = ScanGraph.create(); + TestPlanBuilder builder = new TestPlanBuilder(graph); ComponentVertex file = graph.addComponent(MockSourceFile.createMain("org.foo.Bar")); MutableTestPlan plan = builder.create(file); diff --git a/sonar-core/src/test/java/org/sonar/core/test/TestableBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/test/TestableBuilderTest.java index fa8eed08924..a21be60aad7 100644 --- a/sonar-core/src/test/java/org/sonar/core/test/TestableBuilderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/test/TestableBuilderTest.java @@ -30,15 +30,16 @@ import static org.fest.assertions.Assertions.assertThat; public class TestableBuilderTest { @Test public void test_path() { - TestableBuilder builder = new TestableBuilder(); + ScanGraph graph = ScanGraph.create(); + TestableBuilder builder = new TestableBuilder(graph); assertThat(builder.path().getElements()).isNotEmpty(); } @Test public void should_not_load_missing_perspective() { - TestableBuilder builder = new TestableBuilder(); ScanGraph graph = ScanGraph.create(); + TestableBuilder builder = new TestableBuilder(graph); ComponentVertex file = graph.addComponent(MockSourceFile.createMain("org.foo.Bar")); assertThat(builder.load(file)).isNull(); @@ -46,8 +47,8 @@ public class TestableBuilderTest { @Test public void should_create_perspective() { - TestableBuilder builder = new TestableBuilder(); ScanGraph graph = ScanGraph.create(); + TestableBuilder builder = new TestableBuilder(graph); ComponentVertex file = graph.addComponent(MockSourceFile.createMain("org.foo.Bar")); MutableTestable testable = builder.create(file); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/Highlightable.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/Highlightable.java new file mode 100644 index 00000000000..ee1eaeb8191 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/Highlightable.java @@ -0,0 +1,27 @@ +/* + * 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.api.scan.source; + +import org.sonar.api.component.Perspective; + +public interface Highlightable extends Perspective { + + SyntaxHighlightingRuleSet.Builder highlightText(int startOffset, int endOffset, String typeOfText); +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/HighlightableTextType.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/HighlightableTextType.java new file mode 100644 index 00000000000..5179c27cb82 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/HighlightableTextType.java @@ -0,0 +1,39 @@ +/* + * 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.api.scan.source; + +import com.google.common.collect.ImmutableList; + +public final class HighlightableTextType { + + public static final String ANNOTATION = "a"; + public static final String LITERAL = "s"; + public static final String LINE_COMMENT = "cd"; + public static final String BLOCK_COMMENT = "cppd"; + public static final String CONSTANT = "c"; + public static final String KEYWORD = "k"; + + private static final ImmutableList SUPPORTED_TEXT_TYPES = ImmutableList.of( + ANNOTATION, LITERAL, LINE_COMMENT, BLOCK_COMMENT, CONSTANT, KEYWORD); + + public static boolean supports(String textType) { + return SUPPORTED_TEXT_TYPES.contains(textType); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRule.java new file mode 100644 index 00000000000..d7029412529 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRule.java @@ -0,0 +1,49 @@ +/* + * 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.api.scan.source; + +public class SyntaxHighlightingRule { + + private final int startPosition; + private final int endPosition; + private final String decorableCodePart; + + private SyntaxHighlightingRule(int startPosition, int endPosition, String textType) { + this.startPosition = startPosition; + this.endPosition = endPosition; + this.decorableCodePart = textType; + } + + public static SyntaxHighlightingRule create(int startPosition, int endPosition, String textType) { + return new SyntaxHighlightingRule(startPosition, endPosition, textType); + } + + public int getStartPosition() { + return startPosition; + } + + public int getEndPosition() { + return endPosition; + } + + public String getDecorableCodePart() { + return decorableCodePart; + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSet.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSet.java new file mode 100644 index 00000000000..d5efca127c3 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSet.java @@ -0,0 +1,63 @@ +/* + * 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.api.scan.source; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.utils.SonarException; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +public class SyntaxHighlightingRuleSet { + + private ImmutableList syntaxHighlightingRuleSet; + + private SyntaxHighlightingRuleSet(ImmutableList syntaxHighlightingRules) { + syntaxHighlightingRuleSet = syntaxHighlightingRules; + } + + public static class Builder { + + private List syntaxHighlightingRuleSet; + + public Builder() { + syntaxHighlightingRuleSet = newArrayList(); + } + + public Builder registerHighlightingRule(int startOffset, int endOffset, String typeOfText) { + if (HighlightableTextType.supports(typeOfText)) { + SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(startOffset, endOffset, + typeOfText); + this.syntaxHighlightingRuleSet.add(syntaxHighlightingRule); + return this; + } + throw new SonarException("Unsupported text type : " + typeOfText); + } + + public SyntaxHighlightingRuleSet build() { + return new SyntaxHighlightingRuleSet(ImmutableList.copyOf(syntaxHighlightingRuleSet)); + } + } + + public ImmutableList getSyntaxHighlightingRuleSet() { + return syntaxHighlightingRuleSet; + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSetTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSetTest.java new file mode 100644 index 00000000000..c5ad8b967bd --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/scan/source/SyntaxHighlightingRuleSetTest.java @@ -0,0 +1,53 @@ +/* + * 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.api.scan.source; + + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.SonarException; + +import static org.fest.assertions.Assertions.assertThat; + +public class SyntaxHighlightingRuleSetTest { + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Test + public void should_register_supported_highlighting_rule() throws Exception { + + SyntaxHighlightingRuleSet.Builder highlightingRuleSet = new SyntaxHighlightingRuleSet.Builder(); + highlightingRuleSet.registerHighlightingRule(1, 10, HighlightableTextType.LINE_COMMENT); + highlightingRuleSet.registerHighlightingRule(1, 10, HighlightableTextType.LINE_COMMENT); + + assertThat(highlightingRuleSet.build().getSyntaxHighlightingRuleSet()).hasSize(2); + } + + @Test + public void should_reject_unsupported_highlighting_rule() throws Exception { + + throwable.expect(SonarException.class); + + SyntaxHighlightingRuleSet.Builder highlightingRuleSet = new SyntaxHighlightingRuleSet.Builder(); + highlightingRuleSet.registerHighlightingRule(1, 10, "UnsupportedTextType"); + } +} -- 2.39.5