Index: src/test/org/apache/lucene/search/TestNumericRangeQuery.java =================================================================== --- src/test/org/apache/lucene/search/TestNumericRangeQuery.java (revision 0) +++ src/test/org/apache/lucene/search/TestNumericRangeQuery.java (revision 0) @@ -0,0 +1,174 @@ +/** + * 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.search; + +import org.apache.lucene.analysis.MockAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.NumericField; +import org.apache.lucene.document.Field.Store; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +import java.util.Random; + +public class TestNumericRangeQuery extends LuceneTestCaseJ4 { + + // number of docs to generate for testing + static final int noDocs = 1000* _TestUtil.getRandomMultiplier(); + static RAMDirectory dir = null; + static IndexReader reader = null; + static IndexSearcher searcher = null; + static Random random; + static int defaultShiftWidth; + static int maxDefaultShiftMultiplier; + static long[] vals; + + static class Shift { + int pstep; + String fname; + NumericField field; + Document doc; + } + static Shift[] shifts; + + + @BeforeClass + public static void beforeClass() throws Exception { + random = newStaticRandom(TestNumericRangeQuery64.class); + dir = new RAMDirectory(); + RandomIndexWriter writer = new RandomIndexWriter(random, dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer())); + + int nFields = 10; + shifts = new Shift[nFields]; + OpenBitSet whichShifts = new OpenBitSet(65); + for (int i=0; i=64 ? i : random.nextInt(64)+1; + } while (whichShifts.getAndSet(shift)); // don't repeat shifts + shifts[i] = new Shift(); + shifts[i].pstep = shift; + shifts[i].fname = "f"+shift; + shifts[i].field = new NumericField(shifts[i].fname, shift, Store.YES, true); + shifts[i].doc = new Document(); + shifts[i].doc.add(shifts[i].field); + } + + + vals = new long[noDocs]; + randomLongs(vals); + + for (long val : vals) { + for (Shift shift : shifts) { + shift.field.setLongValue(val); + writer.addDocument(shift.doc); + } + } + + writer.close(); + + reader = IndexReader.open(dir); + searcher = new IndexSearcher(reader); + } + + @AfterClass + public static void afterClass() throws Exception { + searcher.close(); + searcher = null; + reader.close(); + reader = null; + dir.close(); + dir = null; + } + + + public static long randomLong() { + long val; + switch(random.nextInt(4)) { + case 0: + val = 1L << (random.nextInt(63)); // patterns like 0x000000100000 (-1 yields patterns like 0x0000fff) + break; + case 1: + val = -1L << (random.nextInt(63)); // patterns like 0xfffff00000 + break; + default: + val = random.nextLong(); + } + + val += random.nextInt(5)-2; + + if (random.nextBoolean()) { + if (random.nextBoolean()) val += random.nextInt(100)-50; + if (random.nextBoolean()) val = ~val; + if (random.nextBoolean()) val = val<<1; + if (random.nextBoolean()) val = val>>>1; + } + + return val; + } + + public static void randomLongs(long[] out) { + for (int i=0; i upper) { + // swap lower and upper most of the time + if (random.nextInt(8)!=0) { + long tmp = lower; lower=upper; upper=tmp; + } + } + + boolean lowerInc = random.nextBoolean(); + boolean upperInc = random.nextBoolean(); + + // calculate ourselves + int num = 0; + for (long val : vals) { + if ((val > lower || (lowerInc && val==lower)) && (val < upper || (upperInc && val==upper))) + num++; + } + + // now iterate through the different types of fields we indexed and do a range query on each + for (Shift shift : shifts) { + Query query = NumericRangeQuery.newLongRange(shift.fname, shift.pstep, lower, upper, lowerInc, upperInc); + int hits = searcher.search( query, 1 ).totalHits; + assertEquals(num, hits); + } + } +} Property changes on: src/test/org/apache/lucene/search/TestNumericRangeQuery.java ___________________________________________________________________ Added: svn:keywords + Date Author Id Revision HeadURL Added: svn:eol-style + native Index: src/java/org/apache/lucene/util/NumericUtils.java =================================================================== --- src/java/org/apache/lucene/util/NumericUtils.java (revision 964460) +++ src/java/org/apache/lucene/util/NumericUtils.java (working copy) @@ -447,7 +447,10 @@ nextMinBound = (hasLower ? (minBound + diff) : minBound) & ~mask, nextMaxBound = (hasUpper ? (maxBound - diff) : maxBound) & ~mask; - if (shift+precisionStep>=valSize || nextMinBound>nextMaxBound) { + boolean minWrap = nextMinBound < minBound; + boolean maxWrap = nextMaxBound > maxBound; + + if (shift+precisionStep>=valSize || nextMinBound>nextMaxBound || minWrap || maxWrap) { // We are in the lowest precision or the next precision is not available. addRange(builder, valSize, minBound, maxBound, shift); // exit the split recursion loop