add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / backwards / src / test / org / apache / lucene / search / TestNumericRangeQuery32.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import org.apache.lucene.analysis.MockAnalyzer;
21 import org.apache.lucene.document.Document;
22 import org.apache.lucene.document.Field;
23 import org.apache.lucene.document.NumericField;
24 import org.apache.lucene.index.IndexReader;
25 import org.apache.lucene.index.IndexWriter;
26 import org.apache.lucene.index.Term;
27 import org.apache.lucene.index.RandomIndexWriter;
28 import org.apache.lucene.store.Directory;
29 import org.apache.lucene.util.LuceneTestCase;
30 import org.apache.lucene.util.NumericUtils;
31 import org.apache.lucene.util._TestUtil;
32
33 import org.junit.Test;
34 import org.junit.AfterClass;
35 import org.junit.BeforeClass;
36
37 public class TestNumericRangeQuery32 extends LuceneTestCase {
38   // distance of entries
39   private static final int distance = 6666;
40   // shift the starting of the values to the left, to also have negative values:
41   private static final int startOffset = - 1 << 15;
42   // number of docs to generate for testing
43   private static final int noDocs = atLeast(5000);
44   
45   private static Directory directory = null;
46   private static IndexReader reader = null;
47   private static IndexSearcher searcher = null;
48   
49   @BeforeClass
50   public static void beforeClass() throws Exception {
51     directory = newDirectory();
52     RandomIndexWriter writer = new RandomIndexWriter(random, directory,
53         newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random))
54         .setMaxBufferedDocs(_TestUtil.nextInt(random, 50, 1000))
55         .setMergePolicy(newLogMergePolicy()));
56     
57     NumericField
58       field8 = new NumericField("field8", 8, Field.Store.YES, true),
59       field4 = new NumericField("field4", 4, Field.Store.YES, true),
60       field2 = new NumericField("field2", 2, Field.Store.YES, true),
61       fieldNoTrie = new NumericField("field"+Integer.MAX_VALUE, Integer.MAX_VALUE, Field.Store.YES, true),
62       ascfield8 = new NumericField("ascfield8", 8, Field.Store.NO, true),
63       ascfield4 = new NumericField("ascfield4", 4, Field.Store.NO, true),
64       ascfield2 = new NumericField("ascfield2", 2, Field.Store.NO, true);
65     
66     Document doc = new Document();
67     // add fields, that have a distance to test general functionality
68     doc.add(field8); doc.add(field4); doc.add(field2); doc.add(fieldNoTrie);
69     // add ascending fields with a distance of 1, beginning at -noDocs/2 to test the correct splitting of range and inclusive/exclusive
70     doc.add(ascfield8); doc.add(ascfield4); doc.add(ascfield2);
71     
72     // Add a series of noDocs docs with increasing int values
73     for (int l=0; l<noDocs; l++) {
74       int val=distance*l+startOffset;
75       field8.setIntValue(val);
76       field4.setIntValue(val);
77       field2.setIntValue(val);
78       fieldNoTrie.setIntValue(val);
79
80       val=l-(noDocs/2);
81       ascfield8.setIntValue(val);
82       ascfield4.setIntValue(val);
83       ascfield2.setIntValue(val);
84       writer.addDocument(doc);
85     }
86   
87     reader = writer.getReader();
88     searcher=newSearcher(reader);
89     writer.close();
90   }
91   
92   @AfterClass
93   public static void afterClass() throws Exception {
94     searcher.close();
95     searcher = null;
96     reader.close();
97     reader = null;
98     directory.close();
99     directory = null;
100   }
101   
102   @Override
103   public void setUp() throws Exception {
104     super.setUp();
105     // set the theoretical maximum term count for 8bit (see docs for the number)
106     // super.tearDown will restore the default
107     BooleanQuery.setMaxClauseCount(3*255*2 + 255);
108   }
109   
110   /** test for both constant score and boolean query, the other tests only use the constant score mode */
111   private void testRange(int precisionStep) throws Exception {
112     String field="field"+precisionStep;
113     int count=3000;
114     int lower=(distance*3/2)+startOffset, upper=lower + count*distance + (distance/3);
115     NumericRangeQuery<Integer> q = NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
116     NumericRangeFilter<Integer> f = NumericRangeFilter.newIntRange(field, precisionStep, lower, upper, true, true);
117     int lastTerms = 0;
118     for (byte i=0; i<3; i++) {
119       TopDocs topDocs;
120       int terms;
121       String type;
122       q.clearTotalNumberOfTerms();
123       f.clearTotalNumberOfTerms();
124       switch (i) {
125         case 0:
126           type = " (constant score filter rewrite)";
127           q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE);
128           topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
129           terms = q.getTotalNumberOfTerms();
130           break;
131         case 1:
132           type = " (constant score boolean rewrite)";
133           q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE);
134           topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
135           terms = q.getTotalNumberOfTerms();
136           break;
137         case 2:
138           type = " (filter)";
139           topDocs = searcher.search(new MatchAllDocsQuery(), f, noDocs, Sort.INDEXORDER);
140           terms = f.getTotalNumberOfTerms();
141           break;
142         default:
143           return;
144       }
145       if (VERBOSE) System.out.println("Found "+terms+" distinct terms in range for field '"+field+"'"+type+".");
146       ScoreDoc[] sd = topDocs.scoreDocs;
147       assertNotNull(sd);
148       assertEquals("Score doc count"+type, count, sd.length );
149       Document doc=searcher.doc(sd[0].doc);
150       assertEquals("First doc"+type, 2*distance+startOffset, Integer.parseInt(doc.get(field)) );
151       doc=searcher.doc(sd[sd.length-1].doc);
152       assertEquals("Last doc"+type, (1+count)*distance+startOffset, Integer.parseInt(doc.get(field)) );
153       if (i>0 && 
154           (searcher.getIndexReader().getSequentialSubReaders() == null || 
155            searcher.getIndexReader().getSequentialSubReaders().length == 1)) {
156         assertEquals("Distinct term number is equal for all query types", lastTerms, terms);
157       }
158       lastTerms = terms;
159     }
160   }
161
162   @Test
163   public void testRange_8bit() throws Exception {
164     testRange(8);
165   }
166   
167   @Test
168   public void testRange_4bit() throws Exception {
169     testRange(4);
170   }
171   
172   @Test
173   public void testRange_2bit() throws Exception {
174     testRange(2);
175   }
176   
177   @Test
178   public void testInverseRange() throws Exception {
179     NumericRangeFilter<Integer> f = NumericRangeFilter.newIntRange("field8", 8, 1000, -1000, true, true);
180     assertSame("A inverse range should return the EMPTY_DOCIDSET instance", DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
181     f = NumericRangeFilter.newIntRange("field8", 8, Integer.MAX_VALUE, null, false, false);
182     assertSame("A exclusive range starting with Integer.MAX_VALUE should return the EMPTY_DOCIDSET instance",
183       DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
184     f = NumericRangeFilter.newIntRange("field8", 8, null, Integer.MIN_VALUE, false, false);
185     assertSame("A exclusive range ending with Integer.MIN_VALUE should return the EMPTY_DOCIDSET instance",
186       DocIdSet.EMPTY_DOCIDSET, f.getDocIdSet(searcher.getIndexReader()));
187   }
188   
189   @Test
190   public void testOneMatchQuery() throws Exception {
191     NumericRangeQuery<Integer> q = NumericRangeQuery.newIntRange("ascfield8", 8, 1000, 1000, true, true);
192     assertSame(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE, q.getRewriteMethod());
193     TopDocs topDocs = searcher.search(q, noDocs);
194     ScoreDoc[] sd = topDocs.scoreDocs;
195     assertNotNull(sd);
196     assertEquals("Score doc count", 1, sd.length );
197   }
198   
199   private void testLeftOpenRange(int precisionStep) throws Exception {
200     String field="field"+precisionStep;
201     int count=3000;
202     int upper=(count-1)*distance + (distance/3) + startOffset;
203     NumericRangeQuery<Integer> q=NumericRangeQuery.newIntRange(field, precisionStep, null, upper, true, true);
204     TopDocs topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
205     if (VERBOSE) System.out.println("Found "+q.getTotalNumberOfTerms()+" distinct terms in left open range for field '"+field+"'.");
206     ScoreDoc[] sd = topDocs.scoreDocs;
207     assertNotNull(sd);
208     assertEquals("Score doc count", count, sd.length );
209     Document doc=searcher.doc(sd[0].doc);
210     assertEquals("First doc", startOffset, Integer.parseInt(doc.get(field)) );
211     doc=searcher.doc(sd[sd.length-1].doc);
212     assertEquals("Last doc", (count-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
213     
214     q=NumericRangeQuery.newIntRange(field, precisionStep, null, upper, false, true);
215     topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
216     sd = topDocs.scoreDocs;
217     assertNotNull(sd);
218     assertEquals("Score doc count", count, sd.length );
219     doc=searcher.doc(sd[0].doc);
220     assertEquals("First doc", startOffset, Integer.parseInt(doc.get(field)) );
221     doc=searcher.doc(sd[sd.length-1].doc);
222     assertEquals("Last doc", (count-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
223   }
224   
225   @Test
226   public void testLeftOpenRange_8bit() throws Exception {
227     testLeftOpenRange(8);
228   }
229   
230   @Test
231   public void testLeftOpenRange_4bit() throws Exception {
232     testLeftOpenRange(4);
233   }
234   
235   @Test
236   public void testLeftOpenRange_2bit() throws Exception {
237     testLeftOpenRange(2);
238   }
239   
240   private void testRightOpenRange(int precisionStep) throws Exception {
241     String field="field"+precisionStep;
242     int count=3000;
243     int lower=(count-1)*distance + (distance/3) +startOffset;
244     NumericRangeQuery<Integer> q=NumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, true);
245     TopDocs topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
246     if (VERBOSE) System.out.println("Found "+q.getTotalNumberOfTerms()+" distinct terms in right open range for field '"+field+"'.");
247     ScoreDoc[] sd = topDocs.scoreDocs;
248     assertNotNull(sd);
249     assertEquals("Score doc count", noDocs-count, sd.length );
250     Document doc=searcher.doc(sd[0].doc);
251     assertEquals("First doc", count*distance+startOffset, Integer.parseInt(doc.get(field)) );
252     doc=searcher.doc(sd[sd.length-1].doc);
253     assertEquals("Last doc", (noDocs-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
254
255     q=NumericRangeQuery.newIntRange(field, precisionStep, lower, null, true, false);
256     topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER);
257     sd = topDocs.scoreDocs;
258     assertNotNull(sd);
259     assertEquals("Score doc count", noDocs-count, sd.length );
260     doc=searcher.doc(sd[0].doc);
261     assertEquals("First doc", count*distance+startOffset, Integer.parseInt(doc.get(field)) );
262     doc=searcher.doc(sd[sd.length-1].doc);
263     assertEquals("Last doc", (noDocs-1)*distance+startOffset, Integer.parseInt(doc.get(field)) );
264   }
265   
266   @Test
267   public void testRightOpenRange_8bit() throws Exception {
268     testRightOpenRange(8);
269   }
270   
271   @Test
272   public void testRightOpenRange_4bit() throws Exception {
273     testRightOpenRange(4);
274   }
275   
276   @Test
277   public void testRightOpenRange_2bit() throws Exception {
278     testRightOpenRange(2);
279   }
280   
281   @Test
282   public void testInfiniteValues() throws Exception {
283     Directory dir = newDirectory();
284     IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random)));
285     Document doc = new Document();
286     doc.add(new NumericField("float").setFloatValue(Float.NEGATIVE_INFINITY));
287     doc.add(new NumericField("int").setIntValue(Integer.MIN_VALUE));
288     writer.addDocument(doc);
289     
290     doc = new Document();
291     doc.add(new NumericField("float").setFloatValue(Float.POSITIVE_INFINITY));
292     doc.add(new NumericField("int").setIntValue(Integer.MAX_VALUE));
293     writer.addDocument(doc);
294     
295     doc = new Document();
296     doc.add(new NumericField("float").setFloatValue(0.0f));
297     doc.add(new NumericField("int").setIntValue(0));
298     writer.addDocument(doc);
299     writer.close();
300     
301     IndexSearcher s = new IndexSearcher(dir);
302     
303     Query q=NumericRangeQuery.newIntRange("int", null, null, true, true);
304     TopDocs topDocs = s.search(q, 10);
305     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
306     
307     q=NumericRangeQuery.newIntRange("int", null, null, false, false);
308     topDocs = s.search(q, 10);
309     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
310
311     q=NumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, true, true);
312     topDocs = s.search(q, 10);
313     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
314     
315     q=NumericRangeQuery.newIntRange("int", Integer.MIN_VALUE, Integer.MAX_VALUE, false, false);
316     topDocs = s.search(q, 10);
317     assertEquals("Score doc count", 1,  topDocs.scoreDocs.length );
318
319     q=NumericRangeQuery.newFloatRange("float", null, null, true, true);
320     topDocs = s.search(q, 10);
321     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
322
323     q=NumericRangeQuery.newFloatRange("float", null, null, false, false);
324     topDocs = s.search(q, 10);
325     assertEquals("Score doc count", 3,  topDocs.scoreDocs.length );
326
327     s.close();
328     dir.close();
329   }
330   
331   private void testRandomTrieAndClassicRangeQuery(int precisionStep) throws Exception {
332     String field="field"+precisionStep;
333     int termCountT=0,termCountC=0;
334     int num = atLeast(10);
335     for (int i = 0; i < num; i++) {
336       int lower=(int)(random.nextDouble()*noDocs*distance)+startOffset;
337       int upper=(int)(random.nextDouble()*noDocs*distance)+startOffset;
338       if (lower>upper) {
339         int a=lower; lower=upper; upper=a;
340       }
341       // test inclusive range
342       NumericRangeQuery<Integer> tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
343       TermRangeQuery cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), true, true);
344       TopDocs tTopDocs = searcher.search(tq, 1);
345       TopDocs cTopDocs = searcher.search(cq, 1);
346       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
347       termCountT += tq.getTotalNumberOfTerms();
348       termCountC += cq.getTotalNumberOfTerms();
349       // test exclusive range
350       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, false);
351       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), false, false);
352       tTopDocs = searcher.search(tq, 1);
353       cTopDocs = searcher.search(cq, 1);
354       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
355       termCountT += tq.getTotalNumberOfTerms();
356       termCountC += cq.getTotalNumberOfTerms();
357       // test left exclusive range
358       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, true);
359       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), false, true);
360       tTopDocs = searcher.search(tq, 1);
361       cTopDocs = searcher.search(cq, 1);
362       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
363       termCountT += tq.getTotalNumberOfTerms();
364       termCountC += cq.getTotalNumberOfTerms();
365       // test right exclusive range
366       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, false);
367       cq=new TermRangeQuery(field, NumericUtils.intToPrefixCoded(lower), NumericUtils.intToPrefixCoded(upper), true, false);
368       tTopDocs = searcher.search(tq, 1);
369       cTopDocs = searcher.search(cq, 1);
370       assertEquals("Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits );
371       termCountT += tq.getTotalNumberOfTerms();
372       termCountC += cq.getTotalNumberOfTerms();
373     }
374     if (precisionStep == Integer.MAX_VALUE && 
375         (searcher.getIndexReader().getSequentialSubReaders() == null || 
376          searcher.getIndexReader().getSequentialSubReaders().length == 1)) {
377       assertEquals("Total number of terms should be equal for unlimited precStep", termCountT, termCountC);
378     } else if (VERBOSE) {
379       System.out.println("Average number of terms during random search on '" + field + "':");
380       System.out.println(" Trie query: " + (((double)termCountT)/(num * 4)));
381       System.out.println(" Classical query: " + (((double)termCountC)/(num * 4)));
382     }
383   }
384   
385   @Test
386   public void testRandomTrieAndClassicRangeQuery_8bit() throws Exception {
387     testRandomTrieAndClassicRangeQuery(8);
388   }
389   
390   @Test
391   public void testRandomTrieAndClassicRangeQuery_4bit() throws Exception {
392     testRandomTrieAndClassicRangeQuery(4);
393   }
394   
395   @Test
396   public void testRandomTrieAndClassicRangeQuery_2bit() throws Exception {
397     testRandomTrieAndClassicRangeQuery(2);
398   }
399   
400   @Test
401   public void testRandomTrieAndClassicRangeQuery_NoTrie() throws Exception {
402     testRandomTrieAndClassicRangeQuery(Integer.MAX_VALUE);
403   }
404   
405   private void testRangeSplit(int precisionStep) throws Exception {
406     String field="ascfield"+precisionStep;
407     // 10 random tests
408     int  num = atLeast(10);
409     for (int  i =0;  i< num; i++) {
410       int lower=(int)(random.nextDouble()*noDocs - noDocs/2);
411       int upper=(int)(random.nextDouble()*noDocs - noDocs/2);
412       if (lower>upper) {
413         int a=lower; lower=upper; upper=a;
414       }
415       // test inclusive range
416       Query tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
417       TopDocs tTopDocs = searcher.search(tq, 1);
418       assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
419       // test exclusive range
420       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, false);
421       tTopDocs = searcher.search(tq, 1);
422       assertEquals("Returned count of range query must be equal to exclusive range length", Math.max(upper-lower-1, 0), tTopDocs.totalHits );
423       // test left exclusive range
424       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, false, true);
425       tTopDocs = searcher.search(tq, 1);
426       assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
427       // test right exclusive range
428       tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, false);
429       tTopDocs = searcher.search(tq, 1);
430       assertEquals("Returned count of range query must be equal to half exclusive range length", upper-lower, tTopDocs.totalHits );
431     }
432   }
433
434   @Test
435   public void testRangeSplit_8bit() throws Exception {
436     testRangeSplit(8);
437   }
438   
439   @Test
440   public void testRangeSplit_4bit() throws Exception {
441     testRangeSplit(4);
442   }
443   
444   @Test
445   public void testRangeSplit_2bit() throws Exception {
446     testRangeSplit(2);
447   }
448   
449   /** we fake a float test using int2float conversion of NumericUtils */
450   private void testFloatRange(int precisionStep) throws Exception {
451     final String field="ascfield"+precisionStep;
452     final int lower=-1000, upper=+2000;
453     
454     Query tq=NumericRangeQuery.newFloatRange(field, precisionStep,
455       NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
456     TopDocs tTopDocs = searcher.search(tq, 1);
457     assertEquals("Returned count of range query must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
458     
459     Filter tf=NumericRangeFilter.newFloatRange(field, precisionStep,
460       NumericUtils.sortableIntToFloat(lower), NumericUtils.sortableIntToFloat(upper), true, true);
461     tTopDocs = searcher.search(new MatchAllDocsQuery(), tf, 1);
462     assertEquals("Returned count of range filter must be equal to inclusive range length", upper-lower+1, tTopDocs.totalHits );
463   }
464
465   @Test
466   public void testFloatRange_8bit() throws Exception {
467     testFloatRange(8);
468   }
469   
470   @Test
471   public void testFloatRange_4bit() throws Exception {
472     testFloatRange(4);
473   }
474   
475   @Test
476   public void testFloatRange_2bit() throws Exception {
477     testFloatRange(2);
478   }
479   
480   private void testSorting(int precisionStep) throws Exception {
481     String field="field"+precisionStep;
482     // 10 random tests, the index order is ascending,
483     // so using a reverse sort field should retun descending documents
484     int num = atLeast(10);
485     for (int i = 0; i < num; i++) {
486       int lower=(int)(random.nextDouble()*noDocs*distance)+startOffset;
487       int upper=(int)(random.nextDouble()*noDocs*distance)+startOffset;
488       if (lower>upper) {
489         int a=lower; lower=upper; upper=a;
490       }
491       Query tq=NumericRangeQuery.newIntRange(field, precisionStep, lower, upper, true, true);
492       TopDocs topDocs = searcher.search(tq, null, noDocs, new Sort(new SortField(field, SortField.INT, true)));
493       if (topDocs.totalHits==0) continue;
494       ScoreDoc[] sd = topDocs.scoreDocs;
495       assertNotNull(sd);
496       int last=Integer.parseInt(searcher.doc(sd[0].doc).get(field));
497       for (int j=1; j<sd.length; j++) {
498         int act=Integer.parseInt(searcher.doc(sd[j].doc).get(field));
499         assertTrue("Docs should be sorted backwards", last>act );
500         last=act;
501       }
502     }
503   }
504
505   @Test
506   public void testSorting_8bit() throws Exception {
507     testSorting(8);
508   }
509   
510   @Test
511   public void testSorting_4bit() throws Exception {
512     testSorting(4);
513   }
514   
515   @Test
516   public void testSorting_2bit() throws Exception {
517     testSorting(2);
518   }
519   
520   @Test
521   public void testEqualsAndHash() throws Exception {
522     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test1", 4, 10, 20, true, true));
523     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test2", 4, 10, 20, false, true));
524     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test3", 4, 10, 20, true, false));
525     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test4", 4, 10, 20, false, false));
526     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test5", 4, 10, null, true, true));
527     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test6", 4, null, 20, true, true));
528     QueryUtils.checkHashEquals(NumericRangeQuery.newIntRange("test7", 4, null, null, true, true));
529     QueryUtils.checkEqual(
530       NumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true), 
531       NumericRangeQuery.newIntRange("test8", 4, 10, 20, true, true)
532     );
533     QueryUtils.checkUnequal(
534       NumericRangeQuery.newIntRange("test9", 4, 10, 20, true, true), 
535       NumericRangeQuery.newIntRange("test9", 8, 10, 20, true, true)
536     );
537     QueryUtils.checkUnequal(
538       NumericRangeQuery.newIntRange("test10a", 4, 10, 20, true, true), 
539       NumericRangeQuery.newIntRange("test10b", 4, 10, 20, true, true)
540     );
541     QueryUtils.checkUnequal(
542       NumericRangeQuery.newIntRange("test11", 4, 10, 20, true, true), 
543       NumericRangeQuery.newIntRange("test11", 4, 20, 10, true, true)
544     );
545     QueryUtils.checkUnequal(
546       NumericRangeQuery.newIntRange("test12", 4, 10, 20, true, true), 
547       NumericRangeQuery.newIntRange("test12", 4, 10, 20, false, true)
548     );
549     QueryUtils.checkUnequal(
550       NumericRangeQuery.newIntRange("test13", 4, 10, 20, true, true), 
551       NumericRangeQuery.newFloatRange("test13", 4, 10f, 20f, true, true)
552     );
553     // the following produces a hash collision, because Long and Integer have the same hashcode, so only test equality:
554     Query q1 = NumericRangeQuery.newIntRange("test14", 4, 10, 20, true, true);
555     Query q2 = NumericRangeQuery.newLongRange("test14", 4, 10L, 20L, true, true);
556     assertFalse(q1.equals(q2));
557     assertFalse(q2.equals(q1));
558   }
559   
560   private void testEnum(int lower, int upper) throws Exception {
561     NumericRangeQuery<Integer> q = NumericRangeQuery.newIntRange("field4", 4, lower, upper, true, true);
562     FilteredTermEnum termEnum = q.getEnum(searcher.getIndexReader());
563     try {
564       int count = 0;
565       do {
566         final Term t = termEnum.term();
567         if (t != null) {
568           final int val = NumericUtils.prefixCodedToInt(t.text());
569           assertTrue("value not in bounds", val >= lower && val <= upper);
570           count++;
571         } else break;
572       } while (termEnum.next());
573       assertFalse(termEnum.next());
574       if (VERBOSE) System.out.println("TermEnum on 'field4' for range [" + lower + "," + upper + "] contained " + count + " terms.");
575     } finally {
576       termEnum.close();
577     }
578   }
579   
580   @Test
581   public void testEnum() throws Exception {
582     int count=3000;
583     int lower=(distance*3/2)+startOffset, upper=lower + count*distance + (distance/3);
584     // test enum with values
585     testEnum(lower, upper);
586     // test empty enum
587     testEnum(upper, lower);
588     // test empty enum outside of bounds
589     lower = distance*noDocs+startOffset;
590     upper = 2 * lower;
591     testEnum(lower, upper);
592   }
593   
594 }