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 2016/10/02 10:16:59 UTC

[28/49] lucenenet git commit: Ported Core.TestExternalCodes + fixed bugs that were preventing it from running.

Ported Core.TestExternalCodes + fixed bugs that were preventing it from running.


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

Branch: refs/heads/master
Commit: f4819a3e4902fd7c257f70068e511145cbc031e4
Parents: 0e77936
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Sun Sep 11 03:59:31 2016 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Sun Sep 11 04:19:45 2016 +0700

----------------------------------------------------------------------
 .../Pulsing/PulsingPostingsReader.cs            |   6 +-
 src/Lucene.Net.Core/Util/Attribute.cs           |   2 +-
 src/Lucene.Net.Core/Util/AttributeImpl.cs       | 276 +++++++++----------
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   1 +
 src/Lucene.Net.Tests/core/TestExternalCodecs.cs | 264 +++++++++---------
 5 files changed, 273 insertions(+), 276 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f4819a3e/src/Lucene.Net.Codecs/Pulsing/PulsingPostingsReader.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Codecs/Pulsing/PulsingPostingsReader.cs b/src/Lucene.Net.Codecs/Pulsing/PulsingPostingsReader.cs
index 7ab59e9..46e4eb9 100644
--- a/src/Lucene.Net.Codecs/Pulsing/PulsingPostingsReader.cs
+++ b/src/Lucene.Net.Codecs/Pulsing/PulsingPostingsReader.cs
@@ -699,7 +699,7 @@ namespace Lucene.Net.Codecs.Pulsing
         /// 
         /// @lucene.internal
         /// </summary>
-        internal sealed class PulsingEnumAttributeImpl : AttributeImpl, IPulsingEnumAttribute
+        internal sealed class PulsingEnumAttribute : AttributeImpl, IPulsingEnumAttribute
         {
             // we could store 'other', but what if someone 'chained' multiple postings readers,
             // this could cause problems?
@@ -720,13 +720,11 @@ namespace Lucene.Net.Codecs.Pulsing
                 // and is calling clearAttributes(), so they don't nuke the reuse information!
             }
 
-            public override void CopyTo(AttributeImpl target)
+            public override void CopyTo(Util.Attribute target)
             {
                 // this makes no sense for us, because our state is per-docsenum.
                 // we don't want to copy any stuff over to another docsenum ever!
             }
-
         }
-
     }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f4819a3e/src/Lucene.Net.Core/Util/Attribute.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/Attribute.cs b/src/Lucene.Net.Core/Util/Attribute.cs
index 6d00033..adb4277 100644
--- a/src/Lucene.Net.Core/Util/Attribute.cs
+++ b/src/Lucene.Net.Core/Util/Attribute.cs
@@ -72,7 +72,7 @@ namespace Lucene.Net.Util
             }
         }
 
-        public string ReflectAsString(bool prependAttClass)
+        public virtual string ReflectAsString(bool prependAttClass)
         {
             StringBuilder buffer = new StringBuilder();
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f4819a3e/src/Lucene.Net.Core/Util/AttributeImpl.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/AttributeImpl.cs b/src/Lucene.Net.Core/Util/AttributeImpl.cs
index f14425b..20fc88a 100644
--- a/src/Lucene.Net.Core/Util/AttributeImpl.cs
+++ b/src/Lucene.Net.Core/Util/AttributeImpl.cs
@@ -5,8 +5,7 @@ using System.Text;
 
 namespace Lucene.Net.Util
 {
-
-	/*
+    /*
 	 * 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.
@@ -24,150 +23,149 @@ namespace Lucene.Net.Util
 	 */
 
 
-	/// <summary>
-	/// Base class for Attributes that can be added to a 
-	/// <seealso cref="Lucene.Net.Util.AttributeSource"/>.
-	/// <p>
-	/// Attributes are used to add data in a dynamic, yet type-safe way to a source
-	/// of usually streamed objects, e. g. a <seealso cref="Lucene.Net.Analysis.TokenStream"/>.
-	/// </summary>
-	public abstract class AttributeImpl : IAttribute, ICloneable 
-	{
-	  /// <summary>
-	  /// Clears the values in this AttributeImpl and resets it to its 
-	  /// default value. If this implementation implements more than one Attribute interface
-	  /// it clears all.
-	  /// </summary>
-	  public abstract void Clear();
-
-	  /// <summary>
-	  /// this method returns the current attribute values as a string in the following format
-	  /// by calling the <seealso cref="#reflectWith(AttributeReflector)"/> method:
-	  /// 
-	  /// <ul>
-	  /// <li><em>iff {@code prependAttClass=true}:</em> {@code "AttributeClass#key=value,AttributeClass#key=value"}
-	  /// <li><em>iff {@code prependAttClass=false}:</em> {@code "key=value,key=value"}
-	  /// </ul>
-	  /// </summary>
-	  /// <seealso cref= #reflectWith(AttributeReflector) </seealso>
-	  public string ReflectAsString(bool prependAttClass)
-	  {
-		StringBuilder buffer = new StringBuilder();
-		ReflectWith(new AttributeReflectorAnonymousInnerClassHelper(this, prependAttClass, buffer));
-		return buffer.ToString();
-	  }
+    /// <summary>
+    /// Base class for Attributes that can be added to a 
+    /// <seealso cref="Lucene.Net.Util.AttributeSource"/>.
+    /// <p>
+    /// Attributes are used to add data in a dynamic, yet type-safe way to a source
+    /// of usually streamed objects, e. g. a <seealso cref="Lucene.Net.Analysis.TokenStream"/>.
+    /// </summary>
+    public abstract class AttributeImpl : Attribute, IAttribute, ICloneable
+    {
+        /// <summary>
+        /// Clears the values in this AttributeImpl and resets it to its 
+        /// default value. If this implementation implements more than one Attribute interface
+        /// it clears all.
+        /// </summary>
+        public override abstract void Clear();
 
-	  private class AttributeReflectorAnonymousInnerClassHelper : IAttributeReflector
-	  {
-		  private readonly AttributeImpl OuterInstance;
+        /// <summary>
+        /// this method returns the current attribute values as a string in the following format
+        /// by calling the <seealso cref="#reflectWith(AttributeReflector)"/> method:
+        /// 
+        /// <ul>
+        /// <li><em>iff {@code prependAttClass=true}:</em> {@code "AttributeClass#key=value,AttributeClass#key=value"}
+        /// <li><em>iff {@code prependAttClass=false}:</em> {@code "key=value,key=value"}
+        /// </ul>
+        /// </summary>
+        /// <seealso cref= #reflectWith(AttributeReflector) </seealso>
+        public override string ReflectAsString(bool prependAttClass)
+        {
+            StringBuilder buffer = new StringBuilder();
+            ReflectWith(new AttributeReflectorAnonymousInnerClassHelper(this, prependAttClass, buffer));
+            return buffer.ToString();
+        }
 
-		  private bool PrependAttClass;
-		  private StringBuilder Buffer;
+        private class AttributeReflectorAnonymousInnerClassHelper : IAttributeReflector
+        {
+            private readonly AttributeImpl OuterInstance;
 
-		  public AttributeReflectorAnonymousInnerClassHelper(AttributeImpl outerInstance, bool prependAttClass, StringBuilder buffer)
-		  {
-			  this.OuterInstance = outerInstance;
-			  this.PrependAttClass = prependAttClass;
-			  this.Buffer = buffer;
-		  }
+            private bool PrependAttClass;
+            private StringBuilder Buffer;
 
-	      public void Reflect<T>(string key, object value) where T : IAttribute
-	      {
-	          throw new NotImplementedException();
-	      }
+            public AttributeReflectorAnonymousInnerClassHelper(AttributeImpl outerInstance, bool prependAttClass, StringBuilder buffer)
+            {
+                this.OuterInstance = outerInstance;
+                this.PrependAttClass = prependAttClass;
+                this.Buffer = buffer;
+            }
 
-	      public virtual void Reflect(Type attClass, string key, object value)
-		  {
-			if (Buffer.Length > 0)
-			{
-			  Buffer.Append(',');
-			}
-			if (PrependAttClass)
-			{
-			  Buffer.Append(attClass.Name).Append('#');
-			}
-			Buffer.Append(key).Append('=').Append((value == null) ? "null" : value);
-		  }
-	  }
+            public void Reflect<T>(string key, object value) where T : IAttribute
+            {
+                throw new NotImplementedException();
+            }
 
-	  /// <summary>
-	  /// this method is for introspection of attributes, it should simply
-	  /// add the key/values this attribute holds to the given <seealso cref="AttributeReflector"/>.
-	  /// 
-	  /// <p>The default implementation calls <seealso cref="AttributeReflector#reflect"/> for all
-	  /// non-static fields from the implementing class, using the field name as key
-	  /// and the field value as value. The Attribute class is also determined by reflection.
-	  /// Please note that the default implementation can only handle single-Attribute
-	  /// implementations.
-	  /// 
-	  /// <p>Custom implementations look like this (e.g. for a combined attribute implementation):
-	  /// <pre class="prettyprint">
-	  ///   public void reflectWith(AttributeReflector reflector) {
-	  ///     reflector.reflect(CharTermAttribute.class, "term", term());
-	  ///     reflector.reflect(PositionIncrementAttribute.class, "positionIncrement", getPositionIncrement());
-	  ///   }
-	  /// </pre>
-	  /// 
-	  /// <p>If you implement this method, make sure that for each invocation, the same set of <seealso cref="Attribute"/>
-	  /// interfaces and keys are passed to <seealso cref="AttributeReflector#reflect"/> in the same order, but possibly
-	  /// different values. So don't automatically exclude e.g. {@code null} properties!
-	  /// </summary>
-	  /// <seealso cref= #reflectAsString(boolean) </seealso>
-	  public virtual void ReflectWith(IAttributeReflector reflector)
-	  {
-		Type clazz = this.GetType();
-		LinkedList<WeakReference> interfaces = AttributeSource.GetAttributeInterfaces(clazz);
-		if (interfaces.Count != 1)
-		{
-		  throw new System.NotSupportedException(clazz.Name + " implements more than one Attribute interface, the default reflectWith() implementation cannot handle this.");
-		}
-        //LUCENE-TODO unsure about GetType()
-        Type interf = (Type)interfaces.First.Value.GetType();
-        FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance | BindingFlags.Public);
-		try
-		{
-		  for (int i = 0; i < fields.Length; i++)
-		  {
-			FieldInfo f = fields[i];
-			if (f.IsStatic)
-			{
-				continue;
-			}
-			reflector.Reflect(interf, f.Name, f.GetValue(this));
-		  }
-		}
-		catch (Exception)
-		{
-		  // this should never happen, because we're just accessing fields
-		  // from 'this'
-		  throw new Exception("Unknown Error");
-		}
-	  }
+            public virtual void Reflect(Type attClass, string key, object value)
+            {
+                if (Buffer.Length > 0)
+                {
+                    Buffer.Append(',');
+                }
+                if (PrependAttClass)
+                {
+                    Buffer.Append(attClass.Name).Append('#');
+                }
+                Buffer.Append(key).Append('=').Append((value == null) ? "null" : value);
+            }
+        }
 
-	  /// <summary>
-	  /// Copies the values from this Attribute into the passed-in
-	  /// target attribute. The target implementation must support all the
-	  /// Attributes this implementation supports.
-	  /// </summary>
-	  public abstract void CopyTo(AttributeImpl target);
+        /// <summary>
+        /// this method is for introspection of attributes, it should simply
+        /// add the key/values this attribute holds to the given <seealso cref="AttributeReflector"/>.
+        /// 
+        /// <p>The default implementation calls <seealso cref="AttributeReflector#reflect"/> for all
+        /// non-static fields from the implementing class, using the field name as key
+        /// and the field value as value. The Attribute class is also determined by reflection.
+        /// Please note that the default implementation can only handle single-Attribute
+        /// implementations.
+        /// 
+        /// <p>Custom implementations look like this (e.g. for a combined attribute implementation):
+        /// <pre class="prettyprint">
+        ///   public void reflectWith(AttributeReflector reflector) {
+        ///     reflector.reflect(CharTermAttribute.class, "term", term());
+        ///     reflector.reflect(PositionIncrementAttribute.class, "positionIncrement", getPositionIncrement());
+        ///   }
+        /// </pre>
+        /// 
+        /// <p>If you implement this method, make sure that for each invocation, the same set of <seealso cref="Attribute"/>
+        /// interfaces and keys are passed to <seealso cref="AttributeReflector#reflect"/> in the same order, but possibly
+        /// different values. So don't automatically exclude e.g. {@code null} properties!
+        /// </summary>
+        /// <seealso cref= #reflectAsString(boolean) </seealso>
+        public override void ReflectWith(IAttributeReflector reflector)
+        {
+            Type clazz = this.GetType();
+            LinkedList<WeakReference> interfaces = AttributeSource.GetAttributeInterfaces(clazz);
+            if (interfaces.Count != 1)
+            {
+                throw new System.NotSupportedException(clazz.Name + " implements more than one Attribute interface, the default reflectWith() implementation cannot handle this.");
+            }
+            //LUCENE-TODO unsure about GetType()
+            Type interf = (Type)interfaces.First.Value.GetType();
+            FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance | BindingFlags.Public);
+            try
+            {
+                for (int i = 0; i < fields.Length; i++)
+                {
+                    FieldInfo f = fields[i];
+                    if (f.IsStatic)
+                    {
+                        continue;
+                    }
+                    reflector.Reflect(interf, f.Name, f.GetValue(this));
+                }
+            }
+            catch (Exception)
+            {
+                // this should never happen, because we're just accessing fields
+                // from 'this'
+                throw new Exception("Unknown Error");
+            }
+        }
 
-	  /// <summary>
-	  /// Shallow clone. Subclasses must override this if they 
-	  /// need to clone any members deeply,
-	  /// </summary>
-	  public object Clone()
-	  {
-		AttributeImpl clone = null;
-		try
-		{
-		  clone = (AttributeImpl)base.MemberwiseClone();
-		}
-		catch (Exception)
-		{
-		  throw new Exception("Clone not supported"); // shouldn't happen
-		}
-		return clone;
-	  }
-	}
+        /// <summary>
+        /// Copies the values from this Attribute into the passed-in
+        /// target attribute. The target implementation must support all the
+        /// Attributes this implementation supports.
+        /// </summary>
+        public override abstract void CopyTo(Attribute target);
 
+        /// <summary>
+        /// Shallow clone. Subclasses must override this if they 
+        /// need to clone any members deeply,
+        /// </summary>
+        public override object Clone()
+        {
+            AttributeImpl clone = null;
+            try
+            {
+                clone = (AttributeImpl)base.MemberwiseClone();
+            }
+            catch (Exception)
+            {
+                throw new Exception("Clone not supported"); // shouldn't happen
+            }
+            return clone;
+        }
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f4819a3e/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
index a20ba5c..1eab117 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -429,6 +429,7 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="core\TestDemo.cs" />
+    <Compile Include="core\TestExternalCodecs.cs" />
     <Compile Include="core\TestMergeSchedulerExternal.cs">
       <SubType>Code</SubType>
     </Compile>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f4819a3e/src/Lucene.Net.Tests/core/TestExternalCodecs.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/TestExternalCodecs.cs b/src/Lucene.Net.Tests/core/TestExternalCodecs.cs
index 6a6a80a..b8a6683 100644
--- a/src/Lucene.Net.Tests/core/TestExternalCodecs.cs
+++ b/src/Lucene.Net.Tests/core/TestExternalCodecs.cs
@@ -1,9 +1,9 @@
 using System;
+using NUnit.Framework;
 
-namespace org.apache.lucene
+namespace Lucene.Net
 {
-
-	/*
+    /*
 	 * 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.
@@ -20,135 +20,135 @@ namespace org.apache.lucene
 	 * limitations under the License.
 	 */
 
-	using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
-	using PostingsFormat = Lucene.Net.Codecs.PostingsFormat;
-	using Lucene46Codec = Lucene.Net.Codecs.Lucene46.Lucene46Codec;
-	using Document = Lucene.Net.Document.Document;
-	using Field = Lucene.Net.Document.Field;
-	using DirectoryReader = Lucene.Net.Index.DirectoryReader;
-	using IndexReader = Lucene.Net.Index.IndexReader;
-	using IndexWriter = Lucene.Net.Index.IndexWriter;
-	using Term = Lucene.Net.Index.Term;
-	using IndexSearcher = Lucene.Net.Search.IndexSearcher;
-	using TermQuery = Lucene.Net.Search.TermQuery;
-	using BaseDirectoryWrapper = Lucene.Net.Store.BaseDirectoryWrapper;
-	using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
-    using NUnit.Framework;
-
-
-	/* Intentionally outside of oal.index to verify fully
+    using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using PostingsFormat = Lucene.Net.Codecs.PostingsFormat;
+    using Lucene46Codec = Lucene.Net.Codecs.Lucene46.Lucene46Codec;
+    using Document = Lucene.Net.Documents.Document;
+    using Field = Lucene.Net.Documents.Field;
+    using DirectoryReader = Lucene.Net.Index.DirectoryReader;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using IndexWriter = Lucene.Net.Index.IndexWriter;
+    using Term = Lucene.Net.Index.Term;
+    using IndexSearcher = Lucene.Net.Search.IndexSearcher;
+    using TermQuery = Lucene.Net.Search.TermQuery;
+    using BaseDirectoryWrapper = Lucene.Net.Store.BaseDirectoryWrapper;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+
+
+    /* Intentionally outside of oal.index to verify fully
 	   external codecs work fine */
 
-	public class TestExternalCodecs : LuceneTestCase
-	{
-
-	  private sealed class CustomPerFieldCodec : Lucene46Codec
-	  {
-
-		internal readonly PostingsFormat RamFormat = PostingsFormat.ForName("RAMOnly");
-		internal readonly PostingsFormat DefaultFormat = PostingsFormat.ForName("Lucene41");
-		internal readonly PostingsFormat PulsingFormat = PostingsFormat.ForName("Pulsing41");
-
-		public override PostingsFormat GetPostingsFormatForField(string field)
-		{
-		  if (field.Equals("field2") || field.Equals("id"))
-		  {
-			return PulsingFormat;
-		  }
-		  else if (field.Equals("field1"))
-		  {
-			return DefaultFormat;
-		  }
-		  else
-		  {
-			return RamFormat;
-		  }
-		}
-	  }
-
-	  // tests storing "id" and "field2" fields as pulsing codec,
-	  // whose term sort is backwards unicode code point, and
-	  // storing "field1" as a custom entirely-in-RAM codec
-	  public virtual void TestPerFieldCodec()
-	  {
-
-		int NUM_DOCS = atLeast(173);
-		if (VERBOSE)
-		{
-		  Console.WriteLine("TEST: NUM_DOCS=" + NUM_DOCS);
-		}
-
-		BaseDirectoryWrapper dir = newDirectory();
-		dir.CheckIndexOnClose = false; // we use a custom codec provider
-		IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())).setCodec(new CustomPerFieldCodec()).setMergePolicy(newLogMergePolicy(3)));
-		Document doc = new Document();
-		// uses default codec:
-		doc.Add(newTextField("field1", "this field uses the standard codec as the test", Field.Store.NO));
-		// uses pulsing codec:
-		Field field2 = newTextField("field2", "this field uses the pulsing codec as the test", Field.Store.NO);
-		doc.Add(field2);
-
-		Field idField = newStringField("id", "", Field.Store.NO);
-
-		doc.Add(idField);
-		for (int i = 0;i < NUM_DOCS;i++)
-		{
-		  idField.StringValue = "" + i;
-		  w.addDocument(doc);
-		  if ((i + 1) % 10 == 0)
-		  {
-			w.commit();
-		  }
-		}
-		if (VERBOSE)
-		{
-		  Console.WriteLine("TEST: now delete id=77");
-		}
-		w.deleteDocuments(new Term("id", "77"));
-
-		IndexReader r = DirectoryReader.Open(w, true);
-
-		Assert.AreEqual(NUM_DOCS - 1, r.NumDocs());
-		IndexSearcher s = newSearcher(r);
-		Assert.AreEqual(NUM_DOCS - 1, s.Search(new TermQuery(new Term("field1", "standard")), 1).TotalHits);
-		Assert.AreEqual(NUM_DOCS - 1, s.Search(new TermQuery(new Term("field2", "pulsing")), 1).TotalHits);
-		r.Close();
-
-		if (VERBOSE)
-		{
-		  Console.WriteLine("\nTEST: now delete 2nd doc");
-		}
-		w.deleteDocuments(new Term("id", "44"));
-
-		if (VERBOSE)
-		{
-		  Console.WriteLine("\nTEST: now force merge");
-		}
-		w.forceMerge(1);
-		if (VERBOSE)
-		{
-		  Console.WriteLine("\nTEST: now open reader");
-		}
-		r = DirectoryReader.Open(w, true);
-		Assert.AreEqual(NUM_DOCS - 2, r.MaxDoc());
-		Assert.AreEqual(NUM_DOCS - 2, r.NumDocs());
-		s = newSearcher(r);
-		Assert.AreEqual(NUM_DOCS - 2, s.Search(new TermQuery(new Term("field1", "standard")), 1).TotalHits);
-		Assert.AreEqual(NUM_DOCS - 2, s.Search(new TermQuery(new Term("field2", "pulsing")), 1).TotalHits);
-		Assert.AreEqual(1, s.Search(new TermQuery(new Term("id", "76")), 1).TotalHits);
-		Assert.AreEqual(0, s.Search(new TermQuery(new Term("id", "77")), 1).TotalHits);
-		Assert.AreEqual(0, s.Search(new TermQuery(new Term("id", "44")), 1).TotalHits);
-
-		if (VERBOSE)
-		{
-		  Console.WriteLine("\nTEST: now close NRT reader");
-		}
-		r.Close();
-
-		w.Dispose();
-
-		dir.Dispose();
-	  }
-	}
-
+    public class TestExternalCodecs : LuceneTestCase
+    {
+
+        private sealed class CustomPerFieldCodec : Lucene46Codec
+        {
+
+            internal readonly PostingsFormat RamFormat = Codecs.PostingsFormat.ForName("RAMOnly");
+            internal readonly PostingsFormat DefaultFormat = Codecs.PostingsFormat.ForName("Lucene41");
+            internal readonly PostingsFormat PulsingFormat = Codecs.PostingsFormat.ForName("Pulsing41");
+
+            public override PostingsFormat GetPostingsFormatForField(string field)
+            {
+                if (field.Equals("field2") || field.Equals("id"))
+                {
+                    return PulsingFormat;
+                }
+                else if (field.Equals("field1"))
+                {
+                    return DefaultFormat;
+                }
+                else
+                {
+                    return RamFormat;
+                }
+            }
+        }
+
+        // tests storing "id" and "field2" fields as pulsing codec,
+        // whose term sort is backwards unicode code point, and
+        // storing "field1" as a custom entirely-in-RAM codec
+        [Test]
+        public virtual void TestPerFieldCodec()
+        {
+
+            int NUM_DOCS = AtLeast(173);
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: NUM_DOCS=" + NUM_DOCS);
+            }
+
+            using (BaseDirectoryWrapper dir = NewDirectory())
+            {
+                dir.CheckIndexOnClose = false; // we use a custom codec provider
+                using (IndexWriter w = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetCodec(new CustomPerFieldCodec()).SetMergePolicy(NewLogMergePolicy(3))))
+                {
+                    Documents.Document doc = new Documents.Document();
+                    // uses default codec:
+                    doc.Add(NewTextField("field1", "this field uses the standard codec as the test", Field.Store.NO));
+                    // uses pulsing codec:
+                    Field field2 = NewTextField("field2", "this field uses the pulsing codec as the test", Field.Store.NO);
+                    doc.Add(field2);
+
+                    Field idField = NewStringField("id", "", Field.Store.NO);
+
+                    doc.Add(idField);
+                    for (int i = 0; i < NUM_DOCS; i++)
+                    {
+                        idField.StringValue = "" + i;
+                        w.AddDocument(doc);
+                        if ((i + 1) % 10 == 0)
+                        {
+                            w.Commit();
+                        }
+                    }
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("TEST: now delete id=77");
+                    }
+                    w.DeleteDocuments(new Term("id", "77"));
+
+                    using (IndexReader r = DirectoryReader.Open(w, true))
+                    {
+                        Assert.AreEqual(NUM_DOCS - 1, r.NumDocs);
+                        IndexSearcher s = NewSearcher(r);
+                        Assert.AreEqual(NUM_DOCS - 1, s.Search(new TermQuery(new Term("field1", "standard")), 1).TotalHits);
+                        Assert.AreEqual(NUM_DOCS - 1, s.Search(new TermQuery(new Term("field2", "pulsing")), 1).TotalHits);
+                    }
+
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("\nTEST: now delete 2nd doc");
+                    }
+                    w.DeleteDocuments(new Term("id", "44"));
+
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("\nTEST: now force merge");
+                    }
+                    w.ForceMerge(1);
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("\nTEST: now open reader");
+                    }
+                    using (IndexReader r = DirectoryReader.Open(w, true))
+                    {
+                        Assert.AreEqual(NUM_DOCS - 2, r.MaxDoc);
+                        Assert.AreEqual(NUM_DOCS - 2, r.NumDocs);
+                        IndexSearcher s = NewSearcher(r);
+                        Assert.AreEqual(NUM_DOCS - 2, s.Search(new TermQuery(new Term("field1", "standard")), 1).TotalHits);
+                        Assert.AreEqual(NUM_DOCS - 2, s.Search(new TermQuery(new Term("field2", "pulsing")), 1).TotalHits);
+                        Assert.AreEqual(1, s.Search(new TermQuery(new Term("id", "76")), 1).TotalHits);
+                        Assert.AreEqual(0, s.Search(new TermQuery(new Term("id", "77")), 1).TotalHits);
+                        Assert.AreEqual(0, s.Search(new TermQuery(new Term("id", "44")), 1).TotalHits);
+
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("\nTEST: now close NRT reader");
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
\ No newline at end of file