You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2014/12/31 20:12:19 UTC

[13/14] lucenenet git commit: Moving Lucene.Net.Facet tests to their appropriate place

Moving Lucene.Net.Facet tests to their appropriate place


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/68aa9728
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/68aa9728
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/68aa9728

Branch: refs/heads/master
Commit: 68aa9728012959d79a9118628678820b115d8620
Parents: b47de89
Author: Itamar Syn-Hershko <it...@code972.com>
Authored: Wed Dec 31 21:09:48 2014 +0200
Committer: Itamar Syn-Hershko <it...@code972.com>
Committed: Wed Dec 31 21:09:48 2014 +0200

----------------------------------------------------------------------
 Lucene.Net.sln                                  |   14 +-
 .../AssertingSubDocsAtOnceCollector.cs          |   85 ++
 src/Lucene.Net.Tests.Facet/FacetTestCase.cs     |  293 ++++
 .../Lucene.Net.Tests.Facet.csproj               |  100 ++
 .../Properties/AssemblyInfo.cs                  |   36 +
 .../Range/TestRangeFacetCounts.cs               | 1174 +++++++++++++++
 src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs  |  261 ++++
 .../SortedSet/TestSortedSetDocValuesFacets.cs   |  394 ++++++
 .../Taxonomy/Directory/TestAddTaxonomy.cs       |  323 +++++
 .../Directory/TestConcurrentFacetedIndexing.cs  |  228 +++
 .../Directory/TestDirectoryTaxonomyReader.cs    |  624 ++++++++
 .../Directory/TestDirectoryTaxonomyWriter.cs    |  588 ++++++++
 .../Taxonomy/TestCachedOrdinalsReader.cs        |  116 ++
 .../Taxonomy/TestFacetLabel.cs                  |  360 +++++
 .../Taxonomy/TestLRUHashMap.cs                  |   65 +
 .../Taxonomy/TestSearcherTaxonomyManager.cs     |  398 ++++++
 .../Taxonomy/TestTaxonomyCombined.cs            | 1185 ++++++++++++++++
 .../Taxonomy/TestTaxonomyFacetAssociations.cs   |  278 ++++
 .../Taxonomy/TestTaxonomyFacetCounts.cs         |  851 +++++++++++
 .../Taxonomy/TestTaxonomyFacetCounts2.cs        |  403 ++++++
 .../Taxonomy/TestTaxonomyFacetSumValueSource.cs |  610 ++++++++
 .../Taxonomy/WriterCache/TestCharBlockArray.cs  |  110 ++
 .../WriterCache/TestCompactLabelToOrdinal.cs    |  151 ++
 .../TestDrillDownQuery.cs                       |  282 ++++
 src/Lucene.Net.Tests.Facet/TestDrillSideways.cs | 1332 ++++++++++++++++++
 src/Lucene.Net.Tests.Facet/TestFacetsConfig.cs  |  131 ++
 .../TestMultipleIndexFields.cs                  |  300 ++++
 .../TestRandomSamplingFacetsCollector.cs        |  154 ++
 src/Lucene.Net.Tests.Facet/app.config           |   11 +
 src/Lucene.Net.Tests.Facet/packages.config      |    5 +
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   25 -
 .../Facet/AssertingSubDocsAtOnceCollector.cs    |   85 --
 .../core/Facet/FacetTestCase.cs                 |  293 ----
 .../core/Facet/Range/TestRangeFacetCounts.cs    | 1174 ---------------
 .../core/Facet/SlowRAMDirectory.cs              |  261 ----
 .../SortedSet/TestSortedSetDocValuesFacets.cs   |  394 ------
 .../Facet/Taxonomy/Directory/TestAddTaxonomy.cs |  323 -----
 .../Directory/TestConcurrentFacetedIndexing.cs  |  228 ---
 .../Directory/TestDirectoryTaxonomyReader.cs    |  624 --------
 .../Directory/TestDirectoryTaxonomyWriter.cs    |  588 --------
 .../Facet/Taxonomy/TestCachedOrdinalsReader.cs  |  116 --
 .../core/Facet/Taxonomy/TestFacetLabel.cs       |  360 -----
 .../core/Facet/Taxonomy/TestLRUHashMap.cs       |   65 -
 .../Taxonomy/TestSearcherTaxonomyManager.cs     |  398 ------
 .../core/Facet/Taxonomy/TestTaxonomyCombined.cs | 1185 ----------------
 .../Taxonomy/TestTaxonomyFacetAssociations.cs   |  278 ----
 .../Facet/Taxonomy/TestTaxonomyFacetCounts.cs   |  851 -----------
 .../Facet/Taxonomy/TestTaxonomyFacetCounts2.cs  |  403 ------
 .../Taxonomy/TestTaxonomyFacetSumValueSource.cs |  610 --------
 .../Taxonomy/WriterCache/TestCharBlockArray.cs  |  110 --
 .../WriterCache/TestCompactLabelToOrdinal.cs    |  151 --
 .../core/Facet/TestDrillDownQuery.cs            |  282 ----
 .../core/Facet/TestDrillSideways.cs             | 1332 ------------------
 .../core/Facet/TestFacetsConfig.cs              |  131 --
 .../core/Facet/TestMultipleIndexFields.cs       |  300 ----
 .../Facet/TestRandomSamplingFacetsCollector.cs  |  154 --
 56 files changed, 10861 insertions(+), 10722 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 9fb7415..2577faa 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2013
-VisualStudioVersion = 12.0.30723.0
+VisualStudioVersion = 12.0.30501.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net", "src\Lucene.Net.Core\Lucene.Net.csproj", "{5D4AD9BE-1FFB-41AB-9943-25737971BF57}"
 EndProject
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Queries", "src\L
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Facet", "src\Lucene.Net.Facet\Lucene.Net.Facet.csproj", "{48F7884A-9454-4E88-8413-9D35992CB440}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Facet", "src\Lucene.Net.Tests.Facet\Lucene.Net.Tests.Facet.csproj", "{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -74,6 +76,16 @@ Global
 		{48F7884A-9454-4E88-8413-9D35992CB440}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{48F7884A-9454-4E88-8413-9D35992CB440}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{48F7884A-9454-4E88-8413-9D35992CB440}.Release|x86.ActiveCfg = Release|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/AssertingSubDocsAtOnceCollector.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/AssertingSubDocsAtOnceCollector.cs b/src/Lucene.Net.Tests.Facet/AssertingSubDocsAtOnceCollector.cs
new file mode 100644
index 0000000..c3730df
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/AssertingSubDocsAtOnceCollector.cs
@@ -0,0 +1,85 @@
+using System.Collections.Generic;
+using Apache.NMS;
+
+namespace Lucene.Net.Facet
+{
+
+    /*
+     * 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.
+     */
+
+
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using Collector = Lucene.Net.Search.Collector;
+    using ChildScorer = Lucene.Net.Search.Scorer.ChildScorer;
+    using Scorer = Lucene.Net.Search.Scorer;
+
+    /// <summary>
+    /// Verifies in collect() that all child subScorers are on
+    ///  the collected doc. 
+    /// </summary>
+    internal class AssertingSubDocsAtOnceCollector : Collector
+    {
+
+        // TODO: allow wrapping another Collector
+
+        internal IList<Scorer> allScorers;
+
+        public override Scorer Scorer
+        {
+            set
+            {
+                // Gathers all scorers, including value and "under":
+                allScorers = new List<Scorer>();
+                allScorers.Add(value);
+                int upto = 0;
+                while (upto < allScorers.Count)
+                {
+                    value = allScorers[upto++];
+                    foreach (ChildScorer sub in value.Children)
+                    {
+                        allScorers.Add(sub.Child);
+                    }
+                }
+            }
+        }
+
+        public override void Collect(int docID)
+        {
+            foreach (Scorer s in allScorers)
+            {
+                if (docID != s.DocID())
+                {
+                    throw new IllegalStateException("subScorer=" + s + " has docID=" + s.DocID() + " != collected docID=" + docID);
+                }
+            }
+        }
+
+        public override AtomicReaderContext NextReader
+        {
+            set
+            {
+            }
+        }
+
+        public override bool AcceptsDocsOutOfOrder()
+        {
+            return false;
+        }
+
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/FacetTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/FacetTestCase.cs b/src/Lucene.Net.Tests.Facet/FacetTestCase.cs
new file mode 100644
index 0000000..6c2e508
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/FacetTestCase.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Linq;
+using Lucene.Net.Facet;
+using Lucene.Net.Randomized.Generators;
+using Lucene.Net.Support;
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet
+{
+
+    /*
+     * 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.
+     */
+
+
+    using CachedOrdinalsReader = Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader;
+    using DocValuesOrdinalsReader = Lucene.Net.Facet.Taxonomy.DocValuesOrdinalsReader;
+    using FastTaxonomyFacetCounts = Lucene.Net.Facet.Taxonomy.FastTaxonomyFacetCounts;
+    using OrdinalsReader = Lucene.Net.Facet.Taxonomy.OrdinalsReader;
+    using TaxonomyFacetCounts = Lucene.Net.Facet.Taxonomy.TaxonomyFacetCounts;
+    using TaxonomyReader = Lucene.Net.Facet.Taxonomy.TaxonomyReader;
+    using BytesRef = Lucene.Net.Util.BytesRef;
+    using SuppressCodecs = Lucene.Net.Util.LuceneTestCase.SuppressCodecs;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+
+    [TestFixture]
+    public abstract class FacetTestCase : LuceneTestCase
+    {
+        public virtual Facets GetTaxonomyFacetCounts(TaxonomyReader taxoReader, FacetsConfig config, FacetsCollector c)
+        {
+            return GetTaxonomyFacetCounts(taxoReader, config, c, FacetsConfig.DEFAULT_INDEX_FIELD_NAME);
+        }
+        public virtual Facets GetTaxonomyFacetCounts(TaxonomyReader taxoReader, FacetsConfig config, FacetsCollector c, string indexFieldName)
+        {
+            Facets facets;
+            if (Random().NextBoolean())
+            {
+                facets = new FastTaxonomyFacetCounts(indexFieldName, taxoReader, config, c);
+            }
+            else
+            {
+                OrdinalsReader ordsReader = new DocValuesOrdinalsReader(indexFieldName);
+                if (Random().NextBoolean())
+                {
+                    ordsReader = new CachedOrdinalsReader(ordsReader);
+                }
+                facets = new TaxonomyFacetCounts(ordsReader, taxoReader, config, c);
+            }
+
+            return facets;
+        }
+
+        protected internal virtual string[] GetRandomTokens(int count)
+        {
+            string[] tokens = new string[count];
+            for (int i = 0; i < tokens.Length; i++)
+            {
+                tokens[i] = TestUtil.RandomRealisticUnicodeString(Random(), 1, 10);
+                //tokens[i] = TestUtil.RandomSimpleString(Random(), 1, 10);
+            }
+            return tokens;
+        }
+
+        protected internal virtual string PickToken(string[] tokens)
+        {
+            for (int i = 0; i < tokens.Length; i++)
+            {
+                if (Random().NextBoolean())
+                {
+                    return tokens[i];
+                }
+            }
+
+            // Move long tail onto first token:
+            return tokens[0];
+        }
+
+        protected internal class TestDoc
+        {
+            public string content;
+            public string[] dims;
+            public float value;
+        }
+
+        protected internal virtual IList<TestDoc> GetRandomDocs(string[] tokens, int count, int numDims)
+        {
+            IList<TestDoc> docs = new List<TestDoc>();
+            for (int i = 0; i < count; i++)
+            {
+                TestDoc doc = new TestDoc();
+                docs.Add(doc);
+                doc.content = PickToken(tokens);
+                doc.dims = new string[numDims];
+                for (int j = 0; j < numDims; j++)
+                {
+                    doc.dims[j] = PickToken(tokens);
+                    if (Random().Next(10) < 3)
+                    {
+                        break;
+                    }
+                }
+                if (VERBOSE)
+                {
+                    Console.WriteLine("  doc " + i + ": content=" + doc.content);
+                    for (int j = 0; j < numDims; j++)
+                    {
+                        if (doc.dims[j] != null)
+                        {
+                            Console.WriteLine("    dim[" + j + "]=" + doc.dims[j]);
+                        }
+                    }
+                }
+            }
+
+            return docs;
+        }
+
+        protected internal virtual void SortTies(IList<FacetResult> results)
+        {
+            foreach (FacetResult result in results)
+            {
+                SortTies(result.LabelValues);
+            }
+        }
+
+        protected internal virtual void SortTies(LabelAndValue[] labelValues)
+        {
+            double lastValue = -1;
+            int numInRow = 0;
+            int i = 0;
+            while (i <= labelValues.Length)
+            {
+                if (i < labelValues.Length && (double)labelValues[i].value == lastValue)
+                {
+                    numInRow++;
+                }
+                else
+                {
+                    if (numInRow > 1)
+                    {
+                        Array.Sort(labelValues, i - numInRow, i, new ComparatorAnonymousInnerClassHelper(this));
+                    }
+                    numInRow = 1;
+                    if (i < labelValues.Length)
+                    {
+                        lastValue = (double)labelValues[i].value;
+                    }
+                }
+                i++;
+            }
+        }
+
+        private class ComparatorAnonymousInnerClassHelper : IComparer<LabelAndValue>
+        {
+            private readonly FacetTestCase outerInstance;
+
+            public ComparatorAnonymousInnerClassHelper(FacetTestCase outerInstance)
+            {
+                this.outerInstance = outerInstance;
+            }
+
+            public virtual int Compare(LabelAndValue a, LabelAndValue b)
+            {
+                Debug.Assert((double)a.value == (double)b.value);
+                return (new BytesRef(a.label)).CompareTo(new BytesRef(b.label));
+            }
+        }
+
+        protected internal virtual void SortLabelValues(IList<LabelAndValue> labelValues)
+        {
+            var resArray = labelValues.ToArray();
+            Array.Sort(resArray,new ComparatorAnonymousInnerClassHelper2(this));
+            labelValues = resArray.ToList();
+        }
+
+        private class ComparatorAnonymousInnerClassHelper2 : IComparer<LabelAndValue>
+        {
+            private readonly FacetTestCase outerInstance;
+
+            public ComparatorAnonymousInnerClassHelper2(FacetTestCase outerInstance)
+            {
+                this.outerInstance = outerInstance;
+            }
+
+            public virtual int Compare(LabelAndValue a, LabelAndValue b)
+            {
+                if ((double)a.value > (double)b.value)
+                {
+                    return -1;
+                }
+                else if ((double)a.value < (double)b.value)
+                {
+                    return 1;
+                }
+                else
+                {
+                    return (new BytesRef(a.label)).CompareTo(new BytesRef(b.label));
+                }
+            }
+        }
+
+        protected internal virtual void SortFacetResults(IList<FacetResult> results)
+        {
+            var resArray = results.ToArray();
+            Array.Sort(resArray, new ComparatorAnonymousInnerClassHelper3(this));
+            results = resArray.ToList();
+        }
+
+        private class ComparatorAnonymousInnerClassHelper3 : IComparer<FacetResult>
+        {
+            private readonly FacetTestCase outerInstance;
+
+            public ComparatorAnonymousInnerClassHelper3(FacetTestCase outerInstance)
+            {
+                this.outerInstance = outerInstance;
+            }
+
+            public virtual int Compare(FacetResult a, FacetResult b)
+            {
+                if ((double)a.Value > (double)b.Value)
+                {
+                    return -1;
+                }
+                else if ((double)b.Value > (double)a.Value)
+                {
+                    return 1;
+                }
+                else
+                {
+                    return 0;
+                }
+            }
+        }
+
+        [Test]
+        protected internal virtual void AssertFloatValuesEquals(IList<FacetResult> a, IList<FacetResult> b)
+        {
+            Assert.AreEqual(a.Count, b.Count);
+            float lastValue = float.PositiveInfinity;
+            IDictionary<string, FacetResult> aByDim = new Dictionary<string, FacetResult>();
+            for (int i = 0; i < a.Count; i++)
+            {
+                Assert.True((float)a[i].Value <= lastValue);
+                lastValue = (float)a[i].Value;
+                aByDim[a[i].Dim] = a[i];
+            }
+            lastValue = float.PositiveInfinity;
+            IDictionary<string, FacetResult> bByDim = new Dictionary<string, FacetResult>();
+            for (int i = 0; i < b.Count; i++)
+            {
+                bByDim[b[i].Dim] = b[i];
+                Assert.True((float)b[i].Value <= lastValue);
+                lastValue = (float)b[i].Value;
+            }
+            foreach (string dim in aByDim.Keys)
+            {
+                AssertFloatValuesEquals(aByDim[dim], bByDim[dim]);
+            }
+        }
+
+        [Test]
+        protected internal virtual void AssertFloatValuesEquals(FacetResult a, FacetResult b)
+        {
+            Assert.AreEqual(a.Dim, b.Dim);
+            Assert.True(Arrays.Equals(a.Path, b.Path));
+            Assert.AreEqual(a.ChildCount, b.ChildCount);
+            Assert.AreEqual((float)a.Value, (float)b.Value, (float)a.Value / 1e5);
+            Assert.AreEqual(a.LabelValues.Length, b.LabelValues.Length);
+            for (int i = 0; i < a.LabelValues.Length; i++)
+            {
+                Assert.AreEqual(a.LabelValues[i].label, b.LabelValues[i].label);
+                Assert.AreEqual((float)a.LabelValues[i].value, (float)b.LabelValues[i].value, (float)a.LabelValues[i].value / 1e5);
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Lucene.Net.Tests.Facet.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Lucene.Net.Tests.Facet.csproj b/src/Lucene.Net.Tests.Facet/Lucene.Net.Tests.Facet.csproj
new file mode 100644
index 0000000..df0589f
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Lucene.Net.Tests.Facet.csproj
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{4D77E491-F50F-4A0C-9BD9-F9AB655720AD}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Tests.Classification</RootNamespace>
+    <AssemblyName>Lucene.Net.Tests.Classification</AssemblyName>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Apache.NMS">
+      <HintPath>..\..\packages\Apache.NMS.1.6.0.3083\lib\net40\Apache.NMS.dll</HintPath>
+    </Reference>
+    <Reference Include="Lucene.Net.TestFramework">
+      <HintPath>..\Lucene.Net.Tests\bin\Debug\Lucene.Net.TestFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="nunit.framework">
+      <HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="Microsoft.CSharp" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AssertingSubDocsAtOnceCollector.cs" />
+    <Compile Include="FacetTestCase.cs" />
+    <Compile Include="Range\TestRangeFacetCounts.cs" />
+    <Compile Include="SlowRAMDirectory.cs" />
+    <Compile Include="SortedSet\TestSortedSetDocValuesFacets.cs" />
+    <Compile Include="Taxonomy\Directory\TestAddTaxonomy.cs" />
+    <Compile Include="Taxonomy\Directory\TestConcurrentFacetedIndexing.cs" />
+    <Compile Include="Taxonomy\Directory\TestDirectoryTaxonomyReader.cs" />
+    <Compile Include="Taxonomy\Directory\TestDirectoryTaxonomyWriter.cs" />
+    <Compile Include="Taxonomy\TestCachedOrdinalsReader.cs" />
+    <Compile Include="Taxonomy\TestFacetLabel.cs" />
+    <Compile Include="Taxonomy\TestLRUHashMap.cs" />
+    <Compile Include="Taxonomy\TestSearcherTaxonomyManager.cs" />
+    <Compile Include="Taxonomy\TestTaxonomyCombined.cs" />
+    <Compile Include="Taxonomy\TestTaxonomyFacetAssociations.cs" />
+    <Compile Include="Taxonomy\TestTaxonomyFacetCounts.cs" />
+    <Compile Include="Taxonomy\TestTaxonomyFacetCounts2.cs" />
+    <Compile Include="Taxonomy\TestTaxonomyFacetSumValueSource.cs" />
+    <Compile Include="Taxonomy\WriterCache\TestCharBlockArray.cs" />
+    <Compile Include="Taxonomy\WriterCache\TestCompactLabelToOrdinal.cs" />
+    <Compile Include="TestDrillDownQuery.cs" />
+    <Compile Include="TestDrillSideways.cs" />
+    <Compile Include="TestFacetsConfig.cs" />
+    <Compile Include="TestMultipleIndexFields.cs" />
+    <Compile Include="TestRandomSamplingFacetsCollector.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Core\Lucene.Net.csproj">
+      <Project>{5D4AD9BE-1FFB-41AB-9943-25737971BF57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
+      <Project>{48f7884a-9454-4e88-8413-9d35992cb440}</Project>
+      <Name>Lucene.Net.Facet</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Queries\Lucene.Net.Queries.csproj">
+      <Project>{69d7956c-c2cc-4708-b399-a188fec384c4}</Project>
+      <Name>Lucene.Net.Queries</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Properties/AssemblyInfo.cs b/src/Lucene.Net.Tests.Facet/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e1a47e2
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Lucene.Net.Tests.Classification")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Tests.Classification")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("253246a8-7b09-4251-ab4c-7971d3b2be4a")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Range/TestRangeFacetCounts.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Range/TestRangeFacetCounts.cs b/src/Lucene.Net.Tests.Facet/Range/TestRangeFacetCounts.cs
new file mode 100644
index 0000000..bb09c43
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Range/TestRangeFacetCounts.cs
@@ -0,0 +1,1174 @@
+using System;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+using Lucene.Net.Facet.Range;
+using Lucene.Net.Randomized.Generators;
+using Lucene.Net.Support;
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet.Range
+{
+
+    /*
+     * 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.
+     */
+
+
+    using Document = Lucene.Net.Documents.Document;
+    using DoubleDocValuesField = Lucene.Net.Documents.DoubleDocValuesField;
+    using DoubleField = Lucene.Net.Documents.DoubleField;
+    using Field = Lucene.Net.Documents.Field;
+    using FloatDocValuesField = Lucene.Net.Documents.FloatDocValuesField;
+    using FloatField = Lucene.Net.Documents.FloatField;
+    using LongField = Lucene.Net.Documents.LongField;
+    using NumericDocValuesField = Lucene.Net.Documents.NumericDocValuesField;
+    using DrillSidewaysResult = Lucene.Net.Facet.DrillSideways.DrillSidewaysResult;
+    using TaxonomyReader = Lucene.Net.Facet.Taxonomy.TaxonomyReader;
+    using DirectoryTaxonomyReader = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyReader;
+    using DirectoryTaxonomyWriter = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyWriter;
+    using AtomicReader = Lucene.Net.Index.AtomicReader;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using FunctionValues = Lucene.Net.Queries.Function.FunctionValues;
+    using ValueSource = Lucene.Net.Queries.Function.ValueSource;
+    using DoubleDocValues = Lucene.Net.Queries.Function.DocValues.DoubleDocValues;
+    using DoubleFieldSource = Lucene.Net.Queries.Function.ValueSources.DoubleFieldSource;
+    using FloatFieldSource = Lucene.Net.Queries.Function.ValueSources.FloatFieldSource;
+    using LongFieldSource = Lucene.Net.Queries.Function.ValueSources.LongFieldSource;
+    using CachingWrapperFilter = Lucene.Net.Search.CachingWrapperFilter;
+    using DocIdSet = Lucene.Net.Search.DocIdSet;
+    using DocIdSetIterator = Lucene.Net.Search.DocIdSetIterator;
+    using Filter = Lucene.Net.Search.Filter;
+    using IndexSearcher = Lucene.Net.Search.IndexSearcher;
+    using MatchAllDocsQuery = Lucene.Net.Search.MatchAllDocsQuery;
+    using Lucene.Net.Search;
+    using QueryWrapperFilter = Lucene.Net.Search.QueryWrapperFilter;
+    using Directory = Lucene.Net.Store.Directory;
+    using FixedBitSet = Lucene.Net.Util.FixedBitSet;
+    using IOUtils = Lucene.Net.Util.IOUtils;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+
+    [TestFixture]
+    public class TestRangeFacetCounts : FacetTestCase
+    {
+
+        [Test]
+        public virtual void TestBasicLong()
+        {
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            NumericDocValuesField field = new NumericDocValuesField("field", 0L);
+            doc.Add(field);
+            for (long l = 0; l < 100; l++)
+            {
+                field.LongValue = l;
+                w.AddDocument(doc);
+            }
+
+            // Also add Long.MAX_VALUE
+            field.LongValue = long.MaxValue;
+            w.AddDocument(doc);
+
+            IndexReader r = w.Reader;
+            w.Dispose();
+
+            FacetsCollector fc = new FacetsCollector();
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+
+            Facets facets = new LongRangeFacetCounts("field", fc, new LongRange("less than 10", 0L, true, 10L, false), new LongRange("less than or equal to 10", 0L, true, 10L, true), new LongRange("over 90", 90L, false, 100L, false), new LongRange("90 or above", 90L, true, 100L, false), new LongRange("over 1000", 1000L, false, long.MaxValue, true));
+
+            FacetResult result = facets.GetTopChildren(10, "field");
+
+            Assert.AreEqual("dim=field path=[] value=22 childCount=5\n  less than 10 (10)\n  less than or equal to 10 (11)\n  over 90 (9)\n  90 or above (10)\n  over 1000 (1)\n", result.ToString());
+
+            r.Dispose();
+            d.Dispose();
+        }
+
+        [Test]
+        public virtual void TestUselessRange()
+        {
+            try
+            {
+                new LongRange("useless", 7, true, 6, true);
+                Fail("did not hit expected exception");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new LongRange("useless", 7, true, 7, false);
+                Fail("did not hit expected exception");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new DoubleRange("useless", 7.0, true, 6.0, true);
+                Fail("did not hit expected exception");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new DoubleRange("useless", 7.0, true, 7.0, false);
+                Fail("did not hit expected exception");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public virtual void TestLongMinMax()
+        {
+
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            NumericDocValuesField field = new NumericDocValuesField("field", 0L);
+            doc.Add(field);
+            field.LongValue = long.MinValue;
+            w.AddDocument(doc);
+            field.LongValue = 0;
+            w.AddDocument(doc);
+            field.LongValue = long.MaxValue;
+            w.AddDocument(doc);
+
+            IndexReader r = w.Reader;
+            w.Dispose();
+
+            FacetsCollector fc = new FacetsCollector();
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+
+            Facets facets = new LongRangeFacetCounts("field", fc, new LongRange("min", long.MinValue, true, long.MinValue, true), new LongRange("max", long.MaxValue, true, long.MaxValue, true), new LongRange("all0", long.MinValue, true, long.MaxValue, true), new LongRange("all1", long.MinValue, false, long.MaxValue, true), new LongRange("all2", long.MinValue, true, long.MaxValue, false), new LongRange("all3", long.MinValue, false, long.MaxValue, false));
+
+            FacetResult result = facets.GetTopChildren(10, "field");
+            Assert.AreEqual("dim=field path=[] value=3 childCount=6\n  min (1)\n  max (1)\n  all0 (3)\n  all1 (2)\n  all2 (2)\n  all3 (1)\n", result.ToString());
+
+            r.Dispose();
+            d.Dispose();
+        }
+
+        [Test]
+        public virtual void TestOverlappedEndStart()
+        {
+            Directory d = NewDirectory();
+            var w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            NumericDocValuesField field = new NumericDocValuesField("field", 0L);
+            doc.Add(field);
+            for (long l = 0; l < 100; l++)
+            {
+                field.LongValue = l;
+                w.AddDocument(doc);
+            }
+            field.LongValue = long.MaxValue;
+            w.AddDocument(doc);
+
+            IndexReader r = w.Reader;
+            w.Dispose();
+
+            FacetsCollector fc = new FacetsCollector();
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+
+            Facets facets = new LongRangeFacetCounts("field", fc, new LongRange("0-10", 0L, true, 10L, true), new LongRange("10-20", 10L, true, 20L, true), new LongRange("20-30", 20L, true, 30L, true), new LongRange("30-40", 30L, true, 40L, true));
+
+            FacetResult result = facets.GetTopChildren(10, "field");
+            Assert.AreEqual("dim=field path=[] value=41 childCount=4\n  0-10 (11)\n  10-20 (11)\n  20-30 (11)\n  30-40 (11)\n", result.ToString());
+
+            r.Dispose();
+            d.Dispose();
+        }
+
+        /// <summary>
+        /// Tests single request that mixes Range and non-Range
+        ///  faceting, with DrillSideways and taxonomy. 
+        /// </summary>
+        [Test]
+        public virtual void TestMixedRangeAndNonRangeTaxonomy()
+        {
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Directory td = NewDirectory();
+            DirectoryTaxonomyWriter tw = new DirectoryTaxonomyWriter(td, IndexWriterConfig.OpenMode_e.CREATE);
+
+            FacetsConfig config = new FacetsConfig();
+
+            for (long l = 0; l < 100; l++)
+            {
+                Document doc = new Document();
+                // For computing range facet counts:
+                doc.Add(new NumericDocValuesField("field", l));
+                // For drill down by numeric range:
+                doc.Add(new LongField("field", l, Field.Store.NO));
+
+                if ((l & 3) == 0)
+                {
+                    doc.Add(new FacetField("dim", "a"));
+                }
+                else
+                {
+                    doc.Add(new FacetField("dim", "b"));
+                }
+                w.AddDocument(config.Build(tw, doc));
+            }
+
+            IndexReader r = w.Reader;
+
+            var tr = new DirectoryTaxonomyReader(tw);
+
+            IndexSearcher s = NewSearcher(r);
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: searcher=" + s);
+            }
+
+            DrillSideways ds = new DrillSidewaysAnonymousInnerClassHelper(this, s, config, tr);
+
+            // First search, no drill downs:
+            DrillDownQuery ddq = new DrillDownQuery(config);
+            DrillSidewaysResult dsr = ds.Search(null, ddq, 10);
+
+            Assert.AreEqual(100, dsr.Hits.TotalHits);
+            Assert.AreEqual("dim=dim path=[] value=100 childCount=2\n  b (75)\n  a (25)\n", dsr.Facets.GetTopChildren(10, "dim").ToString());
+            Assert.AreEqual("dim=field path=[] value=21 childCount=5\n  less than 10 (10)\n  less than or equal to 10 (11)\n  over 90 (9)\n  90 or above (10)\n  over 1000 (0)\n", dsr.Facets.GetTopChildren(10, "field").ToString());
+
+            // Second search, drill down on dim=b:
+            ddq = new DrillDownQuery(config);
+            ddq.Add("dim", "b");
+            dsr = ds.Search(null, ddq, 10);
+
+            Assert.AreEqual(75, dsr.Hits.TotalHits);
+            Assert.AreEqual("dim=dim path=[] value=100 childCount=2\n  b (75)\n  a (25)\n", dsr.Facets.GetTopChildren(10, "dim").ToString());
+            Assert.AreEqual("dim=field path=[] value=16 childCount=5\n  less than 10 (7)\n  less than or equal to 10 (8)\n  over 90 (7)\n  90 or above (8)\n  over 1000 (0)\n", dsr.Facets.GetTopChildren(10, "field").ToString());
+
+            // Third search, drill down on "less than or equal to 10":
+            ddq = new DrillDownQuery(config);
+            ddq.Add("field", NumericRangeQuery.NewLongRange("field", 0L, 10L, true, true));
+            dsr = ds.Search(null, ddq, 10);
+
+            Assert.AreEqual(11, dsr.Hits.TotalHits);
+            Assert.AreEqual("dim=dim path=[] value=11 childCount=2\n  b (8)\n  a (3)\n", dsr.Facets.GetTopChildren(10, "dim").ToString());
+            Assert.AreEqual("dim=field path=[] value=21 childCount=5\n  less than 10 (10)\n  less than or equal to 10 (11)\n  over 90 (9)\n  90 or above (10)\n  over 1000 (0)\n", dsr.Facets.GetTopChildren(10, "field").ToString());
+            IOUtils.Close(tw, tr, td, w, r, d);
+        }
+
+        private class DrillSidewaysAnonymousInnerClassHelper : DrillSideways
+        {
+            private readonly TestRangeFacetCounts outerInstance;
+
+            private new FacetsConfig config;
+
+            public DrillSidewaysAnonymousInnerClassHelper(TestRangeFacetCounts outerInstance, IndexSearcher s, FacetsConfig config, TaxonomyReader tr)
+                : base(s, config, tr)
+            {
+                this.outerInstance = outerInstance;
+                this.config = config;
+            }
+
+            protected override Facets BuildFacetsResult(FacetsCollector drillDowns, FacetsCollector[] drillSideways, string[] drillSidewaysDims)
+            {
+                FacetsCollector dimFC = drillDowns;
+                FacetsCollector fieldFC = drillDowns;
+                if (drillSideways != null)
+                {
+                    for (int i = 0; i < drillSideways.Length; i++)
+                    {
+                        string dim = drillSidewaysDims[i];
+                        if (dim.Equals("field"))
+                        {
+                            fieldFC = drillSideways[i];
+                        }
+                        else
+                        {
+                            dimFC = drillSideways[i];
+                        }
+                    }
+                }
+
+                IDictionary<string, Facets> byDim = new Dictionary<string, Facets>();
+                byDim["field"] = new LongRangeFacetCounts("field", fieldFC, new LongRange("less than 10", 0L, true, 10L, false), new LongRange("less than or equal to 10", 0L, true, 10L, true), new LongRange("over 90", 90L, false, 100L, false), new LongRange("90 or above", 90L, true, 100L, false), new LongRange("over 1000", 1000L, false, long.MaxValue, false));
+                byDim["dim"] = outerInstance.GetTaxonomyFacetCounts(taxoReader, config, dimFC);
+                return new MultiFacets(byDim, null);
+            }
+
+            protected override bool ScoreSubDocsAtOnce()
+            {
+                return Random().NextBoolean();
+            }
+        }
+
+        [Test]
+        public virtual void TestBasicDouble()
+        {
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            DoubleDocValuesField field = new DoubleDocValuesField("field", 0.0);
+            doc.Add(field);
+            for (long l = 0; l < 100; l++)
+            {
+                field.DoubleValue = l;
+                w.AddDocument(doc);
+            }
+
+            IndexReader r = w.Reader;
+
+            FacetsCollector fc = new FacetsCollector();
+
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+            Facets facets = new DoubleRangeFacetCounts("field", fc, new DoubleRange("less than 10", 0.0, true, 10.0, false), new DoubleRange("less than or equal to 10", 0.0, true, 10.0, true), new DoubleRange("over 90", 90.0, false, 100.0, false), new DoubleRange("90 or above", 90.0, true, 100.0, false), new DoubleRange("over 1000", 1000.0, false, double.PositiveInfinity, false));
+
+            Assert.AreEqual("dim=field path=[] value=21 childCount=5\n  less than 10 (10)\n  less than or equal to 10 (11)\n  over 90 (9)\n  90 or above (10)\n  over 1000 (0)\n", facets.GetTopChildren(10, "field").ToString());
+
+            IOUtils.Close(w, r, d);
+        }
+
+        [Test]
+        public virtual void TestBasicFloat()
+        {
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            FloatDocValuesField field = new FloatDocValuesField("field", 0.0f);
+            doc.Add(field);
+            for (long l = 0; l < 100; l++)
+            {
+                field.FloatValue = l;
+                w.AddDocument(doc);
+            }
+
+            IndexReader r = w.Reader;
+
+            FacetsCollector fc = new FacetsCollector();
+
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+
+            Facets facets = new DoubleRangeFacetCounts("field", new FloatFieldSource("field"), fc, new DoubleRange("less than 10", 0.0f, true, 10.0f, false), new DoubleRange("less than or equal to 10", 0.0f, true, 10.0f, true), new DoubleRange("over 90", 90.0f, false, 100.0f, false), new DoubleRange("90 or above", 90.0f, true, 100.0f, false), new DoubleRange("over 1000", 1000.0f, false, double.PositiveInfinity, false));
+
+            Assert.AreEqual("dim=field path=[] value=21 childCount=5\n  less than 10 (10)\n  less than or equal to 10 (11)\n  over 90 (9)\n  90 or above (10)\n  over 1000 (0)\n", facets.GetTopChildren(10, "field").ToString());
+
+            IOUtils.Close(w, r, d);
+        }
+
+        [Test]
+        public virtual void TestRandomLongs()
+        {
+            Directory dir = NewDirectory();
+            var w = new RandomIndexWriter(Random(), dir);
+
+            int numDocs = AtLeast(1000);
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: numDocs=" + numDocs);
+            }
+            long[] values = new long[numDocs];
+            long minValue = long.MaxValue;
+            long maxValue = long.MinValue;
+            for (int i = 0; i < numDocs; i++)
+            {
+                Document doc = new Document();
+                long v = Random().NextLong();
+                values[i] = v;
+                doc.Add(new NumericDocValuesField("field", v));
+                doc.Add(new LongField("field", v, Field.Store.NO));
+                w.AddDocument(doc);
+                minValue = Math.Min(minValue, v);
+                maxValue = Math.Max(maxValue, v);
+            }
+            IndexReader r = w.Reader;
+
+            IndexSearcher s = NewSearcher(r);
+            FacetsConfig config = new FacetsConfig();
+
+            int numIters = AtLeast(10);
+            for (int iter = 0; iter < numIters; iter++)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: iter=" + iter);
+                }
+                int numRange = TestUtil.NextInt(Random(), 1, 100);
+                LongRange[] ranges = new LongRange[numRange];
+                int[] expectedCounts = new int[numRange];
+                long minAcceptedValue = long.MaxValue;
+                long maxAcceptedValue = long.MinValue;
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    long min;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        LongRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            min = prevRange.min;
+                        }
+                        else
+                        {
+                            min = prevRange.max;
+                        }
+                    }
+                    else
+                    {
+                        min = Random().NextLong();
+                    }
+                    long max;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        LongRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            max = prevRange.min;
+                        }
+                        else
+                        {
+                            max = prevRange.max;
+                        }
+                    }
+                    else
+                    {
+                        max = Random().NextLong();
+                    }
+
+                    if (min > max)
+                    {
+                        long x = min;
+                        min = max;
+                        max = x;
+                    }
+                    bool minIncl;
+                    bool maxIncl;
+                    if (min == max)
+                    {
+                        minIncl = true;
+                        maxIncl = true;
+                    }
+                    else
+                    {
+                        minIncl = Random().NextBoolean();
+                        maxIncl = Random().NextBoolean();
+                    }
+                    ranges[rangeID] = new LongRange("r" + rangeID, min, minIncl, max, maxIncl);
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("  range " + rangeID + ": " + ranges[rangeID]);
+                    }
+
+                    // Do "slow but hopefully correct" computation of
+                    // expected count:
+                    for (int i = 0; i < numDocs; i++)
+                    {
+                        bool accept = true;
+                        if (minIncl)
+                        {
+                            accept &= values[i] >= min;
+                        }
+                        else
+                        {
+                            accept &= values[i] > min;
+                        }
+                        if (maxIncl)
+                        {
+                            accept &= values[i] <= max;
+                        }
+                        else
+                        {
+                            accept &= values[i] < max;
+                        }
+                        if (accept)
+                        {
+                            expectedCounts[rangeID]++;
+                            minAcceptedValue = Math.Min(minAcceptedValue, values[i]);
+                            maxAcceptedValue = Math.Max(maxAcceptedValue, values[i]);
+                        }
+                    }
+                }
+
+                FacetsCollector sfc = new FacetsCollector();
+                s.Search(new MatchAllDocsQuery(), sfc);
+                Filter fastMatchFilter;
+                if (Random().NextBoolean())
+                {
+                    if (Random().NextBoolean())
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewLongRange("field", minValue, maxValue, true, true);
+                    }
+                    else
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewLongRange("field", minAcceptedValue, maxAcceptedValue, true, true);
+                    }
+                }
+                else
+                {
+                    fastMatchFilter = null;
+                }
+                ValueSource vs = new LongFieldSource("field");
+                Facets facets = new LongRangeFacetCounts("field", vs, sfc, fastMatchFilter, ranges);
+                FacetResult result = facets.GetTopChildren(10, "field");
+                Assert.AreEqual(numRange, result.LabelValues.Length);
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("  range " + rangeID + " expectedCount=" + expectedCounts[rangeID]);
+                    }
+                    LabelAndValue subNode = result.LabelValues[rangeID];
+                    Assert.AreEqual("r" + rangeID, subNode.label);
+                    Assert.AreEqual(expectedCounts[rangeID], (int)subNode.value);
+
+                    LongRange range = ranges[rangeID];
+
+                    // Test drill-down:
+                    DrillDownQuery ddq = new DrillDownQuery(config);
+                    if (Random().NextBoolean())
+                    {
+                        if (Random().NextBoolean())
+                        {
+                            ddq.Add("field", NumericRangeFilter.NewLongRange("field", range.min, range.max, range.minInclusive, range.maxInclusive));
+                        }
+                        else
+                        {
+                            ddq.Add("field", NumericRangeQuery.NewLongRange("field", range.min, range.max, range.minInclusive, range.maxInclusive));
+                        }
+                    }
+                    else
+                    {
+                        ddq.Add("field", range.GetFilter(fastMatchFilter, vs));
+                    }
+                    Assert.AreEqual(expectedCounts[rangeID], s.Search(ddq, 10).TotalHits);
+                }
+            }
+
+            IOUtils.Close(w, r, dir);
+        }
+
+        [Test]
+        public virtual void TestRandomFloats()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), dir);
+
+            int numDocs = AtLeast(1000);
+            float[] values = new float[numDocs];
+            float minValue = float.PositiveInfinity;
+            float maxValue = float.NegativeInfinity;
+            for (int i = 0; i < numDocs; i++)
+            {
+                Document doc = new Document();
+                float v = Random().NextFloat();
+                values[i] = v;
+                doc.Add(new FloatDocValuesField("field", v));
+                doc.Add(new FloatField("field", v, Field.Store.NO));
+                w.AddDocument(doc);
+                minValue = Math.Min(minValue, v);
+                maxValue = Math.Max(maxValue, v);
+            }
+            IndexReader r = w.Reader;
+
+            IndexSearcher s = NewSearcher(r);
+            FacetsConfig config = new FacetsConfig();
+
+            int numIters = AtLeast(10);
+            for (int iter = 0; iter < numIters; iter++)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: iter=" + iter);
+                }
+                int numRange = TestUtil.NextInt(Random(), 1, 5);
+                DoubleRange[] ranges = new DoubleRange[numRange];
+                int[] expectedCounts = new int[numRange];
+                float minAcceptedValue = float.PositiveInfinity;
+                float maxAcceptedValue = float.NegativeInfinity;
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: " + numRange + " ranges");
+                }
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    double min;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        DoubleRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            min = prevRange.Min;
+                        }
+                        else
+                        {
+                            min = prevRange.Max;
+                        }
+                    }
+                    else
+                    {
+                        min = Random().NextDouble();
+                    }
+                    double max;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        DoubleRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            max = prevRange.Min;
+                        }
+                        else
+                        {
+                            max = prevRange.Max;
+                        }
+                    }
+                    else
+                    {
+                        max = Random().NextDouble();
+                    }
+
+                    if (min > max)
+                    {
+                        double x = min;
+                        min = max;
+                        max = x;
+                    }
+
+                    // Must truncate to float precision so that the
+                    // drill-down counts (which use NRQ.newFloatRange)
+                    // are correct:
+                    min = (float)min;
+                    max = (float)max;
+
+                    bool minIncl;
+                    bool maxIncl;
+                    if (min == max)
+                    {
+                        minIncl = true;
+                        maxIncl = true;
+                    }
+                    else
+                    {
+                        minIncl = Random().NextBoolean();
+                        maxIncl = Random().NextBoolean();
+                    }
+                    ranges[rangeID] = new DoubleRange("r" + rangeID, min, minIncl, max, maxIncl);
+
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST:   range " + rangeID + ": " + ranges[rangeID]);
+                    }
+
+                    // Do "slow but hopefully correct" computation of
+                    // expected count:
+                    for (int i = 0; i < numDocs; i++)
+                    {
+                        bool accept = true;
+                        if (minIncl)
+                        {
+                            accept &= values[i] >= min;
+                        }
+                        else
+                        {
+                            accept &= values[i] > min;
+                        }
+                        if (maxIncl)
+                        {
+                            accept &= values[i] <= max;
+                        }
+                        else
+                        {
+                            accept &= values[i] < max;
+                        }
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST:   check doc=" + i + " val=" + values[i] + " accept=" + accept);
+                        }
+                        if (accept)
+                        {
+                            expectedCounts[rangeID]++;
+                            minAcceptedValue = Math.Min(minAcceptedValue, values[i]);
+                            maxAcceptedValue = Math.Max(maxAcceptedValue, values[i]);
+                        }
+                    }
+                }
+
+                FacetsCollector sfc = new FacetsCollector();
+                s.Search(new MatchAllDocsQuery(), sfc);
+                Filter fastMatchFilter;
+                if (Random().NextBoolean())
+                {
+                    if (Random().NextBoolean())
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewFloatRange("field", minValue, maxValue, true, true);
+                    }
+                    else
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewFloatRange("field", minAcceptedValue, maxAcceptedValue, true, true);
+                    }
+                }
+                else
+                {
+                    fastMatchFilter = null;
+                }
+                ValueSource vs = new FloatFieldSource("field");
+                Facets facets = new DoubleRangeFacetCounts("field", vs, sfc, fastMatchFilter, ranges);
+                FacetResult result = facets.GetTopChildren(10, "field");
+                Assert.AreEqual(numRange, result.LabelValues.Length);
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: verify range " + rangeID + " expectedCount=" + expectedCounts[rangeID]);
+                    }
+                    LabelAndValue subNode = result.LabelValues[rangeID];
+                    Assert.AreEqual("r" + rangeID, subNode.label);
+                    Assert.AreEqual(expectedCounts[rangeID], (int)subNode.value);
+
+                    DoubleRange range = ranges[rangeID];
+
+                    // Test drill-down:
+                    DrillDownQuery ddq = new DrillDownQuery(config);
+                    if (Random().NextBoolean())
+                    {
+                        if (Random().NextBoolean())
+                        {
+                            ddq.Add("field", NumericRangeFilter.NewFloatRange("field", (float)range.Min, (float)range.Max, range.MinInclusive, range.MaxInclusive));
+                        }
+                        else
+                        {
+                            ddq.Add("field", NumericRangeQuery.NewFloatRange("field", (float)range.Min, (float)range.Max, range.MinInclusive, range.MaxInclusive));
+                        }
+                    }
+                    else
+                    {
+                        ddq.Add("field", range.GetFilter(fastMatchFilter, vs));
+                    }
+                    Assert.AreEqual(expectedCounts[rangeID], s.Search(ddq, 10).TotalHits);
+                }
+            }
+
+            IOUtils.Close(w, r, dir);
+        }
+
+        [Test]
+        public virtual void TestRandomDoubles()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), dir);
+
+            int numDocs = AtLeast(1000);
+            double[] values = new double[numDocs];
+            double minValue = double.PositiveInfinity;
+            double maxValue = double.NegativeInfinity;
+            for (int i = 0; i < numDocs; i++)
+            {
+                Document doc = new Document();
+                double v = Random().NextDouble();
+                values[i] = v;
+                doc.Add(new DoubleDocValuesField("field", v));
+                doc.Add(new DoubleField("field", v, Field.Store.NO));
+                w.AddDocument(doc);
+                minValue = Math.Min(minValue, v);
+                maxValue = Math.Max(maxValue, v);
+            }
+            IndexReader r = w.Reader;
+
+            IndexSearcher s = NewSearcher(r);
+            FacetsConfig config = new FacetsConfig();
+
+            int numIters = AtLeast(10);
+            for (int iter = 0; iter < numIters; iter++)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: iter=" + iter);
+                }
+                int numRange = TestUtil.NextInt(Random(), 1, 5);
+                DoubleRange[] ranges = new DoubleRange[numRange];
+                int[] expectedCounts = new int[numRange];
+                double minAcceptedValue = double.PositiveInfinity;
+                double maxAcceptedValue = double.NegativeInfinity;
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    double min;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        DoubleRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            min = prevRange.Min;
+                        }
+                        else
+                        {
+                            min = prevRange.Max;
+                        }
+                    }
+                    else
+                    {
+                        min = Random().NextDouble();
+                    }
+                    double max;
+                    if (rangeID > 0 && Random().Next(10) == 7)
+                    {
+                        // Use an existing boundary:
+                        DoubleRange prevRange = ranges[Random().Next(rangeID)];
+                        if (Random().NextBoolean())
+                        {
+                            max = prevRange.Min;
+                        }
+                        else
+                        {
+                            max = prevRange.Max;
+                        }
+                    }
+                    else
+                    {
+                        max = Random().NextDouble();
+                    }
+
+                    if (min > max)
+                    {
+                        double x = min;
+                        min = max;
+                        max = x;
+                    }
+
+                    bool minIncl;
+                    bool maxIncl;
+                    if (min == max)
+                    {
+                        minIncl = true;
+                        maxIncl = true;
+                    }
+                    else
+                    {
+                        minIncl = Random().NextBoolean();
+                        maxIncl = Random().NextBoolean();
+                    }
+                    ranges[rangeID] = new DoubleRange("r" + rangeID, min, minIncl, max, maxIncl);
+
+                    // Do "slow but hopefully correct" computation of
+                    // expected count:
+                    for (int i = 0; i < numDocs; i++)
+                    {
+                        bool accept = true;
+                        if (minIncl)
+                        {
+                            accept &= values[i] >= min;
+                        }
+                        else
+                        {
+                            accept &= values[i] > min;
+                        }
+                        if (maxIncl)
+                        {
+                            accept &= values[i] <= max;
+                        }
+                        else
+                        {
+                            accept &= values[i] < max;
+                        }
+                        if (accept)
+                        {
+                            expectedCounts[rangeID]++;
+                            minAcceptedValue = Math.Min(minAcceptedValue, values[i]);
+                            maxAcceptedValue = Math.Max(maxAcceptedValue, values[i]);
+                        }
+                    }
+                }
+
+                FacetsCollector sfc = new FacetsCollector();
+                s.Search(new MatchAllDocsQuery(), sfc);
+                Filter fastMatchFilter;
+                if (Random().NextBoolean())
+                {
+                    if (Random().NextBoolean())
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewDoubleRange("field", minValue, maxValue, true, true);
+                    }
+                    else
+                    {
+                        fastMatchFilter = NumericRangeFilter.NewDoubleRange("field", minAcceptedValue, maxAcceptedValue, true, true);
+                    }
+                }
+                else
+                {
+                    fastMatchFilter = null;
+                }
+                ValueSource vs = new DoubleFieldSource("field");
+                Facets facets = new DoubleRangeFacetCounts("field", vs, sfc, fastMatchFilter, ranges);
+                FacetResult result = facets.GetTopChildren(10, "field");
+                Assert.AreEqual(numRange, result.LabelValues.Length);
+                for (int rangeID = 0; rangeID < numRange; rangeID++)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("  range " + rangeID + " expectedCount=" + expectedCounts[rangeID]);
+                    }
+                    LabelAndValue subNode = result.LabelValues[rangeID];
+                    Assert.AreEqual("r" + rangeID, subNode.label);
+                    Assert.AreEqual(expectedCounts[rangeID], (int)subNode.value);
+
+                    DoubleRange range = ranges[rangeID];
+
+                    // Test drill-down:
+                    DrillDownQuery ddq = new DrillDownQuery(config);
+                    if (Random().NextBoolean())
+                    {
+                        if (Random().NextBoolean())
+                        {
+                            ddq.Add("field", NumericRangeFilter.NewDoubleRange("field", range.Min, range.Max, range.MinInclusive, range.MaxInclusive));
+                        }
+                        else
+                        {
+                            ddq.Add("field", NumericRangeQuery.NewDoubleRange("field", range.Min, range.Max, range.MinInclusive, range.MaxInclusive));
+                        }
+                    }
+                    else
+                    {
+                        ddq.Add("field", range.GetFilter(fastMatchFilter, vs));
+                    }
+
+                    Assert.AreEqual(expectedCounts[rangeID], s.Search(ddq, 10).TotalHits);
+                }
+            }
+
+            IOUtils.Close(w, r, dir);
+        }
+
+        // LUCENE-5178
+        [Test]
+        public virtual void TestMissingValues()
+        {
+            AssumeTrue("codec does not support docsWithField", DefaultCodecSupportsDocsWithField());
+            Directory d = NewDirectory();
+            RandomIndexWriter w = new RandomIndexWriter(Random(), d);
+            Document doc = new Document();
+            NumericDocValuesField field = new NumericDocValuesField("field", 0L);
+            doc.Add(field);
+            for (long l = 0; l < 100; l++)
+            {
+                if (l % 5 == 0)
+                {
+                    // Every 5th doc is missing the value:
+                    w.AddDocument(new Document());
+                    continue;
+                }
+                field.LongValue = l;
+                w.AddDocument(doc);
+            }
+
+            IndexReader r = w.Reader;
+
+            FacetsCollector fc = new FacetsCollector();
+
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+            Facets facets = new LongRangeFacetCounts("field", fc, new LongRange("less than 10", 0L, true, 10L, false), new LongRange("less than or equal to 10", 0L, true, 10L, true), new LongRange("over 90", 90L, false, 100L, false), new LongRange("90 or above", 90L, true, 100L, false), new LongRange("over 1000", 1000L, false, long.MaxValue, false));
+
+            Assert.AreEqual("dim=field path=[] value=16 childCount=5\n  less than 10 (8)\n  less than or equal to 10 (8)\n  over 90 (8)\n  90 or above (8)\n  over 1000 (0)\n", facets.GetTopChildren(10, "field").ToString());
+
+            IOUtils.Close(w, r, d);
+        }
+
+        [Test]
+        public virtual void TestCustomDoublesValueSource()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), dir);
+
+            Document doc = new Document();
+            writer.AddDocument(doc);
+            writer.AddDocument(doc);
+            writer.AddDocument(doc);
+
+            // Test wants 3 docs in one segment:
+            writer.ForceMerge(1);
+
+            var vs = new ValueSourceAnonymousInnerClassHelper(this, doc);
+
+            FacetsConfig config = new FacetsConfig();
+
+            FacetsCollector fc = new FacetsCollector();
+
+            IndexReader r = writer.Reader;
+            IndexSearcher s = NewSearcher(r);
+            s.Search(new MatchAllDocsQuery(), fc);
+
+            DoubleRange[] ranges = new DoubleRange[] { new DoubleRange("< 1", 0.0, true, 1.0, false), new DoubleRange("< 2", 0.0, true, 2.0, false), new DoubleRange("< 5", 0.0, true, 5.0, false), new DoubleRange("< 10", 0.0, true, 10.0, false), new DoubleRange("< 20", 0.0, true, 20.0, false), new DoubleRange("< 50", 0.0, true, 50.0, false) };
+
+            Filter fastMatchFilter;
+            AtomicBoolean filterWasUsed = new AtomicBoolean();
+            if (Random().NextBoolean())
+            {
+                // Sort of silly:
+                fastMatchFilter = new CachingWrapperFilterAnonymousInnerClassHelper(this, new QueryWrapperFilter(new MatchAllDocsQuery()), filterWasUsed);
+            }
+            else
+            {
+                fastMatchFilter = null;
+            }
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: fastMatchFilter=" + fastMatchFilter);
+            }
+
+            Facets facets = new DoubleRangeFacetCounts("field", vs, fc, fastMatchFilter, ranges);
+
+            Assert.AreEqual("dim=field path=[] value=3 childCount=6\n  < 1 (0)\n  < 2 (1)\n  < 5 (3)\n  < 10 (3)\n  < 20 (3)\n  < 50 (3)\n", facets.GetTopChildren(10, "field").ToString());
+            Assert.True(fastMatchFilter == null || filterWasUsed.Get());
+
+            DrillDownQuery ddq = new DrillDownQuery(config);
+            ddq.Add("field", ranges[1].GetFilter(fastMatchFilter, vs));
+
+            // Test simple drill-down:
+            Assert.AreEqual(1, s.Search(ddq, 10).TotalHits);
+
+            // Test drill-sideways after drill-down
+            DrillSideways ds = new DrillSidewaysAnonymousInnerClassHelper2(this, s, config, (TaxonomyReader)null, vs, ranges, fastMatchFilter);
+
+
+            DrillSidewaysResult dsr = ds.Search(ddq, 10);
+            Assert.AreEqual(1, dsr.Hits.TotalHits);
+            Assert.AreEqual("dim=field path=[] value=3 childCount=6\n  < 1 (0)\n  < 2 (1)\n  < 5 (3)\n  < 10 (3)\n  < 20 (3)\n  < 50 (3)\n", dsr.Facets.GetTopChildren(10, "field").ToString());
+
+            IOUtils.Close(r, writer, dir);
+        }
+
+        private class ValueSourceAnonymousInnerClassHelper : ValueSource
+        {
+            private readonly TestRangeFacetCounts outerInstance;
+
+            private Document doc;
+
+            public ValueSourceAnonymousInnerClassHelper(TestRangeFacetCounts outerInstance, Document doc)
+            {
+                this.outerInstance = outerInstance;
+                this.doc = doc;
+            }
+
+            public override FunctionValues GetValues(IDictionary ignored, AtomicReaderContext ignored2)
+            {
+                return new DoubleDocValuesAnonymousInnerClassHelper(this);
+            }
+
+            private class DoubleDocValuesAnonymousInnerClassHelper : DoubleDocValues
+            {
+                private readonly ValueSourceAnonymousInnerClassHelper outerInstance;
+
+                public DoubleDocValuesAnonymousInnerClassHelper(ValueSourceAnonymousInnerClassHelper outerInstance)
+                    : base(null)
+                {
+                    this.outerInstance = outerInstance;
+                }
+
+                public override double DoubleVal(int doc)
+                {
+                    return doc + 1;
+                }
+            }
+
+            public override bool Equals(object o)
+            {
+                throw new System.NotSupportedException();
+            }
+
+            public override int GetHashCode()
+            {
+                throw new System.NotSupportedException();
+            }
+
+            public override string Description
+            {
+                get { throw new NotSupportedException(); }
+            }
+
+        }
+
+        private class CachingWrapperFilterAnonymousInnerClassHelper : CachingWrapperFilter
+        {
+            private readonly TestRangeFacetCounts outerInstance;
+
+            private AtomicBoolean filterWasUsed;
+
+            public CachingWrapperFilterAnonymousInnerClassHelper(TestRangeFacetCounts outerInstance, QueryWrapperFilter org, AtomicBoolean filterWasUsed)
+                : base(org)
+            {
+                this.outerInstance = outerInstance;
+                this.filterWasUsed = filterWasUsed;
+            }
+
+            protected override DocIdSet CacheImpl(DocIdSetIterator iterator, AtomicReader reader)
+            {
+                var cached = new FixedBitSet(reader.MaxDoc);
+                filterWasUsed.Set(true);
+                cached.Or(iterator);
+                return cached;
+            }
+        }
+
+        private class DrillSidewaysAnonymousInnerClassHelper2 : DrillSideways
+        {
+            private readonly TestRangeFacetCounts outerInstance;
+
+            private ValueSource vs;
+            private Lucene.Net.Facet.Range.DoubleRange[] ranges;
+            private Filter fastMatchFilter;
+
+
+            public DrillSidewaysAnonymousInnerClassHelper2(TestRangeFacetCounts testRangeFacetCounts, IndexSearcher indexSearcher, FacetsConfig facetsConfig, TaxonomyReader org, ValueSource valueSource, DoubleRange[] doubleRanges, Filter filter)
+                : base(indexSearcher, facetsConfig, org)
+            {
+                this.outerInstance = outerInstance;
+                this.vs = valueSource;
+                this.ranges = doubleRanges;
+                this.fastMatchFilter = filter;
+            }
+
+
+            protected override Facets BuildFacetsResult(FacetsCollector drillDowns, FacetsCollector[] drillSideways, string[] drillSidewaysDims)
+            {
+                Debug.Assert(drillSideways.Length == 1);
+                return new DoubleRangeFacetCounts("field", vs, drillSideways[0], fastMatchFilter, ranges);
+            }
+
+            protected override bool ScoreSubDocsAtOnce()
+            {
+                return Random().NextBoolean();
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
new file mode 100644
index 0000000..72de557
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Threading;
+using Lucene.Net.Randomized.Generators;
+
+namespace Lucene.Net.Facet
+{
+
+    /*
+     * 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.
+     */
+
+
+    using IOContext = Lucene.Net.Store.IOContext;
+    using IndexInput = Lucene.Net.Store.IndexInput;
+    using IndexOutput = Lucene.Net.Store.IndexOutput;
+    using RAMDirectory = Lucene.Net.Store.RAMDirectory;
+    using ThreadInterruptedException = Lucene.Net.Util.ThreadInterruptedException;
+
+    /// <summary>
+    /// Test utility - slow directory
+    /// </summary>
+    // TODO: move to test-framework and sometimes use in tests?
+    public class SlowRAMDirectory : RAMDirectory
+    {
+
+        private const int IO_SLEEP_THRESHOLD = 50;
+
+        internal Random random;
+        private int sleepMillis;
+
+        public virtual int SleepMillis
+        {
+            set
+            {
+                this.sleepMillis = value;
+            }
+        }
+
+        public SlowRAMDirectory(int sleepMillis, Random random)
+        {
+            this.sleepMillis = sleepMillis;
+            this.random = random;
+        }
+
+        public override IndexOutput CreateOutput(string name, IOContext context)
+        {
+            if (sleepMillis != -1)
+            {
+                return new SlowIndexOutput(this, base.CreateOutput(name, context));
+            }
+
+            return base.CreateOutput(name, context);
+        }
+
+        public override IndexInput OpenInput(string name, IOContext context)
+        {
+            if (sleepMillis != -1)
+            {
+                return new SlowIndexInput(this, base.OpenInput(name, context));
+            }
+            return base.OpenInput(name, context);
+        }
+
+        internal virtual void doSleep(Random random, int length)
+        {
+            int sTime = length < 10 ? sleepMillis : (int)(sleepMillis * Math.Log(length));
+            if (random != null)
+            {
+                sTime = random.Next(sTime);
+            }
+            try
+            {
+                Thread.Sleep(sTime);
+            }
+            catch (ThreadInterruptedException e)
+            {
+                throw new ThreadInterruptedException(e);
+            }
+        }
+
+        /// <summary>
+        /// Make a private random. </summary>
+        internal virtual Random forkRandom()
+        {
+            if (random == null)
+            {
+                return null;
+            }
+            return new Random((int)random.NextLong());
+        }
+
+        /// <summary>
+        /// Delegate class to wrap an IndexInput and delay reading bytes by some
+        /// specified time.
+        /// </summary>
+        private class SlowIndexInput : IndexInput
+        {
+            private readonly SlowRAMDirectory outerInstance;
+
+            internal IndexInput ii;
+            internal int numRead = 0;
+            internal Random rand;
+
+            public SlowIndexInput(SlowRAMDirectory outerInstance, IndexInput ii)
+                : base("SlowIndexInput(" + ii + ")")
+            {
+                this.outerInstance = outerInstance;
+                this.rand = outerInstance.forkRandom();
+                this.ii = ii;
+            }
+
+            public override byte ReadByte()
+            {
+                if (numRead >= IO_SLEEP_THRESHOLD)
+                {
+                    outerInstance.doSleep(rand, 0);
+                    numRead = 0;
+                }
+                ++numRead;
+                return ii.ReadByte();
+            }
+
+            public override void ReadBytes(byte[] b, int offset, int len)
+            {
+                if (numRead >= IO_SLEEP_THRESHOLD)
+                {
+                    outerInstance.doSleep(rand, len);
+                    numRead = 0;
+                }
+                numRead += len;
+                ii.ReadBytes(b, offset, len);
+            }
+
+
+            // TODO: is it intentional that clone doesnt wrap?
+            public override object Clone()
+            {
+                return ii.Clone();
+            }
+
+
+            public override void Dispose()
+            {
+                ii.Dispose();
+            }
+            public override bool Equals(object o)
+            {
+                return ii.Equals(o);
+            }
+            public override long FilePointer
+            {
+                get
+                {
+                    return ii.FilePointer;
+                }
+            }
+
+            public override void Seek(long pos)
+            {
+                ii.Seek(pos);
+            }
+
+
+            public override int GetHashCode()
+            {
+                return ii.GetHashCode();
+            }
+            public override long Length()
+            {
+                return ii.Length();
+            }
+
+        }
+
+        /// <summary>
+        /// Delegate class to wrap an IndexOutput and delay writing bytes by some
+        /// specified time.
+        /// </summary>
+        private class SlowIndexOutput : IndexOutput
+        {
+            private readonly SlowRAMDirectory outerInstance;
+
+
+            internal IndexOutput io;
+            internal int numWrote;
+            internal readonly Random rand;
+
+            public SlowIndexOutput(SlowRAMDirectory outerInstance, IndexOutput io)
+            {
+                this.outerInstance = outerInstance;
+                this.io = io;
+                this.rand = outerInstance.forkRandom();
+            }
+
+            public override void WriteByte(byte b)
+            {
+                if (numWrote >= IO_SLEEP_THRESHOLD)
+                {
+                    outerInstance.doSleep(rand, 0);
+                    numWrote = 0;
+                }
+                ++numWrote;
+                io.WriteByte(b);
+            }
+
+            public override void WriteBytes(byte[] b, int offset, int length)
+            {
+                if (numWrote >= IO_SLEEP_THRESHOLD)
+                {
+                    outerInstance.doSleep(rand, length);
+                    numWrote = 0;
+                }
+                numWrote += length;
+                io.WriteBytes(b, offset, length);
+            }
+
+            public override void Dispose()
+            {
+                io.Dispose();
+            }
+            public override void Flush()
+            {
+                io.Flush();
+            }
+            public override long FilePointer
+            {
+                get
+                {
+                    return io.FilePointer;
+                }
+            }
+            public override void Seek(long pos)
+            {
+                io.Seek(pos);
+            }
+
+            public override long Checksum
+            {
+                get
+                {
+                    return io.Checksum;
+                }
+            }
+        }
+
+    }
+
+}
\ No newline at end of file