From 257aa39c185dd03fe7b7e2a144e2c2677ccb5334 Mon Sep 17 00:00:00 2001 From: taba90 <46672505+taba90@users.noreply.github.com> Date: Fri, 16 Apr 2021 12:58:52 +0200 Subject: [PATCH 1/3] [GEOS-10020] Test for GEOT-6871 and increase test coverage for NumberMatched in wfs when using AppSchema (#4973) * [GEOS-10020] Test for GEOT-6871 and increase test coverage for NumberMatched in wfs when using AppSchema * review feedback --- .../app-schema-postgis-test/pom.xml | 437 +++++++++--------- .../app-schema/app-schema-test/pom.xml | 4 +- ...atureNumberMatchedFeatureChainingTest.java | 46 -- .../test/GetFeatureNumberMatchedGMLTest.java | 207 +++++++++ .../GetFeatureNumberMatchedGeoJSONTest.java | 127 +++++ .../test/GetFeaturesNumberMatchedTest.java | 111 ----- .../org/geoserver/test/IdFunctionWfsTest.java | 8 +- 7 files changed, 557 insertions(+), 383 deletions(-) delete mode 100644 src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedFeatureChainingTest.java create mode 100644 src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGMLTest.java create mode 100644 src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGeoJSONTest.java delete mode 100644 src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeaturesNumberMatchedTest.java diff --git a/src/extension/app-schema/app-schema-postgis-test/pom.xml b/src/extension/app-schema/app-schema-postgis-test/pom.xml index b97feb05c66..0a5994c3348 100644 --- a/src/extension/app-schema/app-schema-postgis-test/pom.xml +++ b/src/extension/app-schema/app-schema-postgis-test/pom.xml @@ -4,240 +4,239 @@ This code is licensed under the GPL 2.0 license, available at the root application directory. --> - + - 4.0.0 - - - org.geoserver.extension - gs-app-schema - 2.20-SNAPSHOT - + 4.0.0 + org.geoserver.extension - gs-app-schema-postgis-test - Application Schema Integration Online Test with Postgis Database + gs-app-schema + 2.20-SNAPSHOT + + + org.geoserver.extension + gs-app-schema-postgis-test + Application Schema Integration Online Test with Postgis Database - - - org.geoserver.extension - gs-app-schema-core - ${gs.version} - - - org.geoserver - gs-main - - - org.geoserver - gs-main - tests - - - org.geoserver - gs-kml - test - - - - org.geoserver - gs-wfs - - - - org.geoserver - gs-wms - - - net.sf.opencsv - opencsv - 1.8 - test - - - org.geoserver - gs-restconfig - ${project.version} - test - - - org.geoserver - gs-restconfig - ${project.version} - tests - test - - - org.springframework - spring-test - test - - - xmlunit - xmlunit - test - - - org.geotools - gt-app-schema - ${gt.version} - - - org.geotools - gt-app-schema - ${gt.version} - tests - test - - - - org.geotools.schemas - geosciml-2.0 - 2.0.2-4 - test - - - org.geotools.schemas - earthresourceml-1.1 - 1.1.0-3 - test - - - org.geotools.schemas - wfs-1.1 - 1.1.2-2 - test - - - org.geotools - gt-sample-data - ${gt.version} - test - - - org.geotools - gt-jdbc - ${gt.version} - test-jar - test - - - org.geotools.jdbc - gt-jdbc-postgis - ${gt.version} - test - - - org.geotools.jdbc - gt-jdbc-oracle - ${gt.version} - test - - - org.geotools.schemas - geosciml-3.0-seegrid - 3.0.0-1 - test - - - org.geotools.schemas - geosciml-3.2 - 3.2.0-1 - test - - - org.geotools.schemas - wfs-2.0 - 2.0.0-2 - test - - - org.geotools.schemas - samplingSpecimen-2.0 - 2.0.0-1 - test - - - com.fasterxml.jackson.core - jackson-core - test - - - com.fasterxml.jackson.core - jackson-annotations - test - - - com.fasterxml.jackson.core - jackson-databind - test - - - - org.geoserver.web - gs-web-core - ${project.version} - tests - test - - - org.geoserver.web - gs-web-demo - ${project.version} - test - - - org.geoserver.web - gs-web-demo - ${project.version} - tests - test - - + + org.geotools.schemas + geosciml-2.0 + 2.0.2-4 + test + + + org.geotools.schemas + earthresourceml-1.1 + 1.1.0-3 + test + + + org.geotools.schemas + wfs-1.1 + 1.1.2-2 + test + + + org.geotools + gt-sample-data + ${gt.version} + test + + + org.geotools + gt-jdbc + ${gt.version} + test-jar + test + + + org.geotools.jdbc + gt-jdbc-postgis + ${gt.version} + test + + + org.geotools.jdbc + gt-jdbc-oracle + ${gt.version} + test + + + org.geotools.schemas + geosciml-3.0-seegrid + 3.0.0-1 + test + + + org.geotools.schemas + geosciml-3.2 + 3.2.0-1 + test + + + org.geotools.schemas + wfs-2.0 + 2.0.0-2 + test + + + org.geotools.schemas + samplingSpecimen-2.0 + 2.0.0-1 + test + + + com.fasterxml.jackson.core + jackson-core + test + + + com.fasterxml.jackson.core + jackson-annotations + test + + + com.fasterxml.jackson.core + jackson-databind + test + + + + org.geoserver.web + gs-web-core + ${project.version} + tests + test + + + org.geoserver.web + gs-web-demo + ${project.version} + test + + + org.geoserver.web + gs-web-demo + ${project.version} + tests + test + + - - ${app-schema-test-dir}/src/test/java - - - org.apache.maven.plugins - maven-surefire-plugin - - - - **/onlineTest/*.java - **/DefaultGeometryTest.java - ${test.exclude.pattern} - - -Xmx${test.maxHeapSize} -enableassertions ${jvm.opts} + + ${app-schema-test-dir}/src/test/java + + + ${app-schema-test-dir}/src/test/resources + + **/*.properties + **/*.xml + **/*.xsd + **/*.sql + **/*.sld + **/*.png + **/*.json + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + **/onlineTest/*.java + **/DefaultGeometryTest.java + ${test.exclude.pattern} + + -Xmx${test.maxHeapSize} -enableassertions ${jvm.opts} -Djava.awt.headless=${java.awt.headless} -DquietTests=${quietTests} -Dapp-schema.joining=true -DtestDatabase=postgis - - - - - - ${app-schema-test-dir}/src/test/resources - - **/*.properties - **/*.xml - **/*.xsd - **/*.sql - **/*.sld - **/*.png - **/*.json - - - - + + + + diff --git a/src/extension/app-schema/app-schema-test/pom.xml b/src/extension/app-schema/app-schema-test/pom.xml index c7b6b22b782..244632b3c1e 100644 --- a/src/extension/app-schema/app-schema-test/pom.xml +++ b/src/extension/app-schema/app-schema-test/pom.xml @@ -300,8 +300,8 @@ **/IdFunctionWfsWithJoiningTest.java **/XPathPredicateTest.java ${test.exclude.pattern} - **/GetFeaturesNumberMatchedTest.java - **/GetFeatureNumberMatchedFeatureChainingTest.java + **/GetFeatureNumberMatchedGMLTest.java + **/GetFeatureNumberMatchedGeoJSONTest.java **/FeatureChainingWfsTest.java **/NoIdExpressionTest.java diff --git a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedFeatureChainingTest.java b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedFeatureChainingTest.java deleted file mode 100644 index 4cca97210cc..00000000000 --- a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedFeatureChainingTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.geoserver.test; - -import static org.junit.Assert.assertEquals; - -import net.sf.json.JSON; -import net.sf.json.JSONObject; -import org.junit.Test; - -public class GetFeatureNumberMatchedFeatureChainingTest extends AbstractAppSchemaTestSupport { - @Override - protected AbstractAppSchemaMockData createTestData() { - return new FeatureChainingMockData(); - } - - @Test - public void testGetFeatureNumberMatchedWithAndNestedFilterOnDifferentTypes() throws Exception { - - JSON json = - getAsJSON( - "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" - + "&cql_filter= gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" - + "OR gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'"); - - JSONObject resp = (JSONObject) json; - int numberMatched = resp.getInt("numberMatched"); - int numberReturned = resp.getInt("numberReturned"); - assertEquals(3, numberMatched); - assertEquals(3, numberReturned); - } - - @Test - public void testGetFeatureNumberMatchedWithAndNestedFilterOnSameTypes() throws Exception { - - JSON json = - getAsJSON( - "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" - + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" - + "AND gsml:specification.gsml:GeologicUnit.gml:name = 'New Group'"); - - JSONObject resp = (JSONObject) json; - int numberMatched = resp.getInt("numberMatched"); - int numberReturned = resp.getInt("numberReturned"); - assertEquals(1, numberMatched); - assertEquals(1, numberReturned); - } -} diff --git a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGMLTest.java b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGMLTest.java new file mode 100644 index 00000000000..da8b9bf91af --- /dev/null +++ b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGMLTest.java @@ -0,0 +1,207 @@ +/* (c) 2014 Open Source Geospatial Foundation - all rights reserved + * (c) 2001 - 2013 OpenPlans + * This code is licensed under the GPL 2.0 license, available at the root + * application directory. + */ + +package org.geoserver.test; + +import org.junit.Test; +import org.w3c.dom.Document; + +/** + * Test the proper encoding of duplicated/repeated features with Ids + * + * @author Victor Tey, CSIRO Exploration and Mining + */ +public class GetFeatureNumberMatchedGMLTest extends AbstractAppSchemaTestSupport { + + @Override + protected FeatureGML32MockData createTestData() { + return new FeatureGML32MockData(); + } + + /** Tests that a count for All the features works * */ + @Test + public void testGetMappedFeatureHitsCount() { + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits"); + LOGGER.info("WFS GetFeature, typename=gsml:MappedFeature response:\n" + prettyString(doc)); + + assertNumberMathcedAndNumberReturned(doc, 5, 0); + } + + /** Test that count with a filter pointing to a root property works */ + @Test + public void testGetFeatureHitsCountWithFilterOnRootAttribute() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" + + "&cql_filter=gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + LOGGER.info(prettyString(doc)); + assertNumberMathcedAndNumberReturned(doc, 1, 0); + } + + /** Test that count with a filter pointing to a nested property works */ + @Test + public void testGetFeatureHitsCountWithFilterOnNestedAttribute() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" + + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'"); + LOGGER.info(prettyString(doc)); + assertNumberMathcedAndNumberReturned(doc, 1, 0); + } + + /** Test that count with a filter pointing to a nested property works */ + @Test + public void testGetFeatureHitsCountWithFilterOnNestedAttribute2() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" + + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); + LOGGER.info(prettyString(doc)); + + assertNumberMathcedAndNumberReturned(doc, 3, 0); + } + + @Test + public void testGetFeatureHitsCountWithFilterOnNestedAttributeWithMaxNumber() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" + + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27&count=1"); + LOGGER.info(prettyString(doc)); + assertNumberMathcedAndNumberReturned(doc, 3, 0); + } + + /** Test that count with a filter pointing to a nested property works */ + @Test + public void testGetFeatureNumberMatchedWithFilterOnNestedAttribute() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'"); + LOGGER.info(prettyString(doc)); + + assertNumberMathcedAndNumberReturned(doc, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithFilterOnNestedAttribute2() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); + LOGGER.info(prettyString(doc)); + + assertNumberMathcedAndNumberReturned(doc, 3, 3); + } + + @Test + public void testGetFeatureNumberMatchedWithAndNestedFilterOnSameTypes() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" + + "AND gsml:specification.gsml:GeologicUnit.gml:name = 'New Group'"); + assertNumberMathcedAndNumberReturned(doc, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithComplexPropertyORSimpleProperty() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27" + + " OR gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMathcedAndNumberReturned(doc, 4, 4); + } + + @Test + public void testGetFeatureNumberMatchedWithSimplePropertyANDComplexProperty() throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" + + " AND gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMathcedAndNumberReturned(doc, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithComplexPropertyORSimplePropertyWithPagination() + throws Exception { + + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27" + + " OR gsml:MappedFeature.gml:name = 'MURRADUC BASALT'&startIndex=3&count=2"); + + assertNumberMathcedAndNumberReturned(doc, 4, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithMultipleAND() throws Exception { + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:name = 'New Group'" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%25%27 AND gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMathcedAndNumberReturned(doc, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilter() throws Exception { + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); + + assertNumberMathcedAndNumberReturned(doc, 3, 3); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilterWithPagination() throws Exception { + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27&startIndex=1"); + + assertNumberMathcedAndNumberReturned(doc, 3, 2); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilterManyAND() throws Exception { + Document doc = + getAsDOM( + "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27 AND gsml:MappedFeature.gml:name = 'GUNTHORPE FORMATION'"); + + assertNumberMathcedAndNumberReturned(doc, 1, 1); + } + + private void assertNumberMathcedAndNumberReturned( + Document doc, int numberMatched, int numberReturned) { + assertXpathEvaluatesTo( + String.valueOf(numberMatched), "/wfs:FeatureCollection/@numberMatched", doc); + assertXpathEvaluatesTo( + String.valueOf(numberReturned), "/wfs:FeatureCollection/@numberReturned", doc); + } +} diff --git a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGeoJSONTest.java b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGeoJSONTest.java new file mode 100644 index 00000000000..9bd30ab2e68 --- /dev/null +++ b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeatureNumberMatchedGeoJSONTest.java @@ -0,0 +1,127 @@ +package org.geoserver.test; + +import static org.junit.Assert.assertEquals; + +import net.sf.json.JSON; +import net.sf.json.JSONObject; +import org.junit.Test; + +public class GetFeatureNumberMatchedGeoJSONTest extends AbstractAppSchemaTestSupport { + @Override + protected AbstractAppSchemaMockData createTestData() { + return new FeatureChainingMockData(); + } + + @Test + public void testGetFeatureNumberMatchedWithAndNestedFilterOnDifferentTypes() throws Exception { + + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter= gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" + + "OR gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'"); + + assertNumberMatchedAndNumberReturned(json, 3, 3); + } + + @Test + public void testGetFeatureNumberMatchedWithAndNestedFilterOnSameTypes() throws Exception { + + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'" + + "AND gsml:specification.gsml:GeologicUnit.gml:name = 'New Group'"); + + assertNumberMatchedAndNumberReturned(json, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithComplexPropertyORSimpleProperty() throws Exception { + + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'" + + " OR gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMatchedAndNumberReturned(json, 3, 3); + } + + @Test + public void testGetFeatureNumberMatchedWithSimplePropertyANDComplexProperty() throws Exception { + + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'" + + " AND gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMatchedAndNumberReturned(json, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithComplexPropertyORSimplePropertyWithPagination() + throws Exception { + + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'" + + " OR gsml:MappedFeature.gml:name = 'MURRADUC BASALT'&startIndex=2"); + + assertNumberMatchedAndNumberReturned(json, 3, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithMultipleAND() throws Exception { + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter=gsml:specification.gsml:GeologicUnit.gsml:composition.gsml:CompositionPart.gsml:proportion.gsml:CGI_TermValue.gsml:value = 'significant'" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%25%27 AND gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); + + assertNumberMatchedAndNumberReturned(json, 1, 1); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilter() throws Exception { + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); + + assertNumberMatchedAndNumberReturned(json, 3, 3); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilterWithPagination() throws Exception { + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27&startIndex=1"); + + assertNumberMatchedAndNumberReturned(json, 3, 2); + } + + @Test + public void testGetFeatureNumberMatchedWithGeomComplexFilterManyAND() throws Exception { + JSON json = + getAsJSON( + "ows?service=WFS&outputFormat=application/json&version=1.1.0&request=GetFeature&typeName=gsml:MappedFeature" + + "&cql_filter= intersects(gsml:shape, buffer(POLYGON((-1.3 52.5,-1.3 52.6,-1.2 52.6,-1.2 52.5,-1.3 52.5)),100))" + + " AND gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27 AND gsml:MappedFeature.gml:name = 'GUNTHORPE FORMATION'"); + assertNumberMatchedAndNumberReturned(json, 1, 1); + } + + private void assertNumberMatchedAndNumberReturned( + JSON resp, int numberMatched, int numberReturned) { + JSONObject jsonObject = (JSONObject) resp; + int numberMatchedValue = jsonObject.getInt("numberMatched"); + int numberReturnedValue = jsonObject.getInt("numberReturned"); + assertEquals(numberMatched, numberMatchedValue); + assertEquals(numberReturned, numberReturnedValue); + } +} diff --git a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeaturesNumberMatchedTest.java b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeaturesNumberMatchedTest.java deleted file mode 100644 index 70ebbbe6fbd..00000000000 --- a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/GetFeaturesNumberMatchedTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* (c) 2014 Open Source Geospatial Foundation - all rights reserved - * (c) 2001 - 2013 OpenPlans - * This code is licensed under the GPL 2.0 license, available at the root - * application directory. - */ - -package org.geoserver.test; - -import org.junit.Test; -import org.w3c.dom.Document; - -/** - * Test the proper encoding of duplicated/repeated features with Ids - * - * @author Victor Tey, CSIRO Exploration and Mining - */ -public class GetFeaturesNumberMatchedTest extends AbstractAppSchemaTestSupport { - - @Override - protected FeatureGML32MockData createTestData() { - return new FeatureGML32MockData(); - } - - /** Tests that a count for All the features works * */ - @Test - public void testGetMappedFeatureHitsCount() { - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits"); - LOGGER.info("WFS GetFeature, typename=gsml:MappedFeature response:\n" + prettyString(doc)); - assertXpathEvaluatesTo("4", "/wfs:FeatureCollection/@numberMatched", doc); - } - - /** Test that count with a filter pointing to a root property works */ - @Test - public void testGetFeatureHitsCountWithFilterOnRootAttribute() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" - + "&cql_filter=gsml:MappedFeature.gml:name = 'MURRADUC BASALT'"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("1", "/wfs:FeatureCollection/@numberMatched", doc); - } - - /** Test that count with a filter pointing to a nested property works */ - @Test - public void testGetFeatureHitsCountWithFilterOnNestedAttribute() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" - + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("1", "/wfs:FeatureCollection/@numberMatched", doc); - } - - /** Test that count with a filter pointing to a nested property works */ - @Test - public void testGetFeatureHitsCountWithFilterOnNestedAttribute2() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" - + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("3", "/wfs:FeatureCollection/@numberMatched", doc); - } - - @Test - public void testGetFeatureHitsCountWithFilterOnNestedAttributeWithMaxNumber() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml3&request=GetFeature&typeNames=gsml:MappedFeature&resulttype=hits" - + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27&count=1"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("3", "/wfs:FeatureCollection/@numberMatched", doc); - } - - /** Test that count with a filter pointing to a nested property works */ - @Test - public void testGetFeatureNumberMatchedWithFilterOnNestedAttribute() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" - + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description = 'Olivine basalt'"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("1", "/wfs:FeatureCollection/@numberMatched", doc); - assertXpathEvaluatesTo("1", "/wfs:FeatureCollection/@numberReturned", doc); - } - - @Test - public void testGetFeatureNumberMatchedWithFilterOnNestedAttribute2() throws Exception { - - Document doc = - getAsDOM( - "ows?service=WFS&version=2.0.0&outputFormat=gml32&request=GetFeature&typeNames=gsml:MappedFeature" - + "&cql_filter=gsml:MappedFeature.gsml:specification.gsml:GeologicUnit.gml:description LIKE %27%25Olivine%20basalt%2C%20tuff%25%27"); - LOGGER.info(prettyString(doc)); - - assertXpathEvaluatesTo("3", "/wfs:FeatureCollection/@numberMatched", doc); - assertXpathEvaluatesTo("3", "/wfs:FeatureCollection/@numberReturned", doc); - } -} diff --git a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/IdFunctionWfsTest.java b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/IdFunctionWfsTest.java index f954a1e4ec1..37c6064c2d0 100644 --- a/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/IdFunctionWfsTest.java +++ b/src/extension/app-schema/app-schema-test/src/test/java/org/geoserver/test/IdFunctionWfsTest.java @@ -72,12 +72,10 @@ public void testGetFeature() { /** Test content of GetFeature response. */ @Test public void testGetFeatureContent() throws Exception { - Document doc = - getAsDOM( - "wfs?request=GetFeature&version=1.1.0&typename=gsml:MappedFeature&featureID=mf1,mf2,mf3,mf4"); + Document doc = getAsDOM("wfs?request=GetFeature&version=1.1.0&typename=gsml:MappedFeature"); LOGGER.info("WFS GetFeature&typename=gsml:MappedFeature response:\n" + prettyString(doc)); - assertXpathEvaluatesTo("4", "/wfs:FeatureCollection/@numberOfFeatures", doc); - assertXpathCount(4, "//gsml:MappedFeature", doc); + assertXpathEvaluatesTo("5", "/wfs:FeatureCollection/@numberOfFeatures", doc); + assertXpathCount(5, "//gsml:MappedFeature", doc); // mf1 { From 3f9a2a315516daeb719bfbba39b3957bba1f98f4 Mon Sep 17 00:00:00 2001 From: taba90 <46672505+taba90@users.noreply.github.com> Date: Fri, 16 Apr 2021 14:45:56 +0200 Subject: [PATCH 2/3] [GEOS-10012] Support inclusion vendor options to disable Style elements when rendering legends (#4950) * [GEOS-10012] Support inclusion vendor options to disable Style elements when rendering legends * review feedback --- .../source/styling/sld/extensions/index.rst | 1 + .../sld/extensions/rendering-selection.rst | 311 ++++++++++++++++++ .../BufferedImageLegendGraphicBuilder.java | 1 + .../JSONLegendGraphicBuilder.java | 1 + .../legendgraphic/LegendGraphicBuilder.java | 16 + .../org/geoserver/wms/WMSTestSupport.java | 22 +- .../wms/legendgraphic/BaseLegendTest.java | 2 + ...redImageLegendGraphicOutputFormatTest.java | 49 +++ .../JSONLegendGraphicOutputFormatTest.java | 60 ++++ .../wms/wms_1_1_1/GetMapIntegrationTest.java | 75 +++++ .../results/renderingSelectionOnRule.png | Bin 0 -> 87 bytes .../renderingSelectionOnSymbolizer.png | Bin 0 -> 115 bytes .../styleWithLegendSelection.sld | 76 +++++ .../styleWithLegendSelectionOnSymbolizer.sld | 86 +++++ .../wms/wms_1_1_1/LakesRenderingSelection.sld | 70 ++++ .../NamedPlacesRenderingSelection.sld | 98 ++++++ .../wms/wms_1_1_1/renderingSelectionLakes.png | Bin 0 -> 2364 bytes .../renderingSelectionNamedPlaces.png | Bin 0 -> 1164 bytes 18 files changed, 864 insertions(+), 4 deletions(-) create mode 100644 doc/en/user/source/styling/sld/extensions/rendering-selection.rst create mode 100644 src/wms/src/test/resources/org/geoserver/wms/legendgraphic/results/renderingSelectionOnRule.png create mode 100644 src/wms/src/test/resources/org/geoserver/wms/legendgraphic/results/renderingSelectionOnSymbolizer.png create mode 100644 src/wms/src/test/resources/org/geoserver/wms/legendgraphic/styleWithLegendSelection.sld create mode 100644 src/wms/src/test/resources/org/geoserver/wms/legendgraphic/styleWithLegendSelectionOnSymbolizer.sld create mode 100644 src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/LakesRenderingSelection.sld create mode 100644 src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/NamedPlacesRenderingSelection.sld create mode 100644 src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionLakes.png create mode 100644 src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionNamedPlaces.png diff --git a/doc/en/user/source/styling/sld/extensions/index.rst b/doc/en/user/source/styling/sld/extensions/index.rst index 43913e4e4a0..20c453bc541 100644 --- a/doc/en/user/source/styling/sld/extensions/index.rst +++ b/doc/en/user/source/styling/sld/extensions/index.rst @@ -19,3 +19,4 @@ Although not portable to other applications, these extensions make styling more randomized composite-blend/index z-order/index + rendering-selection diff --git a/doc/en/user/source/styling/sld/extensions/rendering-selection.rst b/doc/en/user/source/styling/sld/extensions/rendering-selection.rst new file mode 100644 index 00000000000..cfa542d590b --- /dev/null +++ b/doc/en/user/source/styling/sld/extensions/rendering-selection.rst @@ -0,0 +1,311 @@ +.. _rendering_selection: + +Rendering Selection +==================== + +GeoServer provides a ``VendorOption`` to define whether a particular element ``Rule``, ``FeatureTypeStyle`` or ``Symbolizer`` should be applied to a ``getLegendGraphic`` output or to a ``getMap`` output. + +This allows to generate legends from the SLD that can be better looking and more expressive, without the underlying complexity of the actual rendered style. Other systems have a dedicated language to build legends instead. The advantage of using the same language is that dynamic behaviors, like rule removal based on the area being rendered, can be easily retained. + +The vendor option is named ``inclusion``, e.g.: + +* legendOnly + +* mapOnly + +Valid values are: + +* ``legendOnly`` the element will be skipped when applying the style to the data to render map. +* ``mapOnly`` the element will be skipped when applying the style to the data to render legend. +* ``normal`` will have the same effect then omitting the VendorOption: the SLD element will be used for both map and legend (same effect as not specifying the vendor option). + + +Take as an example the following style: for each Rule two symbolizers are defined one that will be skipped when rendering the legend and one that will be skipped when rendering the map and loads the legend icon from an external svg file. + +.. code-block:: xml + + + + + Style example + + + + + + numericValue + 90 + + + + + + circle + + 0xFF0000 + + + 32 + + mapOnly + + + + + + image/svg+xml + + 20 + + legendOnly + + + + + + + numericValue + 90 + + + numericValue + 180 + + + + + + + circle + + #6495ED + + + 32 + + mapOnly + + + + + + image/svg+xml + + 20 + + legendOnly + + + + + + + + +The same result could have been obtained by defining each rule two time each one with a single symbolizer, and defining the vendor options at the rule level. + +.. code-block:: xml + + + + + Style example + + + + + + numericValue + 90 + + + + + + circle + + 0xFF0000 + + + 32 + + + mapOnly + + + + + + numericValue + 90 + + + numericValue + 180 + + + + + + + circle + + #6495ED + + + 32 + + mapOnly + + + + + + numericValue + 90 + + + + + + + image/svg+xml + + 20 + + legendOnly + + + + + + + numericValue + 90 + + + numericValue + 180 + + + + + + + + image/svg+xml + + 20 + + legendOnly + + + + + + + + + +A third way to obtain the same result could be to define vendor options at the FeatureTypeStyle level. + +.. code-block:: xml + + + + + Style example + + + + + + numericValue + 90 + + + + + + circle + + 0xFF0000 + + + 32 + + + + + + + + numericValue + 90 + + + numericValue + 180 + + + + + + + circle + + #6495ED + + + 32 + + + + mapOnly + + + + + + numericValue + 90 + + + + + + + image/svg+xml + + 20 + + + + + + + + numericValue + 90 + + + numericValue + 180 + + + + + + + + image/svg+xml + + 20 + + + + legendOnly + + + + diff --git a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicBuilder.java b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicBuilder.java index eef95a47c34..e53e80ec8b3 100644 --- a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicBuilder.java +++ b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicBuilder.java @@ -135,6 +135,7 @@ public BufferedImage buildLegendGraphic(GetLegendGraphicRequest request) throw new NullPointerException("request.getStyle()"); } + gt2Style = applyRenderingSelection(gt2Style); // get rule corresponding to the layer index // normalize to null for NO RULE String ruleName = legend.getRule(); // was null diff --git a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicBuilder.java b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicBuilder.java index f2ca598d020..d7628277547 100644 --- a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicBuilder.java +++ b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicBuilder.java @@ -269,6 +269,7 @@ public JSONObject buildLegendGraphic(GetLegendGraphicRequest request) { FeatureType layer = legend.getFeatureType(); Style gt2Style = legend.getStyle(); + gt2Style = applyRenderingSelection(gt2Style); if (gt2Style == null) { throw new NullPointerException("request.getStyle()"); } diff --git a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/LegendGraphicBuilder.java b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/LegendGraphicBuilder.java index acad8ec2e6d..42ecebf85c9 100644 --- a/src/wms/src/main/java/org/geoserver/wms/legendgraphic/LegendGraphicBuilder.java +++ b/src/wms/src/main/java/org/geoserver/wms/legendgraphic/LegendGraphicBuilder.java @@ -35,6 +35,8 @@ import org.geotools.styling.Symbolizer; import org.geotools.styling.TextSymbolizer; import org.geotools.styling.visitor.DpiRescaleStyleVisitor; +import org.geotools.styling.visitor.LegendRenderingSelectorStyleVisitor; +import org.geotools.styling.visitor.RenderingSelectorStyleVisitor; import org.geotools.styling.visitor.RescaleStyleVisitor; import org.geotools.styling.visitor.UomRescaleStyleVisitor; import org.locationtech.jts.geom.Coordinate; @@ -509,4 +511,18 @@ protected void checkForRenderingTransformations(Style gt2Style) { } } } + + /** + * Checks if any false is present in the + * style removing style's elements not meant to be applied to the legend. + * + * @param style the style being used to build the legend + * @return the style without the element not meant to be applied to obtain the legend output + */ + protected Style applyRenderingSelection(Style style) { + RenderingSelectorStyleVisitor renderingSelectorStyleVisitor = + new LegendRenderingSelectorStyleVisitor(); + style.accept(renderingSelectorStyleVisitor); + return (Style) renderingSelectorStyleVisitor.getCopy(); + } } diff --git a/src/wms/src/test/java/org/geoserver/wms/WMSTestSupport.java b/src/wms/src/test/java/org/geoserver/wms/WMSTestSupport.java index 745be2d1ecf..1a599fef3be 100644 --- a/src/wms/src/test/java/org/geoserver/wms/WMSTestSupport.java +++ b/src/wms/src/test/java/org/geoserver/wms/WMSTestSupport.java @@ -46,6 +46,7 @@ import org.geoserver.catalog.LayerGroupInfo.Mode; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.ResourceInfo; +import org.geoserver.catalog.StyleInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.data.test.TestData; @@ -460,12 +461,22 @@ protected void setupTemplate(QName featureTypeName, String template, String body protected LayerGroupInfo createLakesPlacesLayerGroup( Catalog catalog, LayerGroupInfo.Mode mode, LayerInfo rootLayer) throws Exception { - return createLakesPlacesLayerGroup(catalog, "lakes_and_places", mode, rootLayer); + return createLakesPlacesLayerGroup(catalog, "lakes_and_places", mode, rootLayer, null); } protected LayerGroupInfo createLakesPlacesLayerGroup( Catalog catalog, String name, LayerGroupInfo.Mode mode, LayerInfo rootLayer) throws Exception { + return createLakesPlacesLayerGroup(catalog, name, mode, rootLayer, null); + } + + protected LayerGroupInfo createLakesPlacesLayerGroup( + Catalog catalog, + String name, + LayerGroupInfo.Mode mode, + LayerInfo rootLayer, + List styleInfos) + throws Exception { LayerInfo lakes = catalog.getLayerByName(getLayerId(MockData.LAKES)); LayerInfo places = catalog.getLayerByName(getLayerId(MockData.NAMED_PLACES)); @@ -480,9 +491,12 @@ protected LayerGroupInfo createLakesPlacesLayerGroup( group.getLayers().add(lakes); group.getLayers().add(places); - group.getStyles().add(null); - group.getStyles().add(null); - + if (styleInfos == null) { + group.getStyles().add(null); + group.getStyles().add(null); + } else { + group.getStyles().addAll(styleInfos); + } CatalogBuilder cb = new CatalogBuilder(catalog); cb.calculateLayerGroupBounds(group); diff --git a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BaseLegendTest.java b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BaseLegendTest.java index 3b5436c8aba..73d50fd495d 100644 --- a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BaseLegendTest.java +++ b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BaseLegendTest.java @@ -47,6 +47,8 @@ protected void onSetUp(SystemTestData testData) throws Exception { testData.addStyle("rainfall_ramp", MockData.class, catalog); testData.addStyle("rainfall_classes", MockData.class, catalog); testData.addStyle("rainfall_classes_nolabels", MockData.class, catalog); + testData.addStyle("styleWithLegendSelection", this.getClass(), catalog); + testData.addStyle("styleWithLegendSelectionOnSymbolizer", this.getClass(), catalog); // add raster layer for rendering transform test testData.addRasterLayer( new QName("http://www.opengis.net/wcs/1.1.1", "DEM", "wcs"), diff --git a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicOutputFormatTest.java b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicOutputFormatTest.java index 9e6ce3b656c..bc9e2ffb1d4 100644 --- a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicOutputFormatTest.java +++ b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/BufferedImageLegendGraphicOutputFormatTest.java @@ -14,7 +14,9 @@ import java.awt.Color; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; +import java.io.File; import java.io.IOException; +import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -43,6 +45,7 @@ import org.geotools.feature.type.AttributeTypeImpl; import org.geotools.feature.type.GeometryDescriptorImpl; import org.geotools.feature.type.GeometryTypeImpl; +import org.geotools.image.test.ImageAssert; import org.geotools.image.util.ImageUtilities; import org.geotools.referencing.CRS; import org.geotools.renderer.lite.RendererUtilities; @@ -1454,6 +1457,52 @@ public void testScaleDPI() throws Exception { assertEquals(66, this.legendProducer.h); } + @org.junit.Test + public void testLegendRenderingSelectionInRule() throws Exception { + // test false set for rule + // works for a getLegendGraphicRequest + // only the yellow square should be displayed + GetLegendGraphicRequest req = new GetLegendGraphicRequest(null); + req.setWidth(20); + req.setHeight(20); + + FeatureTypeInfo ftInfo = + getCatalog() + .getFeatureTypeByName( + MockData.MPOLYGONS.getNamespaceURI(), + MockData.MPOLYGONS.getLocalPart()); + + req.setLayer(ftInfo.getFeatureType()); + req.setStyle(getCatalog().getStyleByName("styleWithLegendSelection").getStyle()); + + BufferedImage image = this.legendProducer.buildLegendGraphic(req); + URL result = getClass().getResource("./results/renderingSelectionOnRule.png"); + ImageAssert.assertEquals(new File(result.toURI()), image, 50); + } + + @org.junit.Test + public void testLegendRenderingSelectionInSymbolizer() throws Exception { + // test the false in a Symbolizer + // only the a blue square should be rendered + GetLegendGraphicRequest req = new GetLegendGraphicRequest(null); + req.setWidth(20); + req.setHeight(20); + + FeatureTypeInfo ftInfo = + getCatalog() + .getFeatureTypeByName( + MockData.MPOLYGONS.getNamespaceURI(), + MockData.MPOLYGONS.getLocalPart()); + + req.setLayer(ftInfo.getFeatureType()); + req.setStyle( + getCatalog().getStyleByName("styleWithLegendSelectionOnSymbolizer").getStyle()); + + BufferedImage image = this.legendProducer.buildLegendGraphic(req); + URL result = getClass().getResource("./results/renderingSelectionOnSymbolizer.png"); + ImageAssert.assertEquals(new File(result.toURI()), image, 50); + } + /** */ private Style readSLD(String sldName) throws IOException { StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory(null); diff --git a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicOutputFormatTest.java b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicOutputFormatTest.java index 783a913b5f4..a5a7719954a 100644 --- a/src/wms/src/test/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicOutputFormatTest.java +++ b/src/wms/src/test/java/org/geoserver/wms/legendgraphic/JSONLegendGraphicOutputFormatTest.java @@ -1662,6 +1662,66 @@ public void testDescreteRaster() throws Exception { assertEquals("intervals", colormap.get(JSONLegendGraphicBuilder.COLORMAP_TYPE)); } + + @org.junit.Test + public void testLegendSelectionInRule() throws Exception { + // test that the false works with the Json + // output + GetLegendGraphicRequest req = getRequest(); + req.setWidth(20); + req.setHeight(20); + + FeatureTypeInfo ftInfo = + getCatalog() + .getFeatureTypeByName( + MockData.MPOLYGONS.getNamespaceURI(), + MockData.MPOLYGONS.getLocalPart()); + + req.setLayer(ftInfo.getFeatureType()); + req.setStyle(getCatalog().getStyleByName("styleWithLegendSelection").getStyle()); + req.setFormat(JSONFormat); + JSONObject jsonLegend = this.legendProducer.buildLegendGraphic(req); + JSONArray legend = jsonLegend.getJSONArray(JSONLegendGraphicBuilder.LEGEND); + JSONArray rules = legend.getJSONObject(0).getJSONArray("rules"); + // only one rule should be included in the output the other one has the renderingLegend + // option set to false. + assertEquals(1, rules.size()); + String ruleName = rules.getJSONObject(0).getString("name"); + assertEquals("nationalpark", ruleName); + } + + @org.junit.Test + public void testLegendSelectionInSymbolizer() throws Exception { + // test that the false option set in + // symbolizer works + // avoiding the inclusion in the final output of one of the two symbolizers + GetLegendGraphicRequest req = getRequest(); + req.setWidth(20); + req.setHeight(20); + + FeatureTypeInfo ftInfo = + getCatalog() + .getFeatureTypeByName( + MockData.MPOLYGONS.getNamespaceURI(), + MockData.MPOLYGONS.getLocalPart()); + + req.setLayer(ftInfo.getFeatureType()); + req.setStyle( + getCatalog().getStyleByName("styleWithLegendSelectionOnSymbolizer").getStyle()); + req.setFormat(JSONFormat); + JSONObject jsonLegend = this.legendProducer.buildLegendGraphic(req); + JSONArray rules = + jsonLegend + .getJSONArray(JSONLegendGraphicBuilder.LEGEND) + .getJSONObject(0) + .getJSONArray("rules"); + assertEquals(1, rules.size()); + JSONArray symbolizers = rules.getJSONObject(0).getJSONArray("symbolizers"); + // only one symbolizer of the two defined should be present in the final output + // the other one has the renderingLabel option set to false + assertEquals(1, symbolizers.size()); + } + /** @param result */ private void assertNotEmpty(JSONObject result) { assertNotNull(result); diff --git a/src/wms/src/test/java/org/geoserver/wms/wms_1_1_1/GetMapIntegrationTest.java b/src/wms/src/test/java/org/geoserver/wms/wms_1_1_1/GetMapIntegrationTest.java index 9b3a722598e..56711150c2f 100644 --- a/src/wms/src/test/java/org/geoserver/wms/wms_1_1_1/GetMapIntegrationTest.java +++ b/src/wms/src/test/java/org/geoserver/wms/wms_1_1_1/GetMapIntegrationTest.java @@ -230,6 +230,15 @@ protected void onSetUp(SystemTestData testData) throws Exception { testData.addStyle( "transparencyFillWidth", "transparencyFillStyleWidth.sld", getClass(), catalog); + testData.addStyle( + "namedPlacesRenderingSelection", + "NamedPlacesRenderingSelection.sld", + getClass(), + catalog); + + testData.addStyle( + "lakesRenderingSelection", "LakesRenderingSelection.sld", getClass(), catalog); + Map properties = new HashMap<>(); properties.put(LayerProperty.STYLE, "raster"); testData.addRasterLayer( @@ -2292,4 +2301,70 @@ public void testTransparencyFillMosaicWithWidth() throws Exception { assertPixel(imageFill, i, 639, Color.RED); } } + + @Test + public void testNamedPlacesRenderingSelection() throws Exception { + // We have two set of rules in the style one for the map having + // test false + // and one for the legend having test + // false + // the final result obtained with a legend decorator should show + // polygons and legend icons with same colors but icons without black border + Catalog catalog = getCatalog(); + File layouts = getDataDirectory().findOrCreateDir("layouts"); + URL layout = GetMapIntegrationTest.class.getResource("../test-layout-legend-image.xml"); + FileUtils.copyURLToFile(layout, new File(layouts, "test-layout-legend-image.xml")); + LayerInfo places = catalog.getLayerByName(getLayerId(MockData.NAMED_PLACES)); + StyleInfo placesStyle = catalog.getStyleByName("namedPlacesRenderingSelection"); + LegendInfoImpl legend = new LegendInfoImpl(); + legend.setFormat("image/png;charset=utf-8"); + legend.setHeight(32); + legend.setWidth(32); + placesStyle.setLegend(legend); + catalog.save(placesStyle); + places.getStyles().add(placesStyle); + catalog.save(places); + String url = + "wms?LAYERS=" + + places.getName() + + "&STYLES=namedPlacesRenderingSelection&FORMAT=image%2Fpng" + + "&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256" + + "&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010&format_options=layout:test-layout-legend-image"; + BufferedImage image = getAsImage(url, "image/png"); + URL urlPng = getClass().getResource("renderingSelectionNamedPlaces.png"); + ImageAssert.assertEquals(new File(urlPng.toURI()), image, 1300); + } + + @Test + public void testLakesWithRenderingSelection() throws Exception { + // We have two featureTypeStyle in the style one for the map having + // test false + // and one for the legend having test + // false + // the final result obtained with a legend decorator should show + // polygon and legend icon with same color but icon without black border + Catalog catalog = getCatalog(); + File layouts = getDataDirectory().findOrCreateDir("layouts"); + URL layout = GetMapIntegrationTest.class.getResource("../test-layout-legend-image.xml"); + FileUtils.copyURLToFile(layout, new File(layouts, "test-layout-legend-image.xml")); + LayerInfo lakes = catalog.getLayerByName(getLayerId(MockData.LAKES)); + StyleInfo lakesStyle = catalog.getStyleByName("lakesRenderingSelection"); + LegendInfoImpl legend = new LegendInfoImpl(); + legend.setFormat("image/png;charset=utf-8"); + legend.setHeight(32); + legend.setWidth(32); + lakesStyle.setLegend(legend); + catalog.save(lakesStyle); + lakes.getStyles().add(lakesStyle); + catalog.save(lakes); + String url = + "wms?LAYERS=" + + lakes.getName() + + "&STYLES=lakesRenderingSelection&FORMAT=image%2Fpng" + + "&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256" + + "&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010&format_options=layout:test-layout-legend-image"; + BufferedImage image = getAsImage(url, "image/png"); + URL urlPng = getClass().getResource("renderingSelectionLakes.png"); + ImageAssert.assertEquals(new File(urlPng.toURI()), image, 1300); + } } diff --git a/src/wms/src/test/resources/org/geoserver/wms/legendgraphic/results/renderingSelectionOnRule.png b/src/wms/src/test/resources/org/geoserver/wms/legendgraphic/results/renderingSelectionOnRule.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f25eb3ad20230f42ae443939fca6d4893e6efd GIT binary patch literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1SFYWcSQjyIZqeIkcwN$Kl~XJBt&LOb~rDd jmg>d5c^V7ph^Z$S3j3^P6ati~c9 + + + + + + + + tl 2010 08013 arealm + + + group 0 + Feature + generic:geometry + simple + + + park + + + MTFCC + K2180 + + + 500000.0 + + + + + + + image/png + + + + + + mapOnly + + + + nationalpark + + + MTFCC + K2181 + + + 500000.0 + + + + + + square + + #ffff00 + + + 6 + + + + + + + + + \ No newline at end of file diff --git a/src/wms/src/test/resources/org/geoserver/wms/legendgraphic/styleWithLegendSelectionOnSymbolizer.sld b/src/wms/src/test/resources/org/geoserver/wms/legendgraphic/styleWithLegendSelectionOnSymbolizer.sld new file mode 100644 index 00000000000..5ce1a9ae286 --- /dev/null +++ b/src/wms/src/test/resources/org/geoserver/wms/legendgraphic/styleWithLegendSelectionOnSymbolizer.sld @@ -0,0 +1,86 @@ + + + + + + + + + tl 2010 08013 arealm + + + group 0 + Feature + generic:geometry + simple + + nationalpark + + + MTFCC + K2181 + + + + + #0099cc + + + #000000 + 0.5 + + + + + + + + circle + + #ffffff + + + 4 + + + rotation + -1 + + + 0.4 + + + + + + + + square + + #ffff00 + + + 6 + + + rotation + -1 + + + 0.4 + + + + mapOnly + + + + + + + \ No newline at end of file diff --git a/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/LakesRenderingSelection.sld b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/LakesRenderingSelection.sld new file mode 100644 index 00000000000..6b00f8e6e60 --- /dev/null +++ b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/LakesRenderingSelection.sld @@ -0,0 +1,70 @@ + + + + Default Styler + Default Styler + + + Feature + + name + Abstract + title + + + + #4040C0 + + + 1.0 + + + + + #000000 + + + butt + + + miter + + + 1 + + + 1 + + + 0 + + + + + mapOnly + + + Feature + + name + Abstract + title + + + + #4040C0 + + + 1.0 + + + + + legendOnly + + + diff --git a/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/NamedPlacesRenderingSelection.sld b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/NamedPlacesRenderingSelection.sld new file mode 100644 index 00000000000..4e1526fcd5c --- /dev/null +++ b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/NamedPlacesRenderingSelection.sld @@ -0,0 +1,98 @@ + + + + Default Styler + Default Styler + + + Feature + + ashton + Ashton + + + NAME + Ashton + + + + + + #AAAAAA + + + + + #000000 + + + + mapOnly + + + goose_island + Goose Island + + + NAME + Goose Island + + + + + + #FF5733 + + + + + #000000 + + + + mapOnly + + + + ashton + Ashton + + + NAME + Ashton + + + + + + #AAAAAA + + + + legendOnly + + + goose_island + Goose Island + + + NAME + Goose Island + + + + + + #FF5733 + + + + legendOnly + + + + diff --git a/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionLakes.png b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionLakes.png new file mode 100644 index 0000000000000000000000000000000000000000..67f2f4c917ae290495bbbe90a76aa1f6b6a1f78f GIT binary patch literal 2364 zcmcguX;>3U8m?{Z|wtj<>q1 zx;mW*;LoAWqX7Wstnu~Q0006_1YjuaS`9pw1E8m~#%s0UtIol5fxf2>n30!?bI#T0 zDE=|eWIF3~N=w^^Z&&7ft@A9qwoEtuP-@2R)xqh^uQPUr&}OYXEx{N%oaTB@Lwn5p zoApg~ya#laYuvC>$`jN7;9B7kbfQDCXY-lHvB{doJ0b&fuMf$M&OH;@+)&CgzcdSk z4FC#e8Z#z)p_#qeFddKpV4oU7fIKn(B5frJft8ft9CiEn`@`+8r!4`E60B|CxWps4 zUwhydMt;YaFdk2aUP`&r9?QjxK+!Fo#L;)P>i*@3Km(#`bc%2Gn!Yi;vw4Y)=3v0RLsfpqjCgLmP&9lwT3Q z8dm;mLjRfC?_vF-D7l!)WIE>fB_&N3Z7MYYvzNQMxw*Q|qw_tbO|KqVXFF{50mHco zL(lyK0`|wnRmED+v!5vPCdM^ELG*ju{yG+jf#;6S&d%=c8hVx6cv zWOYGNf5Akakq&a(`FU-Mhm%wMi@RxVFT&(rpQUf_?!J-zI7#DT9UAt`03?P*7ZnzE zHy`&g%E&OCrE5{LYJ6S!mpx;eohw$Xz(6>s!o(zLaIpQz5mssZX!di|=Me6Z$tfSxvvnxI$ z6B=@6SN#KDhBpY)-}l4zJh3HNNzI0Mf$8RtNw!9-q*#QoE*}!A8RE$d@%Qi_OD>-e*KaWm~v@FfyfrUsyw5SVz&=PRf#Queu?V02-zMa7}oNkM!;I3#v~LG zDFDpPLfQHmf=M-~Ru*h%71JlBQC(vLQ4DPm8RyE0t-De>?V2}dj62cEn>4=7seUHk z+fyU*Qf|L<64a^|)PhctEEipM;LY7Fa=ASB9!;W3OY{S6Tty&aV`I}b@g~zMWdROQ znMRsSQ`-B4bi8(an4XRH4N6(GWgZ?w_CDKRQYn}psNpJj$afvZ)w^nH5)9bOkkNMp zgX(*!wRyMafWz@b6MPRt>rdu`Gk)j2NRmo)@{)}37@!RY8C-=kvQU>8qBcGK1YT#8 zRV;NDsMnEE5rvj0r5Lbq4kjrP3$4jv5a|WBa1|EFkGg~v+NYLIVQdew(-2?J(DK1g zh~gMHDwKJk4Gc*ErKyF-HN?GvlQnsorA`NSsBAHEZIlS45Qg{_J;?>}IGa2TBK?60 zSD}ksqY#JDh9RjtCb1^x8RN+e?P|b56a}DOBoiXWRN^d(4N28h!WiF6W8V}Pn&Rt$ z(-QJWR$&;}f+&i?Ns(+H5=SK-qG^NDDr%Dn&e3Pf#cC$L2{_r4|6~;ggLp(y0USlL zZHR(OyhIxYq(`ZQDQ<{IFxu?M``{=*MY15|kFyAh!BgIKnq)a?N#14^ZUh;KF+zDq zWTCcmBpCauxX>8i1H8dOt{@+*)!AJFJXBIMv_T~ur!<-4vDBt}i%jtVM%yCtIrttM z_yo^|?zupyV{3I)Y-fbWgPkztPE||QC*hKgP>2nJNk)lQ)BsmW z3#e?eg*QmUfwo%gbJ4`Sh1Z6`fk>@>yw{hp(F!1np}F%DD;97CVn8AEzxAE3e@m=3 zAVK68Rn=eW_VD7Nzmwz0`zcZ+qr=ob1^K;VXruqNOuqOGlLTuSP8@)oVnv1m)RwC# zftiKyTtHn-+s26I8EN-4(io`D5g8>aA&>)vvdz%L4{!w^{cT8=od8A~`7uoFV6Koe zf=Jh#RUtQLU|HRt65j{j(8}dgPn(7xm2BC1_vPNqhGV_88$Qot*{z3XAoYGvTYT*F zRC-laZ2H~hH&jRN<@>tjiA~+*{=7TqGcz;G%F4{0_xS||Ha>b(=@t!Nf(G%}>XzmD?GKVzoF0QV^-tV*ivT|aeqdYY=)tj4U zM1rb=b!C?p^#?g5jIFT=y#G@7Li5qC^6>ER=AM*3=(wpgyarwv0|Nv7?WLw!RkN135jP=5p`wW= zKlWMZhvOgn6iR~yj8;~HhtL^gQu|b@j%$~{R$@NX=td5Oe|5>fe=h$24P2a^0x}Oe Uc5i*5>;mvv;~n5t;u&%1XCUdF6aWAK literal 0 HcmV?d00001 diff --git a/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionNamedPlaces.png b/src/wms/src/test/resources/org/geoserver/wms/wms_1_1_1/renderingSelectionNamedPlaces.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb53bb080f8da12c2d91248d905645aeef9d0df GIT binary patch literal 1164 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLk0$xU{4pvkcwMx@A~H53J_@s zT)%j+-h$0MyC!MfP82>PSsonA)-8s{(L?s$n5gyfy?{N^LsfD_ja9r zYQ%H+XU)H}iaf`*Ft9WrkQHCTfEzdJ+||V zzAlRXkQAfY@XA=No|Unrmd9Y1XWw(JpTC2Dclm^W6v_B@GyQw)G6$v^oC=$#pYVT? zZvOdX^Me$Xk6AOAI1_6AJXL?)%|5|0da7lM$GcFUMiv8`{Y%gHKf9?JP-J_1nZwEA zgG?{Jlr}t>n3Q>MzCD93>xCKt8!J|!28L&oHGJD21^526^r>6BD&0nwnS&v{kp;=$ z5O$xm!zXtR21W?7iCZ{f=dDG#j*J^#GW?70Dt^FFw=rFt#h~i!%_~pm{B*tcX#e7O zx5e2Fs{ZG#@xMDWmgUs#_19SqObb@uxBOkqa=?wbLw}Pv!`-)xZu=b>WON%YexEnp zZ8L*K0>e_xfKtI57eqL|$ue*-urM$&Fg7qaFcf@YxOYFuTmU3i@SUZz{GQGq?bh>O zpUm3v&V!+qA#7)gFGG$}!-J*^(U;r5s+H?3HNUTNKkLuW&1O7Oj3#UX?&E$V!qwANCq9r15clS-+PDUz$eB#_wIiy5@ui$APE6e12DaF zH~=-#f|*dvIH#`W_Gw=R9r*+MkfNLfpF1$%R;<8K&je3KxRrqt85Y?+cjE0ttf#y^ RtYyFe1fH&bF6*2UngCKURJZ^D literal 0 HcmV?d00001 From bf182f1bc42379ecd4eb2f0c9c0bff26f4137e28 Mon Sep 17 00:00:00 2001 From: Marco Volpini Date: Tue, 13 Apr 2021 15:33:37 +0200 Subject: [PATCH 3/3] [GEOS-10013] Mark invalid error while validating or saving a Style --- .../org/geoserver/catalog/SLDHandler.java | 2 +- .../wms/web/data/StyleEditPageTest.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/src/main/java/org/geoserver/catalog/SLDHandler.java b/src/main/src/main/java/org/geoserver/catalog/SLDHandler.java index bf8ed9e2da7..56f15cc3dfc 100644 --- a/src/main/src/main/java/org/geoserver/catalog/SLDHandler.java +++ b/src/main/src/main/java/org/geoserver/catalog/SLDHandler.java @@ -60,7 +60,7 @@ public class SLDHandler extends StyleHandler { * number of bytes to "look ahead" when pre parsing xml document. TODO: make this configurable, * and possibley link it to the same value used by the ows dispatcher. */ - static int XML_LOOKAHEAD = 8192; + static int XML_LOOKAHEAD = 8500; public static final String FORMAT = "sld"; diff --git a/src/web/wms/src/test/java/org/geoserver/wms/web/data/StyleEditPageTest.java b/src/web/wms/src/test/java/org/geoserver/wms/web/data/StyleEditPageTest.java index ce2e4f879b9..90d27c9d9f2 100644 --- a/src/web/wms/src/test/java/org/geoserver/wms/web/data/StyleEditPageTest.java +++ b/src/web/wms/src/test/java/org/geoserver/wms/web/data/StyleEditPageTest.java @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Serializable; +import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; import java.net.URL; @@ -68,7 +69,12 @@ import org.geoserver.wms.web.data.publish.WMSLayerConfigTest; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; +import org.geotools.styling.FeatureTypeStyle; +import org.geotools.styling.Style; +import org.geotools.styling.StyleBuilder; +import org.geotools.styling.visitor.DuplicatingStyleVisitor; import org.geotools.util.URLs; +import org.geotools.xml.styling.SLDTransformer; import org.junit.Before; import org.junit.Test; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -984,6 +990,37 @@ public void testStyleComponents() { "styleForm:style-component-mock", StyleEditPageTest.MockStyleComponent.class); } + @Test + public void testInvalidMark() throws Exception { + // GEOS-10013 tests that with a big style there is no error message MarkInvalid throw by the + // SLDHandler + // method getVersionAndReader + + // generate a long style + StyleBuilder styleBuilder = new StyleBuilder(); + DuplicatingStyleVisitor duplicatingStyleVisitor = new DuplicatingStyleVisitor(); + buildingsStyle.getStyle().accept(duplicatingStyleVisitor); + Style style = (Style) duplicatingStyleVisitor.getCopy(); + FeatureTypeStyle typeStyle = style.featureTypeStyles().get(0); + for (int i = 0; i < 30; i++) { + FeatureTypeStyle fts = + styleBuilder.createFeatureTypeStyle( + typeStyle.getName() + i, typeStyle.rules().get(0)); + style.featureTypeStyles().add(fts); + } + SLDTransformer transformer = new SLDTransformer(); + StringWriter writer = new StringWriter(); + transformer.transform(style, writer); + String sld = writer.toString(); + + // test that the Mark invalid error message not appears doesn't occur + tester.newFormTester("styleForm") + .setValue("styleEditor:editorContainer:editorParent:editor", sld); + + tester.executeAjaxEvent("validate", "click"); + tester.assertNoErrorMessage(); + } + public static class MockStyleComponentInfo extends StyleComponentInfo { public MockStyleComponentInfo(String id, AbstractStylePage clazz) { super("test", clazz);