Index: lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.Codec =================================================================== --- lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.Codec (revision 1361189) +++ lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.Codec (working copy) @@ -13,3 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. +org.apache.lucene.codecs.asserting.AssertingCodec Index: lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat =================================================================== --- lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat (revision 1361189) +++ lucene/test-framework/src/resources/META-INF/services/org.apache.lucene.codecs.PostingsFormat (working copy) @@ -20,3 +20,5 @@ org.apache.lucene.codecs.nestedpulsing.NestedPulsingPostingsFormat org.apache.lucene.codecs.ramonly.RAMOnlyPostingsFormat org.apache.lucene.codecs.lucene40ords.Lucene40WithOrds +org.apache.lucene.codecs.asserting.AssertingPostingsFormat + Index: lucene/test-framework/src/java/org/apache/lucene/index/AssertingDirectoryReader.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/index/AssertingDirectoryReader.java (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/index/AssertingDirectoryReader.java (working copy) @@ -0,0 +1,90 @@ +package org.apache.lucene.index; + +/* + * 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. + */ + +import java.io.IOException; +import java.util.List; + +/** + * A {@link DirectoryReader} that wraps all its subreaders with + * {@link AssertingAtomicReader} + */ +public class AssertingDirectoryReader extends DirectoryReader { + protected DirectoryReader in; + + public AssertingDirectoryReader(DirectoryReader in) { + super(in.directory(), wrap(in.getSequentialSubReaders())); + this.in = in; + } + + private static AtomicReader[] wrap(List extends AtomicReader> readers) { + AtomicReader[] wrapped = new AtomicReader[readers.size()]; + for (int i = 0; i < readers.size(); i++) { + wrapped[i] = new AssertingAtomicReader(readers.get(i)); + } + return wrapped; + } + + @Override + protected DirectoryReader doOpenIfChanged() throws IOException { + DirectoryReader d = in.doOpenIfChanged(); + return d == null ? null : new AssertingDirectoryReader(d); + } + + @Override + protected DirectoryReader doOpenIfChanged(IndexCommit commit) throws IOException { + DirectoryReader d = in.doOpenIfChanged(commit); + return d == null ? null : new AssertingDirectoryReader(d); + } + + @Override + protected DirectoryReader doOpenIfChanged(IndexWriter writer, boolean applyAllDeletes) throws IOException { + DirectoryReader d = in.doOpenIfChanged(writer, applyAllDeletes); + return d == null ? null : new AssertingDirectoryReader(d); + } + + @Override + public long getVersion() { + return in.getVersion(); + } + + @Override + public boolean isCurrent() throws IOException { + return in.isCurrent(); + } + + @Override + public IndexCommit getIndexCommit() throws IOException { + return in.getIndexCommit(); + } + + @Override + protected void doClose() throws IOException { + in.doClose(); + } + + @Override + public Object getCoreCacheKey() { + return in.getCoreCacheKey(); + } + + @Override + public Object getCombinedCoreAndDeletesKey() { + return in.getCombinedCoreAndDeletesKey(); + } +} Index: lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java (revision 1361189) +++ lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java (working copy) @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.lucene.codecs.PostingsFormat; +import org.apache.lucene.codecs.asserting.AssertingPostingsFormat; import org.apache.lucene.codecs.lucene40.Lucene40Codec; import org.apache.lucene.codecs.lucene40.Lucene40PostingsFormat; import org.apache.lucene.codecs.lucene40ords.Lucene40WithOrds; @@ -99,6 +100,7 @@ new NestedPulsingPostingsFormat(), new Lucene40WithOrds(), new SimpleTextPostingsFormat(), + new AssertingPostingsFormat(), new MemoryPostingsFormat(true, random.nextFloat()), new MemoryPostingsFormat(false, random.nextFloat())); Index: lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java (working copy) @@ -0,0 +1,370 @@ +package org.apache.lucene.index; + +import java.io.IOException; + +import org.apache.lucene.search.DocIdSetIterator; +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.automaton.CompiledAutomaton; + +/* + * 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. + */ + +/** + * A {@link FilterAtomicReader} that can be used to apply + * additional checks for tests. + */ +public class AssertingAtomicReader extends FilterAtomicReader { + + public AssertingAtomicReader(AtomicReader in) { + super(in); + // check some basic reader sanity + assert in.maxDoc() >= 0; + assert in.numDocs() <= in.maxDoc(); + assert in.numDeletedDocs() + in.numDocs() == in.maxDoc(); + assert !in.hasDeletions() || in.numDeletedDocs() > 0 && in.numDocs() < in.maxDoc(); + } + + @Override + public Fields fields() throws IOException { + Fields fields = super.fields(); + return fields == null ? null : new AssertingFields(fields); + } + + @Override + public Fields getTermVectors(int docID) throws IOException { + Fields fields = super.getTermVectors(docID); + return fields == null ? null : new AssertingFields(fields); + } + + /** + * Wraps a Fields but with additional asserts + */ + public static class AssertingFields extends FilterFields { + public AssertingFields(Fields in) { + super(in); + } + + @Override + public FieldsEnum iterator() throws IOException { + FieldsEnum fieldsEnum = super.iterator(); + assert fieldsEnum != null; + return new AssertingFieldsEnum(fieldsEnum); + } + + @Override + public Terms terms(String field) throws IOException { + Terms terms = super.terms(field); + return terms == null ? null : new AssertingTerms(terms); + } + } + + /** + * Wraps a FieldsEnum but with additional asserts + */ + public static class AssertingFieldsEnum extends FilterFieldsEnum { + public AssertingFieldsEnum(FieldsEnum in) { + super(in); + } + + @Override + public Terms terms() throws IOException { + Terms terms = super.terms(); + return terms == null ? null : new AssertingTerms(terms); + } + } + + /** + * Wraps a Terms but with additional asserts + */ + public static class AssertingTerms extends FilterTerms { + public AssertingTerms(Terms in) { + super(in); + } + + @Override + public TermsEnum intersect(CompiledAutomaton automaton, BytesRef bytes) throws IOException { + TermsEnum termsEnum = super.intersect(automaton, bytes); + assert termsEnum != null; + return new AssertingTermsEnum(termsEnum); + } + + @Override + public TermsEnum iterator(TermsEnum reuse) throws IOException { + // TODO: should we give this thing a random to be super-evil, + // and randomly *not* unwrap? + if (reuse instanceof AssertingTermsEnum) { + reuse = ((AssertingTermsEnum) reuse).in; + } + TermsEnum termsEnum = super.iterator(reuse); + assert termsEnum != null; + return new AssertingTermsEnum(termsEnum); + } + } + + static class AssertingTermsEnum extends FilterTermsEnum { + private enum State {INITIAL, POSITIONED, UNPOSITIONED}; + private State state = State.INITIAL; + + public AssertingTermsEnum(TermsEnum in) { + super(in); + } + + @Override + public DocsEnum docs(Bits liveDocs, DocsEnum reuse, boolean needsFreqs) throws IOException { + assert state == State.POSITIONED: "docs(...) called on unpositioned TermsEnum"; + + // TODO: should we give this thing a random to be super-evil, + // and randomly *not* unwrap? + if (reuse instanceof AssertingDocsEnum) { + reuse = ((AssertingDocsEnum) reuse).in; + } + DocsEnum docs = super.docs(liveDocs, reuse, needsFreqs); + return docs == null ? null : new AssertingDocsEnum(docs); + } + + @Override + public DocsAndPositionsEnum docsAndPositions(Bits liveDocs, DocsAndPositionsEnum reuse, boolean needsOffsets) throws IOException { + assert state == State.POSITIONED: "docsAndPositions(...) called on unpositioned TermsEnum"; + + // TODO: should we give this thing a random to be super-evil, + // and randomly *not* unwrap? + if (reuse instanceof AssertingDocsAndPositionsEnum) { + reuse = ((AssertingDocsAndPositionsEnum) reuse).in; + } + DocsAndPositionsEnum docs = super.docsAndPositions(liveDocs, reuse, needsOffsets); + return docs == null ? null : new AssertingDocsAndPositionsEnum(docs); + } + + // TODO: we should separately track if we are 'at the end' ? + // someone should not call next() after it returns null!!!! + @Override + public BytesRef next() throws IOException { + assert state == State.INITIAL || state == State.POSITIONED: "next() called on unpositioned TermsEnum"; + BytesRef result = super.next(); + if (result == null) { + state = State.UNPOSITIONED; + } else { + state = State.POSITIONED; + } + return result; + } + + @Override + public long ord() throws IOException { + assert state == State.POSITIONED : "ord() called on unpositioned TermsEnum"; + return super.ord(); + } + + @Override + public int docFreq() throws IOException { + assert state == State.POSITIONED : "docFreq() called on unpositioned TermsEnum"; + return super.docFreq(); + } + + @Override + public long totalTermFreq() throws IOException { + assert state == State.POSITIONED : "totalTermFreq() called on unpositioned TermsEnum"; + return super.totalTermFreq(); + } + + @Override + public BytesRef term() throws IOException { + assert state == State.POSITIONED : "term() called on unpositioned TermsEnum"; + return super.term(); + } + + @Override + public void seekExact(long ord) throws IOException { + super.seekExact(ord); + state = State.POSITIONED; + } + + @Override + public SeekStatus seekCeil(BytesRef term, boolean useCache) throws IOException { + SeekStatus result = super.seekCeil(term, useCache); + if (result == SeekStatus.END) { + state = State.UNPOSITIONED; + } else { + state = State.POSITIONED; + } + return result; + } + + @Override + public boolean seekExact(BytesRef text, boolean useCache) throws IOException { + if (super.seekExact(text, useCache)) { + state = State.POSITIONED; + return true; + } else { + state = State.UNPOSITIONED; + return false; + } + } + + @Override + public TermState termState() throws IOException { + assert state == State.POSITIONED : "termState() called on unpositioned TermsEnum"; + return super.termState(); + } + + @Override + public void seekExact(BytesRef term, TermState state) throws IOException { + super.seekExact(term, state); + this.state = State.POSITIONED; + } + } + + static enum DocsEnumState { START, ITERATING, FINISHED }; + static class AssertingDocsEnum extends FilterDocsEnum { + private DocsEnumState state = DocsEnumState.START; + + public AssertingDocsEnum(DocsEnum in) { + super(in); + int docid = in.docID(); + assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : "invalid initial doc id: " + docid; + } + + @Override + public int nextDoc() throws IOException { + assert state != DocsEnumState.FINISHED : "nextDoc() called after iterator is exhausted!"; + int nextDoc = super.nextDoc(); + assert nextDoc >= 0 : "invalid doc id: " + nextDoc; + if (nextDoc == DocIdSetIterator.NO_MORE_DOCS) { + state = DocsEnumState.FINISHED; + } else { + state = DocsEnumState.ITERATING; + } + return nextDoc; + } + + @Override + public int advance(int target) throws IOException { + assert state != DocsEnumState.FINISHED : "advance() called after iterator is exhausted!"; + int advanced = super.advance(target); + assert advanced >= 0 : "invalid doc id: " + advanced; + assert advanced >= target : "backwards advance from: " + target + " to: " + advanced; + if (advanced == DocIdSetIterator.NO_MORE_DOCS) { + state = DocsEnumState.FINISHED; + } else { + state = DocsEnumState.ITERATING; + } + return advanced; + } + + // NOTE: We don't assert anything for docId(). Specifically DocsEnum javadocs + // are ambiguous with DocIdSetIterator here, DocIdSetIterator says its ok + // to call this method before nextDoc(), just that it must be -1 or NO_MORE_DOCS! + + @Override + public int freq() throws IOException { + assert state != DocsEnumState.START : "freq() called before nextDoc()/advance()"; + int freq = super.freq(); + assert freq > 0; + return freq; + } + } + + static class AssertingDocsAndPositionsEnum extends FilterDocsAndPositionsEnum { + private DocsEnumState state = DocsEnumState.START; + private int positionMax = 0; + private int positionCount = 0; + + public AssertingDocsAndPositionsEnum(DocsAndPositionsEnum in) { + super(in); + int docid = in.docID(); + assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : "invalid initial doc id: " + docid; + } + + @Override + public int nextDoc() throws IOException { + assert state != DocsEnumState.FINISHED : "nextDoc() called after iterator is exhausted!"; + int nextDoc = super.nextDoc(); + assert nextDoc >= 0 : "invalid doc id: " + nextDoc; + if (nextDoc == DocIdSetIterator.NO_MORE_DOCS) { + state = DocsEnumState.FINISHED; + } else { + state = DocsEnumState.ITERATING; + } + positionCount = 0; + positionMax = super.freq(); + return nextDoc; + } + + @Override + public int advance(int target) throws IOException { + assert state != DocsEnumState.FINISHED : "advance() called after iterator is exhausted!"; + int advanced = super.advance(target); + assert advanced >= 0 : "invalid doc id: " + advanced; + assert advanced >= target : "backwards advance from: " + target + " to: " + advanced; + if (advanced == DocIdSetIterator.NO_MORE_DOCS) { + state = DocsEnumState.FINISHED; + } else { + state = DocsEnumState.ITERATING; + } + positionCount = 0; + positionMax = super.freq(); + return advanced; + } + + @Override + public int freq() throws IOException { + assert state != DocsEnumState.START : "freq() called before nextDoc()/advance()"; + int freq = super.freq(); + assert freq > 0; + return freq; + } + + @Override + public int nextPosition() throws IOException { + assert state != DocsEnumState.START : "nextPosition() called before nextDoc()/advance()"; + assert positionCount < positionMax : "nextPosition() called more than freq() times!"; + int position = super.nextPosition(); + assert position >= 0 || position == -1 : "invalid position: " + position; + positionCount++; + return position; + } + + @Override + public int startOffset() throws IOException { + assert state != DocsEnumState.START : "startOffset() called before nextDoc()/advance()"; + assert positionCount > 0 : "startOffset() called before nextPosition()!"; + return super.startOffset(); + } + + @Override + public int endOffset() throws IOException { + assert state != DocsEnumState.START : "endOffset() called before nextDoc()/advance()"; + assert positionCount > 0 : "endOffset() called before nextPosition()!"; + return super.endOffset(); + } + + @Override + public BytesRef getPayload() throws IOException { + assert state != DocsEnumState.START : "getPayload() called before nextDoc()/advance()"; + assert positionCount > 0 : "getPayload() called before nextPosition()!"; + return super.getPayload(); + } + + @Override + public boolean hasPayload() { + assert state != DocsEnumState.START : "hasPayload() called before nextDoc()/advance()"; + assert positionCount > 0 : "hasPayload() called before nextPosition()!"; + return super.hasPayload(); + } + } +} Index: lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java (revision 1361189) +++ lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java (working copy) @@ -1006,11 +1006,11 @@ */ public static IndexReader maybeWrapReader(IndexReader r) throws IOException { Random random = random(); - if (rarely()) { + if (true || /* nocommit: */ rarely()) { // TODO: remove this, and fix those tests to wrap before putting slow around: final boolean wasOriginallyAtomic = r instanceof AtomicReader; for (int i = 0, c = random.nextInt(6)+1; i < c; i++) { - switch(random.nextInt(4)) { + switch(4 /* nocommit: random.nextInt(5) */) { case 0: r = SlowCompositeReaderWrapper.wrap(r); break; @@ -1041,6 +1041,16 @@ new FieldFilterAtomicReader(ar, fields, true) ); break; + case 4: + // H√§ckidy-Hick-Hack: a standard Reader will cause FC insanity, so we use + // QueryUtils' reader with a fake cache key, so insanity checker cannot walk + // along our reader: + if (r instanceof AtomicReader) { + r = new FCInvisibleMultiReader(new AssertingAtomicReader((AtomicReader)r)); + } else if (r instanceof DirectoryReader) { + r = new FCInvisibleMultiReader(new AssertingDirectoryReader((DirectoryReader)r)); + } + break; default: fail("should not get here"); } Index: lucene/test-framework/src/java/org/apache/lucene/util/TestRuleSetupAndRestoreClassEnv.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/util/TestRuleSetupAndRestoreClassEnv.java (revision 1361189) +++ lucene/test-framework/src/java/org/apache/lucene/util/TestRuleSetupAndRestoreClassEnv.java (working copy) @@ -30,6 +30,7 @@ import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.appending.AppendingCodec; +import org.apache.lucene.codecs.asserting.AssertingCodec; import org.apache.lucene.codecs.lucene40.Lucene40Codec; import org.apache.lucene.codecs.mockrandom.MockRandomPostingsFormat; import org.apache.lucene.codecs.simpletext.SimpleTextCodec; @@ -189,6 +190,8 @@ codec = new SimpleTextCodec(); } else if ("Appending".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 8 && !shouldAvoidCodec("Appending"))) { codec = new AppendingCodec(); + } else if ("Asserting".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 7 && !shouldAvoidCodec("Asserting"))) { + codec = new AssertingCodec(); } else if (!"random".equals(TEST_CODEC)) { codec = Codec.forName(TEST_CODEC); } else if ("random".equals(TEST_POSTINGSFORMAT)) { Index: lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/package.html =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/package.html (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/package.html (working copy) @@ -0,0 +1,25 @@ + + + +
+ + + +Codec for testing that asserts various contracts of the codec apis. + + Index: lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingPostingsFormat.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingPostingsFormat.java (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingPostingsFormat.java (working copy) @@ -0,0 +1,88 @@ +package org.apache.lucene.codecs.asserting; + +/* + * 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. + */ + +import java.io.IOException; + +import org.apache.lucene.codecs.FieldsConsumer; +import org.apache.lucene.codecs.FieldsProducer; +import org.apache.lucene.codecs.PostingsFormat; +import org.apache.lucene.codecs.lucene40.Lucene40PostingsFormat; +import org.apache.lucene.index.AssertingAtomicReader; +import org.apache.lucene.index.FieldsEnum; +import org.apache.lucene.index.SegmentReadState; +import org.apache.lucene.index.SegmentWriteState; +import org.apache.lucene.index.Terms; + +/** + * Just like {@link Lucene40PostingsFormat} but with additional asserts. + */ +public class AssertingPostingsFormat extends PostingsFormat { + private final PostingsFormat in = new Lucene40PostingsFormat(); + + public AssertingPostingsFormat() { + super("Asserting"); + } + + // TODO: we could add some useful checks here? + @Override + public FieldsConsumer fieldsConsumer(SegmentWriteState state) throws IOException { + return in.fieldsConsumer(state); + } + + @Override + public FieldsProducer fieldsProducer(SegmentReadState state) throws IOException { + return new AssertingFieldsProducer(in.fieldsProducer(state)); + } + + static class AssertingFieldsProducer extends FieldsProducer { + private final FieldsProducer in; + + AssertingFieldsProducer(FieldsProducer in) { + this.in = in; + } + + @Override + public void close() throws IOException { + in.close(); + } + + @Override + public FieldsEnum iterator() throws IOException { + FieldsEnum iterator = in.iterator(); + assert iterator != null; + return new AssertingAtomicReader.AssertingFieldsEnum(iterator); + } + + @Override + public Terms terms(String field) throws IOException { + Terms terms = in.terms(field); + return terms == null ? null : new AssertingAtomicReader.AssertingTerms(terms); + } + + @Override + public int size() throws IOException { + return in.size(); + } + + @Override + public long getUniqueTermCount() throws IOException { + return in.getUniqueTermCount(); + } + } +} Index: lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingTermVectorsFormat.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingTermVectorsFormat.java (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingTermVectorsFormat.java (working copy) @@ -0,0 +1,72 @@ +package org.apache.lucene.codecs.asserting; + +/* + * 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. + */ + +import java.io.IOException; + +import org.apache.lucene.codecs.TermVectorsFormat; +import org.apache.lucene.codecs.TermVectorsReader; +import org.apache.lucene.codecs.TermVectorsWriter; +import org.apache.lucene.codecs.lucene40.Lucene40TermVectorsFormat; +import org.apache.lucene.index.AssertingAtomicReader; +import org.apache.lucene.index.FieldInfos; +import org.apache.lucene.index.Fields; +import org.apache.lucene.index.SegmentInfo; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.IOContext; + +/** + * Just like {@link Lucene40TermVectorsFormat} but with additional asserts. + */ +public class AssertingTermVectorsFormat extends TermVectorsFormat { + private final TermVectorsFormat in = new Lucene40TermVectorsFormat(); + + @Override + public TermVectorsReader vectorsReader(Directory directory, SegmentInfo segmentInfo, FieldInfos fieldInfos, IOContext context) throws IOException { + return new AssertingTermVectorsReader(in.vectorsReader(directory, segmentInfo, fieldInfos, context)); + } + + @Override + public TermVectorsWriter vectorsWriter(Directory directory, SegmentInfo segmentInfo, IOContext context) throws IOException { + return in.vectorsWriter(directory, segmentInfo, context); + } + + static class AssertingTermVectorsReader extends TermVectorsReader { + private final TermVectorsReader in; + + AssertingTermVectorsReader(TermVectorsReader in) { + this.in = in; + } + + @Override + public void close() throws IOException { + in.close(); + } + + @Override + public Fields get(int doc) throws IOException { + Fields fields = in.get(doc); + return fields == null ? null : new AssertingAtomicReader.AssertingFields(fields); + } + + @Override + public TermVectorsReader clone() { + return new AssertingTermVectorsReader(in.clone()); + } + } +} Index: lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java (revision 0) +++ lucene/test-framework/src/java/org/apache/lucene/codecs/asserting/AssertingCodec.java (working copy) @@ -0,0 +1,94 @@ +package org.apache.lucene.codecs.asserting; + +/* + * 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. + */ + +import org.apache.lucene.codecs.Codec; +import org.apache.lucene.codecs.DocValuesFormat; +import org.apache.lucene.codecs.FieldInfosFormat; +import org.apache.lucene.codecs.LiveDocsFormat; +import org.apache.lucene.codecs.NormsFormat; +import org.apache.lucene.codecs.PostingsFormat; +import org.apache.lucene.codecs.SegmentInfoFormat; +import org.apache.lucene.codecs.StoredFieldsFormat; +import org.apache.lucene.codecs.TermVectorsFormat; +import org.apache.lucene.codecs.lucene40.Lucene40Codec; // javadocs @link +import org.apache.lucene.codecs.lucene40.Lucene40DocValuesFormat; +import org.apache.lucene.codecs.lucene40.Lucene40FieldInfosFormat; +import org.apache.lucene.codecs.lucene40.Lucene40LiveDocsFormat; +import org.apache.lucene.codecs.lucene40.Lucene40NormsFormat; +import org.apache.lucene.codecs.lucene40.Lucene40SegmentInfoFormat; +import org.apache.lucene.codecs.lucene40.Lucene40StoredFieldsFormat; + +/** + * Acts like {@link Lucene40Codec} but with additional asserts. + */ +public class AssertingCodec extends Codec { + + private final PostingsFormat postings = new AssertingPostingsFormat(); + private final SegmentInfoFormat infos = new Lucene40SegmentInfoFormat(); + private final StoredFieldsFormat fields = new Lucene40StoredFieldsFormat(); + private final FieldInfosFormat fieldInfos = new Lucene40FieldInfosFormat(); + private final TermVectorsFormat vectors = new AssertingTermVectorsFormat(); + private final DocValuesFormat docValues = new Lucene40DocValuesFormat(); + private final NormsFormat norms = new Lucene40NormsFormat(); + private final LiveDocsFormat liveDocs = new Lucene40LiveDocsFormat(); + + public AssertingCodec() { + super("Asserting"); + } + + @Override + public PostingsFormat postingsFormat() { + return postings; + } + + @Override + public DocValuesFormat docValuesFormat() { + return docValues; + } + + @Override + public StoredFieldsFormat storedFieldsFormat() { + return fields; + } + + @Override + public TermVectorsFormat termVectorsFormat() { + return vectors; + } + + @Override + public FieldInfosFormat fieldInfosFormat() { + return fieldInfos; + } + + @Override + public SegmentInfoFormat segmentInfoFormat() { + return infos; + } + + @Override + public NormsFormat normsFormat() { + return norms; + } + + @Override + public LiveDocsFormat liveDocsFormat() { + return liveDocs; + } +}