| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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.apache.lucene.util; |
| |
| |
| import org.apache.lucene.analysis.Token; |
| import org.apache.lucene.analysis.TokenStream; |
| import org.apache.lucene.analysis.tokenattributes.*; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| public class TestAttributeSource extends LuceneTestCase { |
| |
| public void testCaptureState() { |
| // init a first instance |
| AttributeSource src = new AttributeSource(); |
| CharTermAttribute termAtt = src.addAttribute(CharTermAttribute.class); |
| TypeAttribute typeAtt = src.addAttribute(TypeAttribute.class); |
| termAtt.append("TestTerm"); |
| typeAtt.setType("TestType"); |
| final int hashCode = src.hashCode(); |
| |
| AttributeSource.State state = src.captureState(); |
| |
| // modify the attributes |
| termAtt.setEmpty().append("AnotherTestTerm"); |
| typeAtt.setType("AnotherTestType"); |
| assertTrue("Hash code should be different", hashCode != src.hashCode()); |
| |
| src.restoreState(state); |
| assertEquals("TestTerm", termAtt.toString()); |
| assertEquals("TestType", typeAtt.type()); |
| assertEquals("Hash code should be equal after restore", hashCode, src.hashCode()); |
| |
| // restore into an exact configured copy |
| AttributeSource copy = new AttributeSource(); |
| copy.addAttribute(CharTermAttribute.class); |
| copy.addAttribute(TypeAttribute.class); |
| copy.restoreState(state); |
| assertEquals("Both AttributeSources should have same hashCode after restore", src.hashCode(), copy.hashCode()); |
| assertEquals("Both AttributeSources should be equal after restore", src, copy); |
| |
| // init a second instance (with attributes in different order and one additional attribute) |
| AttributeSource src2 = new AttributeSource(); |
| typeAtt = src2.addAttribute(TypeAttribute.class); |
| FlagsAttribute flagsAtt = src2.addAttribute(FlagsAttribute.class); |
| termAtt = src2.addAttribute(CharTermAttribute.class); |
| flagsAtt.setFlags(12345); |
| |
| src2.restoreState(state); |
| assertEquals("TestTerm", termAtt.toString()); |
| assertEquals("TestType", typeAtt.type()); |
| assertEquals("FlagsAttribute should not be touched", 12345, flagsAtt.getFlags()); |
| |
| // init a third instance missing one Attribute |
| AttributeSource src3 = new AttributeSource(); |
| termAtt = src3.addAttribute(CharTermAttribute.class); |
| // The third instance is missing the TypeAttribute, so restoreState() should throw IllegalArgumentException |
| expectThrows(IllegalArgumentException.class, () -> { |
| src3.restoreState(state); |
| }); |
| } |
| |
| public void testCloneAttributes() { |
| final AttributeSource src = new AttributeSource(); |
| final FlagsAttribute flagsAtt = src.addAttribute(FlagsAttribute.class); |
| final TypeAttribute typeAtt = src.addAttribute(TypeAttribute.class); |
| flagsAtt.setFlags(1234); |
| typeAtt.setType("TestType"); |
| |
| final AttributeSource clone = src.cloneAttributes(); |
| final Iterator<Class<? extends Attribute>> it = clone.getAttributeClassesIterator(); |
| assertEquals("FlagsAttribute must be the first attribute", FlagsAttribute.class, it.next()); |
| assertEquals("TypeAttribute must be the second attribute", TypeAttribute.class, it.next()); |
| assertFalse("No more attributes", it.hasNext()); |
| |
| final FlagsAttribute flagsAtt2 = clone.getAttribute(FlagsAttribute.class); |
| assertNotNull(flagsAtt2); |
| final TypeAttribute typeAtt2 = clone.getAttribute(TypeAttribute.class); |
| assertNotNull(typeAtt2); |
| assertNotSame("FlagsAttribute of original and clone must be different instances", flagsAtt2, flagsAtt); |
| assertNotSame("TypeAttribute of original and clone must be different instances", typeAtt2, typeAtt); |
| assertEquals("FlagsAttribute of original and clone must be equal", flagsAtt2, flagsAtt); |
| assertEquals("TypeAttribute of original and clone must be equal", typeAtt2, typeAtt); |
| |
| // test copy back |
| flagsAtt2.setFlags(4711); |
| typeAtt2.setType("OtherType"); |
| clone.copyTo(src); |
| assertEquals("FlagsAttribute of original must now contain updated term", 4711, flagsAtt.getFlags()); |
| assertEquals("TypeAttribute of original must now contain updated type", "OtherType", typeAtt.type()); |
| // verify again: |
| assertNotSame("FlagsAttribute of original and clone must be different instances", flagsAtt2, flagsAtt); |
| assertNotSame("TypeAttribute of original and clone must be different instances", typeAtt2, typeAtt); |
| assertEquals("FlagsAttribute of original and clone must be equal", flagsAtt2, flagsAtt); |
| assertEquals("TypeAttribute of original and clone must be equal", typeAtt2, typeAtt); |
| } |
| |
| public void testDefaultAttributeFactory() throws Exception { |
| AttributeSource src = new AttributeSource(); |
| |
| assertTrue("CharTermAttribute is not implemented by CharTermAttributeImpl", |
| src.addAttribute(CharTermAttribute.class) instanceof CharTermAttributeImpl); |
| assertTrue("OffsetAttribute is not implemented by OffsetAttributeImpl", |
| src.addAttribute(OffsetAttribute.class) instanceof OffsetAttributeImpl); |
| assertTrue("FlagsAttribute is not implemented by FlagsAttributeImpl", |
| src.addAttribute(FlagsAttribute.class) instanceof FlagsAttributeImpl); |
| assertTrue("PayloadAttribute is not implemented by PayloadAttributeImpl", |
| src.addAttribute(PayloadAttribute.class) instanceof PayloadAttributeImpl); |
| assertTrue("PositionIncrementAttribute is not implemented by PositionIncrementAttributeImpl", |
| src.addAttribute(PositionIncrementAttribute.class) instanceof PositionIncrementAttributeImpl); |
| assertTrue("TypeAttribute is not implemented by TypeAttributeImpl", |
| src.addAttribute(TypeAttribute.class) instanceof TypeAttributeImpl); |
| } |
| |
| @SuppressWarnings({"rawtypes","unchecked"}) |
| public void testInvalidArguments() throws Exception { |
| expectThrows(IllegalArgumentException.class, () -> { |
| AttributeSource src = new AttributeSource(); |
| src.addAttribute(Token.class); |
| fail("Should throw IllegalArgumentException"); |
| }); |
| |
| expectThrows(IllegalArgumentException.class, () -> { |
| AttributeSource src = new AttributeSource(Token.TOKEN_ATTRIBUTE_FACTORY); |
| src.addAttribute(Token.class); |
| }); |
| |
| expectThrows(IllegalArgumentException.class, () -> { |
| AttributeSource src = new AttributeSource(); |
| // break this by unsafe cast |
| src.addAttribute((Class) Iterator.class); |
| }); |
| } |
| |
| public void testLUCENE_3042() throws Exception { |
| final AttributeSource src1 = new AttributeSource(); |
| src1.addAttribute(CharTermAttribute.class).append("foo"); |
| int hash1 = src1.hashCode(); // this triggers a cached state |
| final AttributeSource src2 = new AttributeSource(src1); |
| src2.addAttribute(TypeAttribute.class).setType("bar"); |
| assertTrue("The hashCode is identical, so the captured state was preserved.", hash1 != src1.hashCode()); |
| assertEquals(src2.hashCode(), src1.hashCode()); |
| } |
| |
| public void testClonePayloadAttribute() throws Exception { |
| // LUCENE-6055: verify that PayloadAttribute.clone() does deep cloning. |
| PayloadAttributeImpl src = new PayloadAttributeImpl(new BytesRef(new byte[] { 1, 2, 3 })); |
| |
| // test clone() |
| PayloadAttributeImpl clone = src.clone(); |
| clone.getPayload().bytes[0] = 10; // modify one byte, srcBytes shouldn't change |
| assertEquals("clone() wasn't deep", 1, src.getPayload().bytes[0]); |
| |
| // test copyTo() |
| clone = new PayloadAttributeImpl(); |
| src.copyTo(clone); |
| clone.getPayload().bytes[0] = 10; // modify one byte, srcBytes shouldn't change |
| assertEquals("clone() wasn't deep", 1, src.getPayload().bytes[0]); |
| } |
| |
| public void testRemoveAllAttributes() { |
| List<Class<? extends Attribute>> attrClasses = new ArrayList<>(); |
| attrClasses.add(CharTermAttribute.class); |
| attrClasses.add(OffsetAttribute.class); |
| attrClasses.add(FlagsAttribute.class); |
| attrClasses.add(PayloadAttribute.class); |
| attrClasses.add(PositionIncrementAttribute.class); |
| attrClasses.add(TypeAttribute.class); |
| |
| // Add attributes with the default factory, then try to remove all of them |
| AttributeSource defaultFactoryAttributeSource = new AttributeSource(); |
| |
| assertFalse(defaultFactoryAttributeSource.hasAttributes()); |
| |
| for (Class<? extends Attribute> attrClass : attrClasses) { |
| defaultFactoryAttributeSource.addAttribute(attrClass); |
| assertTrue("Missing added attribute " + attrClass.getSimpleName(), |
| defaultFactoryAttributeSource.hasAttribute(attrClass)); |
| } |
| |
| defaultFactoryAttributeSource.removeAllAttributes(); |
| |
| for (Class<? extends Attribute> attrClass : attrClasses) { |
| assertFalse("Didn't remove attribute " + attrClass.getSimpleName(), |
| defaultFactoryAttributeSource.hasAttribute(attrClass)); |
| } |
| assertFalse(defaultFactoryAttributeSource.hasAttributes()); |
| |
| // Add attributes with the packed implementations factory, then try to remove all of them |
| AttributeSource packedImplsAttributeSource |
| = new AttributeSource(TokenStream.DEFAULT_TOKEN_ATTRIBUTE_FACTORY); |
| assertFalse(packedImplsAttributeSource.hasAttributes()); |
| |
| for (Class<? extends Attribute> attrClass : attrClasses) { |
| packedImplsAttributeSource.addAttribute(attrClass); |
| assertTrue("Missing added attribute " + attrClass.getSimpleName(), |
| packedImplsAttributeSource.hasAttribute(attrClass)); |
| } |
| |
| packedImplsAttributeSource.removeAllAttributes(); |
| |
| for (Class<? extends Attribute> attrClass : attrClasses) { |
| assertFalse("Didn't remove attribute " + attrClass.getSimpleName(), |
| packedImplsAttributeSource.hasAttribute(attrClass)); |
| } |
| assertFalse(packedImplsAttributeSource.hasAttributes()); |
| } |
| } |