Index: src/test/org/apache/lucene/search/CheckHits.java
===================================================================
--- src/test/org/apache/lucene/search/CheckHits.java	(revision 803879)
+++ src/test/org/apache/lucene/search/CheckHits.java	(working copy)
@@ -82,31 +82,53 @@
   public static void checkHitCollector(Query query, String defaultFieldName,
                                        Searcher searcher, int[] results)
     throws IOException {
+
+    QueryUtils.check(query,searcher);
     
     Set correct = new TreeSet();
     for (int i = 0; i < results.length; i++) {
       correct.add(new Integer(results[i]));
     }
-    
     final Set actual = new TreeSet();
-    searcher.search(query, new Collector() {
-        private int base = 0;
-        public void setScorer(Scorer scorer) throws IOException {}
-        public void collect(int doc) {
-          actual.add(new Integer(doc + base));
-        }
-        public void setNextReader(IndexReader reader, int docBase) {
-          base = docBase;
-        }
-        public boolean acceptsDocsOutOfOrder() {
-          return true;
-        }
-      });
-    Assert.assertEquals(query.toString(defaultFieldName), correct, actual);
+    final Collector c = new SetCollector(actual);
 
-    QueryUtils.check(query,searcher);
+    searcher.search(query, c);
+    Assert.assertEquals("Simple: " + query.toString(defaultFieldName), 
+                        correct, actual);
+
+    actual.clear();
+    
+    QueryUtils.wrapSearcher(searcher).search(query, c);
+    Assert.assertEquals("Wrapped Searcher: "+query.toString(defaultFieldName),
+                        correct, actual);
+                        
+    if ( ! ( searcher instanceof IndexSearcher ) ) return;
+
+    actual.clear();
+    QueryUtils.wrapUnderlyingReader((IndexSearcher)searcher).search(query, c);
+    Assert.assertEquals("Wrapped Reader: "+query.toString(defaultFieldName),
+                        correct, actual);
+
   }
-  
+
+  public static class SetCollector extends Collector {
+    final Set bag;
+    public SetCollector(Set bag) {
+      this.bag = bag;
+    }
+    private int base = 0;
+    public void setScorer(Scorer scorer) throws IOException {}
+    public void collect(int doc) {
+      bag.add(new Integer(doc + base));
+    }
+    public void setNextReader(IndexReader reader, int docBase) {
+      base = docBase;
+    }
+    public boolean acceptsDocsOutOfOrder() {
+      return true;
+    }
+  }
+
   /**
    * Tests that a query matches the an expected set of documents using Hits.
    *
Index: src/test/org/apache/lucene/search/QueryUtils.java
===================================================================
--- src/test/org/apache/lucene/search/QueryUtils.java	(revision 803879)
+++ src/test/org/apache/lucene/search/QueryUtils.java	(working copy)
@@ -5,10 +5,19 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 import junit.framework.Assert;
 
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import org.apache.lucene.document.Document;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.MultiReader;
+import org.apache.lucene.index.IndexWriter.MaxFieldLength;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.util.ReaderUtil;
 
 /**
  * Copyright 2005 Apache Software Foundation
@@ -75,12 +84,20 @@
   }
   
   /** 
-   * various query sanity checks on a searcher, including explanation checks.
-   * @see #checkExplanations
-   * @see #checkSkipTo
+   * Various query sanity checks on a searcher, some checks are only done for
+   * instanceof IndexSearcher.
+   *
    * @see #check(Query)
+   * @see #checkFirstSkipTo
+   * @see #checkSkipTo
+   * @see #checkExplanations
+   * @see #checkSerialization
+   * @see #checkEqual
    */
   public static void check(Query q1, Searcher s) {
+    check(q1, s, true);
+  }
+  private static void check(Query q1, Searcher s, boolean wrap) {
     try {
       check(q1);
       if (s!=null) {
@@ -88,6 +105,14 @@
           IndexSearcher is = (IndexSearcher)s;
           checkFirstSkipTo(q1,is);
           checkSkipTo(q1,is);
+          if (wrap) {
+            IndexSearcher wrappedR = wrapUnderlyingReader(is);
+            check(q1, wrappedR, false);
+          }
+        }
+        if (wrap) {
+          MultiSearcher wrappedS = wrapSearcher(s);
+          check(q1, wrappedS, false);
         }
         checkExplanations(q1,s);
         checkSerialization(q1,s);
@@ -101,6 +126,97 @@
     }
   }
 
+  /**
+   * Given an IndexSearcher, returns a new IndexSearcher whose IndexReader 
+   * is a MultiReader containing the Reader of the original IndexSearcher, 
+   * as well as several "empty" IndexReaders -- some of which will have 
+   * deleted documents in them.  This new IndexSearcher should 
+   * behave exactly the same as the original IndexSearcher.
+   */
+  public static IndexSearcher wrapUnderlyingReader(final IndexSearcher s) 
+    throws IOException {
+
+    // we can't put deleted docs before the nested reader, because
+    // it will through off the docIds
+    IndexReader[] readers = new IndexReader[] {
+      IndexReader.open(makeEmptyIndex(0)),
+      IndexReader.open(makeEmptyIndex(0)),
+      new MultiReader(new IndexReader[] {
+        IndexReader.open(makeEmptyIndex(0)),
+        IndexReader.open(makeEmptyIndex(0))
+      }),
+      s.getIndexReader(),
+      IndexReader.open(makeEmptyIndex(7)),
+      IndexReader.open(makeEmptyIndex(0)),
+      new MultiReader(new IndexReader[] {
+        IndexReader.open(makeEmptyIndex(5)),
+        IndexReader.open(makeEmptyIndex(0))
+      }),
+      
+    };
+    IndexSearcher out = new IndexSearcher(new MultiReader(readers));
+    out.setSimilarity(s.getSimilarity());
+    return out;
+  }
+  /**
+   * Given a Searcher, returns a new MultiSearcher wrapping the  
+   * the original Searcher, 
+   * as well as several "empty" IndexSearchers -- some of which will have
+   * deleted documents in them.  This new MultiSearcher 
+   * should behave exactly the same as the original Searcher.
+   */
+  public static MultiSearcher wrapSearcher(final Searcher s) 
+    throws IOException {
+
+    // we can't put deleted docs before the nested reader, because
+    // it will through off the docIds
+    Searcher[] searchers = new Searcher[] {
+      new IndexSearcher(makeEmptyIndex(0)),
+      new MultiSearcher(new Searcher[] {
+        new IndexSearcher(makeEmptyIndex(0)),
+        new IndexSearcher(makeEmptyIndex(0)) 
+      }),
+      s,
+      new IndexSearcher(makeEmptyIndex(3)),
+      new IndexSearcher(makeEmptyIndex(0)),
+      new MultiSearcher(new Searcher[] {
+        new IndexSearcher(makeEmptyIndex(5)),
+        new IndexSearcher(makeEmptyIndex(0)) 
+      })
+    };
+    MultiSearcher out = new MultiSearcher(searchers);
+    out.setSimilarity(s.getSimilarity());
+    return out;
+  }
+
+  private static RAMDirectory makeEmptyIndex(final int numDeletedDocs) 
+    throws IOException {
+      RAMDirectory d = new RAMDirectory();
+      IndexWriter w = new IndexWriter(d, new WhitespaceAnalyzer(), true,
+                                      MaxFieldLength.LIMITED);
+      for (int i = 0; i < numDeletedDocs; i++) {
+        w.addDocument(new Document());
+      }
+      w.commit();
+      w.deleteDocuments( new MatchAllDocsQuery() );
+      w.commit();
+
+      if (0 < numDeletedDocs)
+        Assert.assertTrue("writer has no deletions", w.hasDeletions());
+
+      Assert.assertEquals("writer is missing some deleted docs", 
+                          numDeletedDocs, w.maxDoc());
+      Assert.assertEquals("writer has non-deleted docs", 
+                          0, w.numDocs());
+      w.close();
+      IndexReader r = IndexReader.open(d);
+      Assert.assertEquals("reader has wrong number of deleted docs", 
+                          numDeletedDocs, r.numDeletedDocs());
+      r.close();
+      return d;
+  }
+  
+
   /** check that the query weight is serializable. 
    * @throws IOException if serialization check fail. 
    */
@@ -146,10 +262,6 @@
         {skip_op, skip_op, skip_op, next_op, next_op},
     };
     for (int k = 0; k < orders.length; k++) {
-      IndexReader[] readers = s.getIndexReader().getSequentialSubReaders();
-
-      for (int x = 0; x < readers.length; x++) {
-        IndexReader reader = readers[x];
 
         final int order[] = orders[k];
         // System.out.print("Order:");for (int i = 0; i < order.length; i++)
@@ -158,7 +270,7 @@
         final int opidx[] = { 0 };
 
         final Weight w = q.weight(s);
-        final Scorer scorer = w.scorer(reader, true, false);
+        final Scorer scorer = w.scorer(s.getIndexReader(), true, false);
         if (scorer == null) {
           continue;
         }
@@ -229,7 +341,6 @@
             .nextDoc()) != DocIdSetIterator.NO_MORE_DOCS;
         Assert.assertFalse(more);
       }
-    }
   }
     
   // check that first skip on just created scorers always goes to the right doc
@@ -271,7 +382,9 @@
       }
     });
     
-    IndexReader[] readers = s.getIndexReader().getSequentialSubReaders();
+    List readerList = new ArrayList();
+    ReaderUtil.gatherSubReaders(readerList, s.getIndexReader());
+    IndexReader[] readers = (IndexReader[]) readerList.toArray(new IndexReader[0]);
     for(int i = 0; i < readers.length; i++) {
       IndexReader reader = readers[i];
       Weight w = q.weight(s);
Index: src/test/org/apache/lucene/search/TestComplexExplanations.java
===================================================================
--- src/test/org/apache/lucene/search/TestComplexExplanations.java	(revision 803879)
+++ src/test/org/apache/lucene/search/TestComplexExplanations.java	(working copy)
@@ -59,11 +59,11 @@
           Occur.SHOULD);
     
     Query t = new FilteredQuery(qp.parse("xx"),
-                                new ItemizedFilter(new int[] {1,3}));
+                                new ItemizedFilter(searcher.getIndexReader(),new int[] {1,3}));
     t.setBoost(1000);
     q.add(t, Occur.SHOULD);
     
-    t = new ConstantScoreQuery(new ItemizedFilter(new int[] {0,2}));
+    t = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(),new int[] {0,2}));
     t.setBoost(30);
     q.add(t, Occur.SHOULD);
     
@@ -107,11 +107,11 @@
           Occur.SHOULD);
     
     Query t = new FilteredQuery(qp.parse("xx"),
-                                new ItemizedFilter(new int[] {1,3}));
+                                new ItemizedFilter(searcher.getIndexReader(),new int[] {1,3}));
     t.setBoost(1000);
     q.add(t, Occur.SHOULD);
     
-    t = new ConstantScoreQuery(new ItemizedFilter(new int[] {0,2}));
+    t = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(),new int[] {0,2}));
     t.setBoost(-20.0f);
     q.add(t, Occur.SHOULD);
     
@@ -164,12 +164,12 @@
   
   public void testFQ5() throws Exception {
     bqtest(new FilteredQuery(qp.parse("xx^0"),
-                             new ItemizedFilter(new int[] {1,3})),
+                             new ItemizedFilter(searcher.getIndexReader(),new int[] {1,3})),
            new int[] {3});
   }
   
   public void testCSQ4() throws Exception {
-    Query q = new ConstantScoreQuery(new ItemizedFilter(new int[] {3}));
+    Query q = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(), new int[] {3}));
     q.setBoost(0);
     bqtest(q, new int[] {3});
   }
Index: src/test/org/apache/lucene/search/TestExplanations.java
===================================================================
--- src/test/org/apache/lucene/search/TestExplanations.java	(revision 803879)
+++ src/test/org/apache/lucene/search/TestExplanations.java	(working copy)
@@ -17,26 +17,26 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.search.spans.*;
-import org.apache.lucene.store.RAMDirectory;
-
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.Term;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
 
 import org.apache.lucene.analysis.WhitespaceAnalyzer;
-
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
-
-import org.apache.lucene.queryParser.QueryParser;
-import org.apache.lucene.queryParser.ParseException;
-
-import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.spans.SpanFirstQuery;
+import org.apache.lucene.search.spans.SpanNearQuery;
+import org.apache.lucene.search.spans.SpanNotQuery;
+import org.apache.lucene.search.spans.SpanOrQuery;
+import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.SpanTermQuery;
+import org.apache.lucene.store.RAMDirectory;
 import org.apache.lucene.util.DocIdBitSet;
-
-import java.util.Random;
-import java.util.BitSet;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.ReaderUtil;
 
 /**
  * Tests primative queries (ie: that rewrite to themselves) to
@@ -120,14 +120,31 @@
   /** A filter that only lets the specified document numbers pass */
   public static class ItemizedFilter extends Filter {
     int[] docs;
-    public ItemizedFilter(int[] docs) {
+    int base;
+    private transient IndexReader topReader;
+    private transient IndexReader firstSubReader;
+    public ItemizedFilter(IndexReader topReader, int[] docs) {
       this.docs = docs;
+      this.topReader = topReader;
+      List subReaders = new ArrayList();
+      ReaderUtil.gatherSubReaders(subReaders, topReader);
+      firstSubReader = (IndexReader) subReaders.get(0);
     }
     public DocIdSet getDocIdSet(IndexReader r) {
+      if(r == topReader || r == firstSubReader) {
+        // we need to reset the base when a new search
+        // is being done - this will happen either when the
+        // original top level reader is passed, or when
+        // the first sub-reader is passed
+        base = 0;
+      }
       BitSet b = new BitSet(r.maxDoc());
       for (int i = 0; i < docs.length; i++) {
-        b.set(docs[i]);
+        if(docs[i] >= base && docs[i] < base + r.maxDoc()) {
+          b.set(docs[i]);
+        }
       }
+      base += r.maxDoc();
       return new DocIdBitSet(b);
     }
   }
Index: src/test/org/apache/lucene/search/TestSimpleExplanations.java
===================================================================
--- src/test/org/apache/lucene/search/TestSimpleExplanations.java	(revision 803879)
+++ src/test/org/apache/lucene/search/TestSimpleExplanations.java	(working copy)
@@ -75,27 +75,27 @@
   
   public void testFQ1() throws Exception {
     qtest(new FilteredQuery(qp.parse("w1"),
-                            new ItemizedFilter(new int[] {0,1,2,3})),
+                            new ItemizedFilter(searcher.getIndexReader(), new int[] {0,1,2,3})),
           new int[] {0,1,2,3});
   }
   public void testFQ2() throws Exception {
     qtest(new FilteredQuery(qp.parse("w1"),
-                            new ItemizedFilter(new int[] {0,2,3})),
+                            new ItemizedFilter(searcher.getIndexReader(), new int[] {0,2,3})),
           new int[] {0,2,3});
   }
   public void testFQ3() throws Exception {
     qtest(new FilteredQuery(qp.parse("xx"),
-                            new ItemizedFilter(new int[] {1,3})),
+                            new ItemizedFilter(searcher.getIndexReader(), new int[] {1,3})),
           new int[] {3});
   }
   public void testFQ4() throws Exception {
     qtest(new FilteredQuery(qp.parse("xx^1000"),
-                            new ItemizedFilter(new int[] {1,3})),
+                            new ItemizedFilter(searcher.getIndexReader(), new int[] {1,3})),
           new int[] {3});
   }
   public void testFQ6() throws Exception {
     Query q = new FilteredQuery(qp.parse("xx"),
-                                new ItemizedFilter(new int[] {1,3}));
+                                new ItemizedFilter(searcher.getIndexReader(), new int[] {1,3}));
     q.setBoost(1000);
     qtest(q, new int[] {3});
   }
@@ -103,15 +103,15 @@
   /* ConstantScoreQueries */
   
   public void testCSQ1() throws Exception {
-    Query q = new ConstantScoreQuery(new ItemizedFilter(new int[] {0,1,2,3}));
+    Query q = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(), new int[] {0,1,2,3}));
     qtest(q, new int[] {0,1,2,3});
   }
   public void testCSQ2() throws Exception {
-    Query q = new ConstantScoreQuery(new ItemizedFilter(new int[] {1,3}));
+    Query q = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(), new int[] {1,3}));
     qtest(q, new int[] {1,3});
   }
   public void testCSQ3() throws Exception {
-    Query q = new ConstantScoreQuery(new ItemizedFilter(new int[] {0,2}));
+    Query q = new ConstantScoreQuery(new ItemizedFilter(searcher.getIndexReader(), new int[] {0,2}));
     q.setBoost(1000);
     qtest(q, new int[] {0,2});
   }

