// Copyright 2011 Google Inc. // // Licensed 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 com.google.enterprise.connector.util.filter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; import com.google.enterprise.connector.spi.Document; import com.google.enterprise.connector.spi.Property; import com.google.enterprise.connector.spi.SimpleDocument; import com.google.enterprise.connector.spi.SpiConstants; import com.google.enterprise.connector.spi.Value; import com.google.enterprise.connector.spiimpl.BinaryValue; import junit.framework.TestCase; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Mostly useful for other DocumentFilter tests to subclass. */ public class DocumentFilterTest extends TestCase { protected static final String PROP1 = "property1"; protected static final String PROP2 = "property2"; protected static final String PROP3 = "property3"; protected static final String PROP4 = "property4"; protected static final String PROP5 = "property5"; protected static final String PROP6 = "property6"; protected static final String PROP7 = "property7"; protected static final String TEST_STRING = "The_.quick_brown_fox.jumped.over"; protected static final String CLEAN_STRING = "The quick brown fox jumped over"; protected static final String TEST_EXTRA_STRING = "lazy.dog's_back"; protected static final String EXTRA_STRING = "lazy dog's back"; protected static final String PATTERN = "[_\\.]+"; protected static final String SPACE = " "; protected static final String MIMEVALUE = "text/plain;utf-8"; /** Creates a source Document. */ protected Document createDocument() { return new SimpleDocument(createProperties()); } protected Document createDocument(boolean includeMimetype){ return new SimpleDocument(createProperties(includeMimetype)); } /** Default createProperties which adds mimetype to the doc. */ protected Map<String, List<Value>> createProperties() { return createProperties(true); } /** Creates the filter without adding mimetype property. */ protected Map<String, List<Value>> createProperties(boolean includeMimetype) { Map<String, List<Value>> props = new HashMap<String, List<Value>>(); if (includeMimetype) { // Avoid valueList, which is overridden for binary values in subclasses. LinkedList<Value> list = new LinkedList<Value>(); list.add(Value.getStringValue(MIMEVALUE)); props.put(SpiConstants.PROPNAME_MIMETYPE, list); } props.put(PROP1, valueList(TEST_STRING)); props.put(PROP2, valueList(CLEAN_STRING)); props.put(PROP3, valueList(TEST_STRING, EXTRA_STRING)); props.put(PROP4, valueList(CLEAN_STRING, EXTRA_STRING)); props.put(PROP5, valueList(CLEAN_STRING, TEST_EXTRA_STRING)); props.put(PROP6, valueList(TEST_STRING, TEST_EXTRA_STRING)); props.put(PROP7, valueList(EXTRA_STRING)); return props; } protected List<Value> valueList(String... values) { LinkedList<Value> list = new LinkedList<Value>(); for (String value : values) { list.add(Value.getStringValue(value)); } return list; } /** Checks that the Document Properties match the expected Properties. */ protected void checkDocument(Document document, Map<String, List<Value>> expectedProps) throws Exception { checkDocument(document, expectedProps, null); } /** * Checks that the Document Properties match the expected Properties. * * @param document the document to check * @param expectedProps the expected properties of the document * @param skipProp a property who's value should not be checked * but is still returned in getPropertyNames */ protected void checkDocument(Document document, Map<String, List<Value>> expectedProps, String skipProp) throws Exception { Set<String> expectedSet; if (Strings.isNullOrEmpty(skipProp)) { expectedSet = expectedProps.keySet(); } else { expectedSet = Sets.union(expectedProps.keySet(), ImmutableSet.of(skipProp)); } assertEquals(expectedSet, document.getPropertyNames()); checkDocumentProperties(document, expectedProps); } /** * Checks that the Document Properties match the expected Properties, * which may be a subset of the full document properties. */ protected void checkDocumentProperties(Document document, Map<String, List<Value>> expectedProps) throws Exception { for (Map.Entry<String, List<Value>> entry : expectedProps.entrySet()) { Property prop = document.findProperty(entry.getKey()); assertNotNull(prop); for (Value expectedValue : entry.getValue()) { Value value = prop.nextValue(); assertNotNull(value); if (value instanceof BinaryValue) { assertEquals(getStringFromBinaryValue(expectedValue), getStringFromBinaryValue(value)); } else { assertEquals(expectedValue.toString(), value.toString()); } } assertNull(prop.nextValue()); } } protected static String getStringFromBinaryValue(Value value) throws Exception { InputStream in = ((BinaryValue) value).getInputStream(); return new String(ByteStreams.toByteArray(in)); } /** Check IllegalStateException if the Filter was not properly initialized. */ protected void checkIllegalState(DocumentFilterFactory factory) throws Exception { Document filter = factory.newDocumentFilter(createDocument()); try { filter.getPropertyNames(); fail("IllegalStateException expected"); } catch (IllegalStateException expected) { // Expected. } try { filter.findProperty(PROP1); fail("IllegalStateException expected"); } catch (IllegalStateException expected) { // Expected. } } /** Check IllegalStateException if the Filter was not properly initialized. */ protected void checkIllegalStateFindProperty( DocumentFilterFactory factory) throws Exception { Document filter = factory.newDocumentFilter(createDocument()); try { filter.findProperty(PROP1); fail("IllegalStateException expected"); } catch (IllegalStateException expected) { // Expected. } } /** Test createDocument. */ public void testCreateDocument() throws Exception { checkDocument(createDocument(), createProperties()); } /** If no methods are overridden, the AbstractDocumentFilter is just * a NO-OP filter, passing all calls through to the source Document. */ public void testNoopFilter() throws Exception { NoopDocumentFilter filter = new NoopDocumentFilter(); checkDocument(filter.newDocumentFilter(createDocument()), createProperties()); } /** Test null source document. */ public void testNullSourceDocument() throws Exception { NoopDocumentFilter filter = new NoopDocumentFilter(); try { filter.newDocumentFilter(null); fail("NullPointerException expected"); } catch (NullPointerException expected) { // Expected. } } /** Test toString(). Test Subclasses should override this */ public void testToString() { NoopDocumentFilter filter = new NoopDocumentFilter(); assertEquals("DocumentFilterTest$NoopDocumentFilter", filter.toString()); } /** AbstractDocumentFilter is defined as abstract, so I must subclass it. */ class NoopDocumentFilter extends AbstractDocumentFilter { } }