summaryrefslogtreecommitdiff
path: root/core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java')
-rw-r--r--core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java1430
1 files changed, 1430 insertions, 0 deletions
diff --git a/core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java b/core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java
new file mode 100644
index 0000000000..9d95ea6013
--- /dev/null
+++ b/core/src/test/java/org/elasticsearch/common/xcontent/support/AbstractFilteringTestCase.java
@@ -0,0 +1,1430 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.common.xcontent.support;
+
+import org.elasticsearch.common.CheckedFunction;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.util.set.Sets;
+import org.elasticsearch.common.xcontent.XContent;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.test.ESTestCase;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
+
+/**
+ * Tests for {@link XContent} filtering.
+ */
+public abstract class AbstractFilteringTestCase extends ESTestCase {
+
+ @FunctionalInterface
+ protected interface Builder extends CheckedFunction<XContentBuilder, XContentBuilder, IOException> {
+ }
+
+ protected abstract void testFilter(Builder expected, Builder actual, Set<String> includes, Set<String> excludes) throws IOException;
+
+ /** Sample test case **/
+ private static final Builder SAMPLE = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ public void testNoFiltering() throws Exception {
+ final Builder expected = SAMPLE;
+
+ testFilter(expected, SAMPLE, emptySet(), emptySet());
+ testFilter(expected, SAMPLE, singleton("*"), emptySet());
+ testFilter(expected, SAMPLE, singleton("**"), emptySet());
+ testFilter(expected, SAMPLE, emptySet(), singleton("xyz"));
+ }
+
+ public void testNoMatch() throws Exception {
+ final Builder expected = builder -> builder.startObject().endObject();
+
+ testFilter(expected, SAMPLE, singleton("xyz"), emptySet());
+ testFilter(expected, SAMPLE, emptySet(), singleton("*"));
+ testFilter(expected, SAMPLE, emptySet(), singleton("**"));
+ }
+
+ public void testSimpleFieldInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject().field("title", "My awesome book").endObject();
+
+ testFilter(expected, SAMPLE, singleton("title"), emptySet());
+ }
+
+ public void testSimpleFieldExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("title"));
+ }
+
+ public void testSimpleFieldWithWildcardInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("price", 27.99)
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("pr*"), emptySet());
+ }
+
+ public void testSimpleFieldWithWildcardExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("pr*"));
+ }
+
+ public void testMultipleFieldsInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .endObject();
+
+ testFilter(expected, SAMPLE, Sets.newHashSet("title", "pages"), emptySet());
+ }
+
+ public void testMultipleFieldsExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), Sets.newHashSet("title", "pages"));
+ }
+
+ public void testSimpleArrayInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("tags"), emptySet());
+ }
+
+ public void testSimpleArrayExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("tags"));
+ }
+
+ public void testSimpleArrayOfObjectsInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("authors"), emptySet());
+ testFilter(expected, SAMPLE, singleton("authors.*"), emptySet());
+ testFilter(expected, SAMPLE, singleton("authors.*name"), emptySet());
+ }
+
+ public void testSimpleArrayOfObjectsExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("authors"));
+ testFilter(expected, SAMPLE, emptySet(), singleton("authors.*"));
+ testFilter(expected, SAMPLE, emptySet(), singleton("authors.*name"));
+ }
+
+ public void testSimpleArrayOfObjectsPropertyInclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startArray("authors")
+ .startObject()
+ .field("lastname", "John")
+ .endObject()
+ .startObject()
+ .field("lastname", "William")
+ .endObject()
+ .endArray()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("authors.lastname"), emptySet());
+ testFilter(expected, SAMPLE, singleton("authors.l*"), emptySet());
+ }
+
+ public void testSimpleArrayOfObjectsPropertyExclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("authors.lastname"));
+ testFilter(expected, SAMPLE, emptySet(), singleton("authors.l*"));
+ }
+
+ public void testRecurseField1Inclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ . endObject()
+ .endArray()
+ .startObject("properties")
+ .startObject("language")
+ .startObject("en")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("**.name"), emptySet());
+ }
+
+ public void testRecurseField1Exclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("**.name"));
+ }
+
+ public void testRecurseField2Inclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startObject("properties")
+ .startObject("language")
+ .startObject("en")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("properties.**.name"), emptySet());
+ }
+
+ public void testRecurseField2Exclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("properties.**.name"));
+ }
+
+ public void testRecurseField3Inclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startObject("properties")
+ .startObject("language")
+ .startObject("en")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("properties.*.en.**.name"), emptySet());
+ }
+
+ public void testRecurseField3Exclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("properties.*.en.**.name"));
+ }
+
+ public void testRecurseField4Inclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .startObject("properties")
+ .startObject("language")
+ .startObject("en")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .startArray("distributors")
+ .startObject()
+ .field("name", "La Maison du Livre")
+ .endObject()
+ .startObject()
+ .field("name", "Thetra")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("properties.**.distributors.name"), emptySet());
+ }
+
+ public void testRecurseField4Exclusive() throws Exception {
+ final Builder expected = builder -> builder.startObject()
+ .field("title", "My awesome book")
+ .field("pages", 456)
+ .field("price", 27.99)
+ .field("timestamp", 1428582942867L)
+ .nullField("default")
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("name", "John Doe")
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("name", "William Smith")
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Hampton St")
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("name", "address #2")
+ .field("street", "Queen St")
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .startArray("distributors")
+ .startObject()
+ .startArray("addresses")
+ .startObject()
+ .field("name", "address #1")
+ .field("street", "Rue Mouffetard")
+ .field("city", "Paris")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, emptySet(), singleton("properties.**.distributors.name"));
+ }
+
+ public void testRawField() throws Exception {
+ final Builder expectedRawField = builder -> builder
+ .startObject()
+ .field("foo", 0)
+ .startObject("raw")
+ .field("content", "hello world!")
+ .endObject()
+ .endObject();
+
+ final Builder expectedRawFieldFiltered = builder -> builder
+ .startObject()
+ .field("foo", 0)
+ .endObject();
+
+ final Builder expectedRawFieldNotFiltered = builder -> builder
+ .startObject()
+ .startObject("raw")
+ .field("content", "hello world!")
+ .endObject()
+ .endObject();
+
+ Builder sampleWithRaw = builder -> {
+ BytesReference raw = XContentBuilder.builder(builder.contentType().xContent())
+ .startObject()
+ .field("content", "hello world!")
+ .endObject()
+ .bytes();
+ return builder.startObject().field("foo", 0).rawField("raw", raw).endObject();
+ };
+
+ // Test method: rawField(String fieldName, BytesReference content)
+ testFilter(expectedRawField, sampleWithRaw, emptySet(), emptySet());
+ testFilter(expectedRawFieldFiltered, sampleWithRaw, singleton("f*"), emptySet());
+ testFilter(expectedRawFieldFiltered, sampleWithRaw, emptySet(), singleton("r*"));
+ testFilter(expectedRawFieldNotFiltered, sampleWithRaw, singleton("r*"), emptySet());
+ testFilter(expectedRawFieldNotFiltered, sampleWithRaw, emptySet(), singleton("f*"));
+
+ sampleWithRaw = builder -> {
+ BytesReference raw = XContentBuilder.builder(builder.contentType().xContent())
+ .startObject()
+ . field("content", "hello world!")
+ .endObject()
+ .bytes();
+ return builder.startObject().field("foo", 0).rawField("raw", raw.streamInput()).endObject();
+ };
+
+ // Test method: rawField(String fieldName, InputStream content)
+ testFilter(expectedRawField, sampleWithRaw, emptySet(), emptySet());
+ testFilter(expectedRawFieldFiltered, sampleWithRaw, singleton("f*"), emptySet());
+ testFilter(expectedRawFieldFiltered, sampleWithRaw, emptySet(), singleton("r*"));
+ testFilter(expectedRawFieldNotFiltered, sampleWithRaw, singleton("r*"), emptySet());
+ testFilter(expectedRawFieldNotFiltered, sampleWithRaw, emptySet(), singleton("f*"));
+ }
+
+ public void testArrays() throws Exception {
+ // Test: Array of values (no filtering)
+ final Builder sampleArrayOfValues = builder -> builder
+ .startObject()
+ .startArray("tags")
+ .value("lorem").value("ipsum").value("dolor")
+ .endArray()
+ .endObject();
+ testFilter(sampleArrayOfValues, sampleArrayOfValues, singleton("t*"), emptySet());
+ testFilter(sampleArrayOfValues, sampleArrayOfValues, singleton("tags"), emptySet());
+ testFilter(sampleArrayOfValues, sampleArrayOfValues, emptySet(), singleton("a"));
+
+ // Test: Array of values (with filtering)
+ Builder expected = builder -> builder.startObject().endObject();
+ testFilter(expected, sampleArrayOfValues, singleton("foo"), emptySet());
+ testFilter(expected, sampleArrayOfValues, emptySet(), singleton("t*"));
+ testFilter(expected, sampleArrayOfValues, emptySet(), singleton("tags"));
+
+ // Test: Array of objects (no filtering)
+ final Builder sampleArrayOfObjects = builder -> builder
+ .startObject()
+ .startArray("tags")
+ .startObject()
+ .field("lastname", "lorem")
+ .endObject()
+ .startObject()
+ .field("firstname", "ipsum")
+ .endObject()
+ .endArray()
+ .endObject();
+ testFilter(sampleArrayOfObjects, sampleArrayOfObjects, singleton("t*"), emptySet());
+ testFilter(sampleArrayOfObjects, sampleArrayOfObjects, singleton("tags"), emptySet());
+ testFilter(sampleArrayOfObjects, sampleArrayOfObjects, emptySet(), singleton("a"));
+
+ // Test: Array of objects (with filtering)
+ testFilter(expected, sampleArrayOfObjects, singleton("foo"), emptySet());
+ testFilter(expected, sampleArrayOfObjects, emptySet(), singleton("t*"));
+ testFilter(expected, sampleArrayOfObjects, emptySet(), singleton("tags"));
+
+ // Test: Array of objects (with partial filtering)
+ expected = builder -> builder
+ .startObject()
+ .startArray("tags")
+ .startObject()
+ .field("firstname", "ipsum")
+ .endObject()
+ .endArray()
+ .endObject();
+ testFilter(expected, sampleArrayOfObjects, singleton("t*.firstname"), emptySet());
+ testFilter(expected, sampleArrayOfObjects, emptySet(), singleton("t*.lastname"));
+ }
+
+ public void testEmptyObject() throws IOException {
+ final Builder sample = builder -> builder.startObject().startObject("foo").endObject().endObject();
+
+ Builder expected = builder -> builder.startObject().startObject("foo").endObject().endObject();
+ testFilter(expected, sample, singleton("foo"), emptySet());
+ testFilter(expected, sample, emptySet(), singleton("bar"));
+ testFilter(expected, sample, singleton("f*"), singleton("baz"));
+
+ expected = builder -> builder.startObject().endObject();
+ testFilter(expected, sample, emptySet(), singleton("foo"));
+ testFilter(expected, sample, singleton("bar"), emptySet());
+ testFilter(expected, sample, singleton("f*"), singleton("foo"));
+ }
+
+ public void testSingleFieldWithBothExcludesIncludes() throws IOException {
+ final Builder expected = builder -> builder
+ .startObject()
+ .field("pages", 456)
+ .field("price", 27.99)
+ .endObject();
+
+ testFilter(expected, SAMPLE, singleton("p*"), singleton("properties"));
+ }
+
+ public void testObjectsInArrayWithBothExcludesIncludes() throws IOException {
+ Set<String> includes = Sets.newHashSet("tags", "authors");
+ Set<String> excludes = singleton("authors.name");
+
+ final Builder expected = builder -> builder
+ .startObject()
+ .startArray("tags")
+ .value("elasticsearch")
+ .value("java")
+ .endArray()
+ .startArray("authors")
+ .startObject()
+ .field("lastname", "John")
+ .field("firstname", "Doe")
+ .endObject()
+ .startObject()
+ .field("lastname", "William")
+ .field("firstname", "Smith")
+ .endObject()
+ .endArray()
+ .endObject();
+
+ testFilter(expected, SAMPLE, includes, excludes);
+ }
+
+ public void testRecursiveObjectsInArrayWithBothExcludesIncludes() throws IOException {
+ Set<String> includes = Sets.newHashSet("**.language", "properties.weight");
+ Set<String> excludes = singleton("**.distributors");
+
+ final Builder expected = builder -> builder
+ .startObject()
+ .startObject("properties")
+ .field("weight", 0.8d)
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .endObject()
+ .startObject("fr")
+ .field("lang", "French")
+ .field("available", false)
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, includes, excludes);
+ }
+
+ public void testRecursiveSameObjectWithBothExcludesIncludes() throws IOException {
+ Set<String> includes = singleton("**.distributors");
+ Set<String> excludes = singleton("**.distributors");
+
+ final Builder expected = builder -> builder.startObject().endObject();
+ testFilter(expected, SAMPLE, includes, excludes);
+ }
+
+ public void testRecursiveObjectsPropertiesWithBothExcludesIncludes() throws IOException {
+ Set<String> includes = singleton("**.en.*");
+ Set<String> excludes = Sets.newHashSet("**.distributors.*.name", "**.street");
+
+ final Builder expected = builder -> builder
+ .startObject()
+ .startObject("properties")
+ .startObject("language")
+ .startObject("en")
+ .field("lang", "English")
+ .field("available", true)
+ .startArray("distributors")
+ .startObject()
+ .field("name", "The Book Shop")
+ .startArray("addresses")
+ .startObject()
+ .field("city", "London")
+ .endObject()
+ .startObject()
+ .field("city", "Stornoway")
+ .endObject()
+ .endArray()
+ .endObject()
+ .startObject()
+ .field("name", "Sussex Books House")
+ .endObject()
+ .endArray()
+ .endObject()
+ .endObject()
+ .endObject()
+ .endObject();
+
+ testFilter(expected, SAMPLE, includes, excludes);
+ }
+
+ public void testWithLfAtEnd() throws IOException {
+ final Builder sample = builder -> builder
+ .startObject()
+ .startObject("foo")
+ .field("bar", "baz")
+ .endObject()
+ .endObject()
+ .prettyPrint()
+ .lfAtEnd();
+
+ testFilter(sample, sample, singleton("foo"), emptySet());
+ testFilter(sample, sample, emptySet(), singleton("bar"));
+ testFilter(sample, sample, singleton("f*"), singleton("baz"));
+
+ final Builder expected = builder -> builder.startObject().endObject().prettyPrint().lfAtEnd();
+ testFilter(expected, sample, emptySet(), singleton("foo"));
+ testFilter(expected, sample, singleton("bar"), emptySet());
+ testFilter(expected, sample, singleton("f*"), singleton("foo"));
+ }
+
+ public void testBasics() throws Exception {
+ final Builder sample = builder -> builder
+ .startObject()
+ .field("test1", "value1")
+ .field("test2", "value2")
+ .field("something_else", "value3")
+ .endObject();
+
+ Builder expected = builder -> builder
+ .startObject()
+ .field("test1", "value1")
+ .endObject();
+ testFilter(expected, sample, singleton("test1"), emptySet());
+
+ expected = builder -> builder
+ .startObject()
+ .field("test1", "value1")
+ .field("test2", "value2")
+ .endObject();
+ testFilter(expected, sample, singleton("test*"), emptySet());
+
+ expected = builder -> builder
+ .startObject()
+ .field("test2", "value2")
+ .field("something_else", "value3")
+ .endObject();
+ testFilter(expected, sample, emptySet(), singleton("test1"));
+
+ // more complex object...
+ final Builder complex = builder -> builder
+ .startObject()
+ .startObject("path1")
+ .startArray("path2")
+ .startObject().field("test", "value1").endObject()
+ .startObject().field("test", "value2").endObject()
+ .endArray()
+ .endObject()
+ .field("test1", "value1")
+ .endObject();
+
+ expected = builder -> builder
+ .startObject()
+ .startObject("path1")
+ .startArray("path2")
+ .startObject().field("test", "value1").endObject()
+ .startObject().field("test", "value2").endObject()
+ .endArray()
+ .endObject()
+ .endObject();
+ testFilter(expected, complex, singleton("path1"), emptySet());
+ testFilter(expected, complex, singleton("path1*"), emptySet());
+ testFilter(expected, complex, singleton("path1.path2.*"), emptySet());
+
+ expected = builder -> builder
+ .startObject()
+ .field("test1", "value1")
+ .endObject();
+ testFilter(expected, complex, singleton("test1*"), emptySet());
+ }
+
+ /**
+ * Generalization of {@link XContentMapValuesTests#testSupplementaryCharactersInPaths()}
+ */
+ public void testFilterSupplementaryCharactersInPaths() throws IOException {
+ final Builder sample = builder -> builder
+ .startObject()
+ .field("搜索", 2)
+ .field("指数", 3)
+ .endObject();
+
+ Builder expected = builder -> builder
+ .startObject()
+ .field("搜索", 2)
+ .endObject();
+ testFilter(expected, sample, singleton("搜索"), emptySet());
+
+ expected = builder -> builder
+ .startObject()
+ .field("指数", 3)
+ .endObject();
+ testFilter(expected, sample, emptySet(), singleton("搜索"));
+ }
+
+ /**
+ * Generalization of {@link XContentMapValuesTests#testSharedPrefixes()}
+ */
+ public void testFilterSharedPrefixes() throws IOException {
+ final Builder sample = builder -> builder
+ .startObject()
+ .field("foobar", 2)
+ .field("foobaz", 3)
+ .endObject();
+
+ Builder expected = builder -> builder
+ .startObject()
+ .field("foobar", 2)
+ .endObject();
+ testFilter(expected, sample, singleton("foobar"), emptySet());
+
+ expected = builder -> builder
+ .startObject()
+ .field("foobaz", 3)
+ .endObject();
+ testFilter(expected, sample, emptySet(), singleton("foobar"));
+ }
+
+ /**
+ * Generalization of {@link XContentMapValuesTests#testPrefix()}
+ */
+ public void testFilterPrefix() throws IOException {
+ final Builder sample = builder -> builder
+ .startObject()
+ .array("photos", "foo", "bar")
+ .field("photosCount", 2)
+ .endObject();
+
+ Builder expected = builder -> builder
+ .startObject()
+ .field("photosCount", 2)
+ .endObject();
+ testFilter(expected, sample, singleton("photosCount"), emptySet());
+ }
+}