/// Test that values loaded for FieldScoreQuery are cached properly and consumes
    /// the proper RAM resources.
    void doTestCaching(const String& field, FieldScoreQuery::Type tp) {
        // prepare expected array types for comparison
        HashMap<FieldScoreQuery::Type, CollectionValue> expectedArrayTypes = HashMap<FieldScoreQuery::Type, CollectionValue>::newInstance();
        expectedArrayTypes.put(FieldScoreQuery::BYTE, Collection<uint8_t>::newInstance());
        expectedArrayTypes.put(FieldScoreQuery::INT, Collection<int32_t>::newInstance());
        expectedArrayTypes.put(FieldScoreQuery::DOUBLE, Collection<double>::newInstance());

        IndexSearcherPtr s = newLucene<IndexSearcher>(dir, true);
        Collection<CollectionValue> innerArray = Collection<CollectionValue>::newInstance(s->getIndexReader()->getSequentialSubReaders().size());

        bool warned = false; // print warning once.
        for (int32_t i = 0; i < 10; ++i) {
            FieldScoreQueryPtr q = newLucene<FieldScoreQuery>(field, tp);
            Collection<ScoreDocPtr> h = s->search(q, FilterPtr(), 1000)->scoreDocs;
            EXPECT_EQ(N_DOCS, h.size());
            Collection<IndexReaderPtr> readers = s->getIndexReader()->getSequentialSubReaders();
            for (int32_t j = 0; j < readers.size(); ++j) {
                IndexReaderPtr reader = readers[j];
                try {
                    if (i == 0) {
                        innerArray[j] = q->valSrc->getValues(reader)->getInnerArray();
                        EXPECT_TRUE(VariantUtils::equalsType(innerArray[j], expectedArrayTypes.get(tp)));
                    } else {
                        EXPECT_TRUE(VariantUtils::equals(innerArray[j], q->valSrc->getValues(reader)->getInnerArray()));
                    }
                } catch (UnsupportedOperationException&) {
                    if (!warned) {
                        // std::cout << "WARNING: Cannot fully test values of " << StringUtils::toUTF8(q->toString());
                        warned = true;
                    }
                }
            }
        }

        // verify new values are reloaded (not reused) for a new reader
        s = newLucene<IndexSearcher>(dir, true);
        FieldScoreQueryPtr q = newLucene<FieldScoreQuery>(field, tp);
        Collection<ScoreDocPtr> h = s->search(q, FilterPtr(), 1000)->scoreDocs;
        EXPECT_EQ(N_DOCS, h.size());
        Collection<IndexReaderPtr> readers = s->getIndexReader()->getSequentialSubReaders();
        for (int32_t j = 0; j < readers.size(); ++j) {
            IndexReaderPtr reader = readers[j];
            try {
                EXPECT_TRUE(!equalCollectionValues(innerArray[j], q->valSrc->getValues(reader)->getInnerArray()));
            } catch (UnsupportedOperationException&) {
                if (!warned) {
                    // std::cout << "WARNING: Cannot fully test values of " << StringUtils::toUTF8(q->toString());
                    warned = true;
                }
            }
        }
    }
 /// Test that FieldScoreQuery returns docs with expected score.
 void doTestExactScore(const String& field, FieldScoreQuery::Type tp) {
     IndexSearcherPtr s = newLucene<IndexSearcher>(dir, true);
     QueryPtr q = newLucene<FieldScoreQuery>(field, tp);
     TopDocsPtr td = s->search(q, FilterPtr(), 1000);
     EXPECT_EQ(N_DOCS, td->totalHits);
     Collection<ScoreDocPtr> sd = td->scoreDocs;
     for (int32_t i = 0; i < sd.size(); ++i) {
         double score = sd[i]->score;
         String id = s->getIndexReader()->document(sd[i]->doc)->get(ID_FIELD);
         double expectedScore = expectedFieldScore(id); // "ID7" --> 7.0
         EXPECT_NEAR(expectedScore, score, TEST_SCORE_TOLERANCE_DELTA);
     }
 }
 void testEnumRange(int32_t lower, int32_t upper) {
     NumericRangeQueryPtr q = NumericRangeQuery::newIntRange(L"field4", 4, lower, upper, true, true);
     FilteredTermEnumPtr termEnum = newLucene<NumericRangeTermEnum>(q, searcher->getIndexReader());
     do {
         TermPtr t = termEnum->term();
         if (t) {
             int32_t val = NumericUtils::prefixCodedToInt(t->text());
             EXPECT_TRUE(val >= lower && val <= upper);
         } else {
             break;
         }
     } while (termEnum->next());
     EXPECT_TRUE(!termEnum->next());
     termEnum->close();
 }