NightOwl888 commented on code in PR #914:
URL: https://github.com/apache/lucenenet/pull/914#discussion_r1493331959


##########
src/Lucene.Net.Tests/Search/Spans/TestSpans.cs:
##########
@@ -320,7 +373,8 @@ private void TstNextSpans(Spans spans, int doc, int start, 
int end)
         [Test]
         public virtual void TestSpanOrEmpty()
         {
-            Spans spans = OrSpans(new string[0]);
+            // LUCENENET: Using Array.Empty<T>() instead of new string[0] to 
reduce allocations
+            Spans spans = OrSpans(Array.Empty<string>());

Review Comment:
   `Array.Empty<T>` was added in .NET 4.6. We only recently changed our minimum 
target framework from `net45` to `net462`. As a result, all existing code is 
using `Arrays.Empty<T>` instead of `Array.Empty<T>`.
   
   We should probably keep using `Arrays.Empty<T>` consistently until there is 
a concerted effort to change all of these calls to `Array.Empty<T>`. No 
objections if you wish to open a new issue for this task, but it goes beyond 
the scope of this PR. The task would also involve removing the 
`Arrays.Empty<T>` method, backing static class, and `FEATURE_ARRAYEMPTY` from 
the codebase.



##########
src/Lucene.Net.Tests/Search/Spans/TestSpans.cs:
##########
@@ -556,6 +609,7 @@ public virtual void TestSpanNots()
 
         [Test]
         [Description("LUCENENET-597")]
+        [LuceneNetSpecific]

Review Comment:
   Any ideas what the string returned here is supposed to represent?
   
   Java: `spanNear([f:lucene, f:net, f:solr], 0, true)`
   .NET: `SpanNear([f:lucene, f:net, f:solr], 0, True)`
   
   This looks like something that may be copied and pasted somewhere to me, but 
it may just be a textual description. If the former, we should probably at 
least strive to match the case of the boolean. I am guessing the name is the 
correct casing for .NET, though.
   
   Of course, we are probably using upper case for all booleans converted to 
string in .NET, because that is what .NET does by default. So, whatever the 
fix, it should be applied consistently in all queries.



##########
src/Lucene.Net.Tests/Search/BaseTestRangeFilter.cs:
##########
@@ -208,8 +198,8 @@ public virtual void TestPad()
                 string bb = Pad(b);
                 string label = a + ":" + aa + " vs " + b + ":" + bb;
                 Assert.AreEqual(aa.Length, bb.Length, "i=" + i + ": length of 
" + label);
-                Assert.IsTrue(System.String.Compare(aa, bb, 
System.StringComparison.Ordinal) < 0, "i=" + i + ": compare less than " + 
label);
+                Assert.IsTrue(string.Compare(aa, bb, StringComparison.Ordinal) 
< 0, "i=" + i + ": compare less than " + label);

Review Comment:
   Just FYI - there is a `CompareToOrdinal()` extension method that is a 
shortcut to `string.Compare(aa, bb, StringComparison.Ordinal)`. Not critical 
that we use it everywhere, though.



##########
src/Lucene.Net.Tests/Search/Spans/TestSpansAdvanced.cs:
##########
@@ -79,16 +82,9 @@ public override void SetUp()
         [TearDown]
         public override void TearDown()
         {
-            if (reader != null)
-            {
-                reader.Dispose();
-            }
-
-            if (mDirectory != null)
-            {
-                mDirectory.Dispose();
-                mDirectory = null;
-            }
+            reader.Dispose();
+            mDirectory.Dispose();

Review Comment:
   Please change this to `mDirectory?.Dispose();`. 



##########
src/Lucene.Net.Tests/Search/Spans/TestSpansAdvanced.cs:
##########
@@ -79,16 +82,9 @@ public override void SetUp()
         [TearDown]
         public override void TearDown()
         {
-            if (reader != null)
-            {
-                reader.Dispose();
-            }
-
-            if (mDirectory != null)
-            {
-                mDirectory.Dispose();
-                mDirectory = null;
-            }
+            reader.Dispose();

Review Comment:
   Please change this to `reader?.Dispose();`. We may bomb before reaching the 
line to create the reader and this will hide the original failure message.



##########
src/Lucene.Net.Tests/Search/TestBooleanOr.cs:
##########
@@ -200,9 +200,9 @@ public virtual void TestBooleanScorerMax()
 
             FixedBitSet hits = new FixedBitSet(docCount);
             AtomicInt32 end = new AtomicInt32();
-            ICollector c = new CollectorAnonymousClass(this, scorer, hits, 
end);
+            ICollector c = new CollectorAnonymousClass(hits, end);
 
-            while (end < docCount)
+            while (end.Value < docCount)

Review Comment:
   The implicit operator is overloaded here, so calling `.Value` is 
unnecessary. However, a case could be made either way as to which is more 
readable (this aligns more closely with Java).



##########
src/Lucene.Net.Tests/Search/TestSimpleExplanationsOfNonMatches.cs:
##########
@@ -28,10 +26,10 @@ public class TestSimpleExplanationsOfNonMatches : 
TestSimpleExplanations
         /// <summary>
         /// Overrides superclass to ignore matches and focus on non-matches
         /// </summary>
-        /// <seealso cref= CheckHits#checkNoMatchExplanations </seealso>
+        /// <seealso 
cref="Lucene.Net.Search.CheckHits.CheckNoMatchExplanations" />

Review Comment:
   `CheckHits` unnecessarily calls `Convert.ToInt32(object?, CultureInfo?)` in 
5 places, causing boxing. Please fix. In these cases, we don't need the method 
call at all because we are converting `int` to `int`.



##########
src/Lucene.Net.Tests/Search/TestScorerPerf.cs:
##########
@@ -63,34 +63,35 @@ public virtual void CreateDummySearcher()
             s = NewSearcher(r);
         }
 
-        public virtual void CreateRandomTerms(int nDocs, int nTerms, double 
power, Directory dir)
-        {
-            int[] freq = new int[nTerms];
-            terms = new Term[nTerms];
-            for (int i = 0; i < nTerms; i++)
-            {
-                int f = (nTerms + 1) - i; // make first terms less frequent
-                freq[i] = (int)Math.Ceiling(Math.Pow(f, power));
-                terms[i] = new Term("f", char.ToString((char)('A' + i)));
-            }
-
-            IndexWriter iw = new IndexWriter(dir, 
NewIndexWriterConfig(TEST_VERSION_CURRENT, new 
MockAnalyzer(Random)).SetOpenMode(OpenMode.CREATE));
-            for (int i = 0; i < nDocs; i++)
-            {
-                Document d = new Document();
-                for (int j = 0; j < nTerms; j++)
-                {
-                    if (Random.Next(freq[j]) == 0)
-                    {
-                        d.Add(NewStringField("f", terms[j].Text, 
Field.Store.NO));
-                        //System.out.println(d);
-                    }
-                }
-                iw.AddDocument(d);
-            }
-            iw.ForceMerge(1);
-            iw.Dispose();
-        }
+        // LUCENENET: unused so commented out here, only used by commented-out 
code below
+        // public virtual void CreateRandomTerms(int nDocs, int nTerms, double 
power, Directory dir)
+        // {
+        //     int[] freq = new int[nTerms];
+        //     terms = new Term[nTerms];

Review Comment:
   `internal Term[] terms` is now generating warnings because it is unused. 
Please fix.



##########
src/Lucene.Net.Tests/Support/Threading/TestUninterruptableMonitor.cs:
##########
@@ -33,7 +33,7 @@ public class TestUninterruptableMonitor : LuceneTestCase
     {
         private class TransactionlThreadInterrupt : ThreadJob

Review Comment:
   Please correct the class name. It should be `TransactionalThreadInterrupt`.



##########
src/Lucene.Net.Tests/Search/TestBooleanOr.cs:
##########
@@ -200,9 +200,9 @@ public virtual void TestBooleanScorerMax()
 
             FixedBitSet hits = new FixedBitSet(docCount);
             AtomicInt32 end = new AtomicInt32();
-            ICollector c = new CollectorAnonymousClass(this, scorer, hits, 
end);
+            ICollector c = new CollectorAnonymousClass(hits, end);
 
-            while (end < docCount)
+            while (end.Value < docCount)
             {
                 int inc = TestUtil.NextInt32(Random, 1, 1000);
                 end.AddAndGet(inc);

Review Comment:
   In Java, this was `end.GetAndAdd(inc)`.
   
   Since this was likely done because at one point the method didn't exist, we 
should do a sweep to ensure that all calls to `GetAndAdd()`, `AddAndGet()`, 
`IncrementAndGet()`, `GetAndIncrement()`, `DecrementAndGet()`, and 
`GetAndDecrement()` match Lucene (for both `AtomicInt32` and `AtomicInt64`). We 
may not have caught this everywhere it matters. This should be a separate task 
outside of the scope of this PR, we just need a new issue about it.



##########
src/Lucene.Net.Tests/Search/TestCachingWrapperFilter.cs:
##########
@@ -207,29 +207,19 @@ public virtual void TestNullDocIdSet()
             IndexReader reader = 
SlowCompositeReaderWrapper.Wrap(DirectoryReader.Open(dir));

Review Comment:
   The `IndexReader` constructor is:
   
   
https://github.com/apache/lucenenet/blob/b1476aee4fe21131899c1f43b2e06e25971b3ebe/src/Lucene.Net/Index/IndexReader.cs#L84-L90
   
   We can remove the check and error message, since it is declared `private 
protected`. But we will need a `LUCENENET specific` comment to indicate we 
removed it in the .NET version and enforced it at the compiler level. There may 
also be tests to confirm this exception is thrown.
   
   This can be another issue that is outside of the scope of this PR.



##########
src/Lucene.Net.Tests/Search/TestBoolean2.cs:
##########
@@ -225,7 +229,7 @@ public virtual void TestQueries07()
             query.Add(new TermQuery(new Term(field, "w3")), Occur.MUST_NOT);
             query.Add(new TermQuery(new Term(field, "xx")), Occur.MUST_NOT);
             query.Add(new TermQuery(new Term(field, "w5")), Occur.MUST_NOT);
-            int[] expDocNrs = new int[] { };
+            int[] expDocNrs = Array.Empty<int>(); // LUCENENET: instead of new 
int[] { };

Review Comment:
   See my comment on TestSpans.cs



##########
src/Lucene.Net.Tests/Search/Spans/TestSpansAdvanced.cs:
##########
@@ -131,7 +127,7 @@ protected internal virtual void 
DoTestBooleanQueryWithSpanQueries(IndexSearcher
 
         /// <summary>
         /// Checks to see if the hits are what we expected.
-        /// 
+        ///
         /// LUCENENET specific

Review Comment:
   This comment is out of date, and can be removed.
   
   We can probably also go back to making this method static, since this was 
only done to access the instance level Similarity property that no longer 
exists.



##########
src/Lucene.Net.Tests/Search/TestBooleanQuery.cs:
##########
@@ -182,9 +182,6 @@ public virtual void TestDeMorgan()
             IndexSearcher searcher = NewSearcher(multireader);
             Assert.AreEqual(0, searcher.Search(query, 10).TotalHits);
 
-
-            Task foo = new Task(TestDeMorgan);
-
             TaskScheduler es = TaskScheduler.Default;
             searcher = new IndexSearcher(multireader, es);

Review Comment:
   Would it make sense to add an overload here that accepts a cancellation 
token?



##########
src/Lucene.Net.Tests/Search/TestCachingCollector.cs:
##########
@@ -63,9 +67,14 @@ public override long GetCost()
 
         private class NoOpCollector : ICollector
         {
+            // LUCENENET: static instances to reduce allocations
+            public static readonly NoOpCollector FalseInstance = new 
NoOpCollector(false);

Review Comment:
   Due to the fact that this serves as a demo to users, it would not be a good 
practice to make this static, since typical collectors will have state (even if 
this one does not).



##########
src/Lucene.Net.Tests/Search/TestCachingCollector.cs:
##########
@@ -31,7 +31,11 @@ public class TestCachingCollector : LuceneTestCase
 
         private class MockScorer : Scorer
         {
-            internal MockScorer()
+            // LUCENENET: static instance to reduce allocations
+            public static readonly MockScorer Default = new MockScorer();

Review Comment:
   Due to the fact that this serves as a demo to users, it would not be a good 
practice to make this static, since typical scorers will have state (even if 
this one does not).



##########
src/Lucene.Net.Tests/Search/TestBooleanScorer.cs:
##########
@@ -125,13 +125,10 @@ public override bool Score(ICollector c, int maxDoc)
 
         private sealed class CollectorAnonymousClass : ICollector

Review Comment:
   Due to covariance issues with `Lucene.Net.Grouping`, we changed `Collector` 
from an abstract class to an interface. However, we also have a static 
`Collector` class that is only used to put constants that are not possible to 
put on an interface in .NET. We should probably change that static class back 
to an abstract class that implements `ICollector` and leave `ICollector` on all 
of the methods throughout the codebase. This makes it easier for users who are 
copying code from Java to implement a collector.
   
   However, we need an analyzer to ensure that none of our internal code 
actually accepts `Collector` as an argument.
   
   This can be a new issue that is done outside of the scope of this PR.
   
   Do note that we could potentially get rid of the `ICollector` interface 
altogether if the `GroupingSearch` class were divided into 3 separate classes 
instead of having main `Search` methods that deal with `object` closing types. 
I would really like to get rid of the non-generic `IDictionary` and 
`ICollection` usages in `Lucene.Net.Grouping` and `Lucene.Net.Queries` and 
replace them with generics prior to the release. J2N doesn't fully support 
non-generic collection interfaces, so it is best not to use them at all.
   
   @rclabo did some analysis in this area and added some tests (as demos), so 
he would be a big help to accomplish this.



##########
src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs:
##########
@@ -251,7 +245,7 @@ internal RandomGen(TestCustomSearcherSort outerInstance, 
Random random)
 
             // Just to generate some different Lucene Date strings
             internal virtual string LuceneDate
-                => DateTools.TimeToString((DateTime.Now.Ticks / 
TimeSpan.TicksPerMillisecond) + random.Next() - int.MinValue, 
DateResolution.DAY);
+                => DateTools.TimeToString((@base.Ticks / 
TimeSpan.TicksPerMillisecond) + random.Next() - int.MinValue, 
DateResolution.DAY);

Review Comment:
   This is not correct to generate a date for ticks. The default now assumes to 
use milliseconds since Unix epoch (as it is in Lucene). Please use:
   
   ```c#
   internal virtual string LuceneDate
       => DateTools.TimeToString(DateTools.TicksToUnixTimeMilliseconds(@base) + 
random.Next() - int.MinValue, DateResolution.DAY);
   ```
   
   It is possible that the following would be equivalent, but it would need to 
be tested to confirm:
   
   ```c#
   internal virtual string LuceneDate
       => DateTools.TimeToString(J2N.Time.GetMillisecondsSinceUnixEpoch(@base) 
+ random.Next() - int.MinValue, DateResolution.DAY);
   ```
   
   ```c#
   internal virtual string LuceneDate
       => DateTools.TimeToString(@base.Ticks + random.Next() - int.MinValue, 
DateResolution.DAY, NumericRepresentation.TICKS);
   ```
   
   The `DateTools` representation for input `long` and output `long` is now 
consistent. In Lucene.Net 3.x it was expecting ticks as milliseconds as input 
and was outputting ticks. We have built in legacy support for 
`TICKS_AS_MILLISECONDS`, but we shouldn't be using it in code going forward.



##########
src/Lucene.Net.Tests/Search/TestFieldCacheRangeFilter.cs:
##########
@@ -501,7 +501,7 @@ public virtual void TestFieldCacheRangeFilterFloats()
 
             int numDocs = reader.NumDocs;
             float minIdO = Convert.ToSingle(minId + .5f);
-            float medIdO = Convert.ToSingle((float)minIdO + ((maxId - minId)) 
/ 2.0f);
+            float medIdO = Convert.ToSingle(minIdO + ((maxId - minId)) / 2.0f);

Review Comment:
   FYI - we need to be careful to run these tests on x86 (.NET Framework) to 
ensure this doesn't cause issues. I ran this 3x on Azure DevOps and it seems to 
be okay.  IIRC, there were issues with losing precision when leaving it up to 
the compiler to do an implicit `float` > `double` cast, which is fixed by 
casting to `double` explicitly.



##########
src/Lucene.Net.Tests/Search/TestComplexExplanationsOfNonMatches.cs:
##########
@@ -28,10 +26,10 @@ public class TestComplexExplanationsOfNonMatches : 
TestComplexExplanations
         /// <summary>
         /// Overrides superclass to ignore matches and focus on non-matches
         /// </summary>
-        /// <seealso cref= CheckHits#checkNoMatchExplanations </seealso>
+        /// <seealso cref="CheckHits.CheckNoMatchExplanations" />

Review Comment:
   Without specifying the parameters, this links to the wrong overload.



##########
src/Lucene.Net.Tests/Search/TestPhraseQuery.cs:
##########
@@ -63,22 +64,22 @@ public override void BeforeClass()
             base.BeforeClass();
 
             directory = NewDirectory();
-            Analyzer analyzer = new AnalyzerAnonymousClass();
+            Analyzer analyzer = AnalyzerAnonymousClass.Default; // LUCENENET: 
using static instance

Review Comment:
   This will never be reused so we can revert it back to a constructor call for 
clarity.



##########
src/Lucene.Net.Tests/Search/TestMultiThreadTermVectors.cs:
##########
@@ -60,7 +58,7 @@ public override void SetUp()
             customType.StoreTermVectors = true;
             for (int i = 0; i < numDocs; i++)
             {
-                Documents.Document doc = new Documents.Document();
+                Document doc = new Document();
                 Field fld = NewField("field", English.Int32ToEnglish(i), 
customType);

Review Comment:
   This is duplicate functionality:
   
   
https://github.com/apache/lucenenet/blob/b1476aee4fe21131899c1f43b2e06e25971b3ebe/src/Lucene.Net.TestFramework/Util/English.cs
   
https://github.com/apache/lucenenet/blob/b1476aee4fe21131899c1f43b2e06e25971b3ebe/src/Lucene.Net.Benchmark/Support/Util/EnglishNumberFormatExtensions.cs
   
   The first was actually part of the test framework and the second is a 
workaround because ICU4N didn't support rule-based number formatting until 
recently. `Lucene.Net.Benchmark` only uses English language, though, so we 
don't need to rely on ICU4N for this even though we now [have 
RuleBasedNumberFormat 
support](https://github.com/NightOwl888/ICU4N/blob/v60.1.0-alpha.402/src/ICU4N/Support/FormatNumberRuleBasedExtension.cs).
 ICU4N 60.1.0-alpha.402 only has `RuleBasedNumberFormat` support for `net6.0` 
and `net7.0`, but the main branch has support for `net451`+.
   
   I suppose this one is also out of scope for this PR.



##########
src/Lucene.Net.Tests/Support/TestCase.cs:
##########
@@ -1,50 +0,0 @@
-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.
-     * 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.
-     */
-
-    /// <summary>
-    /// Support for junit.framework.TestCase.getName().
-    /// {{Lucene.Net-2.9.1}} Move to another location after LUCENENET-266
-    /// </summary>
-    public static class TestCase // LUCENENET specific: CA1052 Static holder 
types should be Static or NotInheritable
-    {
-        public static string GetName()
-        {
-            return GetTestCaseName(false);
-        }
-
-        public static string GetFullName()
-        {
-            return GetTestCaseName(true);
-        }
-
-        static string GetTestCaseName(bool fullName)
-        {
-            System.Diagnostics.StackTrace stackTrace = new 
System.Diagnostics.StackTrace();
-            for (int i = 0; i < stackTrace.FrameCount; i++)
-            {
-                System.Reflection.MethodBase method = 
stackTrace.GetFrame(i).GetMethod();
-                object[] testAttrs = 
method.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), false);
-                if (testAttrs != null && testAttrs.Length > 0)
-                    if (fullName) return method.DeclaringType.FullName + "." + 
method.Name;

Review Comment:
   This looks like it is something like what we need to show the test name. 
However, we need the type where the method is running, not the declaring type. 
We should aim to fix this in the Test Framework, possibly in the 
`LuceneTestCase` class.



##########
src/Lucene.Net.Tests/Search/TestFilteredQuery.cs:
##########
@@ -46,7 +46,7 @@ namespace Lucene.Net.Search
     /// <summary>
     /// FilteredQuery JUnit tests.
     ///
-    /// <p>Created: Apr 21, 2004 1:21:46 PM

Review Comment:
   We have been converting these to `<para/>`. Let's do that here, too.



##########
src/Lucene.Net.Tests/Search/TestQueryRescorer.cs:
##########
@@ -363,7 +357,7 @@ public virtual void TestRandom()
             //System.out.println("numHits=" + numHits + " reverse=" + reverse);
             TopDocs hits = s.Search(new TermQuery(new Term("field", "a")), 
numHits);
 
-            TopDocs hits2 = new QueryRescorerAnonymousClass3(this, new 
FixedScoreQuery(idToNum, reverse))
+            TopDocs hits2 = new QueryRescorerAnonymousClass3(new 
FixedScoreQuery(idToNum, reverse))

Review Comment:
   Below we are missing the `CultureInfo.InvariantCulture` parameter for the 
following lines:
   
   
https://github.com/paulirwin/lucene.net/blob/test-review-j-s/src/Lucene.Net.Tests/Search/TestQueryRescorer.cs#L376-L377
   
   Negative integers will use localized minus signs, so to match Java we must 
use this. Please fix and be sure to check for other string-to-number and 
number-to-string conversions. I am going to create a new task for this because 
there are many and several of them have common names like `ToString()` and we 
just need to check the numeric/date data types. The IDE tools are inadequate 
for pinpointing them, plus we have custom ones in J2N.
   
   We also are unnecessarily calling the pass-through methods such as 
`Convert.ToInt32(int)`. Ideally, we wouldn't have these calls in production 
code. Having them in the tests isn't such a big deal. 
   
   And we will have new `ReadOnlySpan<char>` and `Span<char>` overloads of 
`TryFormat/Parse/TryParse` in J2N that we will be able to take advantage of for 
better performance.



##########
src/Lucene.Net.Tests/Search/TestFieldCacheRewriteMethod.cs:
##########
@@ -54,29 +54,12 @@ public virtual void TestEquals()
             Assert.AreEqual(a1, a2);
             Assert.IsFalse(a1.Equals(b));
 
-            a1.MultiTermRewriteMethod = (new FieldCacheRewriteMethod());
-            a2.MultiTermRewriteMethod = (new FieldCacheRewriteMethod());
-            b.MultiTermRewriteMethod = (new FieldCacheRewriteMethod());
+            a1.MultiTermRewriteMethod = new FieldCacheRewriteMethod();
+            a2.MultiTermRewriteMethod = new FieldCacheRewriteMethod();
+            b.MultiTermRewriteMethod = new FieldCacheRewriteMethod();
             Assert.AreEqual(a1, a2);
             Assert.IsFalse(a1.Equals(b));
             QueryUtils.Check(a1);
         }
-
-
-
-        #region TestSnapshotDeletionPolicy
-        // LUCENENET NOTE: Tests in a base class are not pulled into the 
correct

Review Comment:
   I know we discussed this before, but I think in CI we still have an issue 
with these. When we get a test failure in Azure DevOps, NUnit displays only the 
base class, not the class where the failure occurred. This can make it 
difficult to work out which of the subclasses caused the failure, especially if 
there are multiple levels.
   
   We do need an issue created to investigate whether we can improve the 
reporting that NUnit does to show the subclass (perhaps by overriding the name 
of the test to include the fully qualified name or class-qualified name), but 
we shouldn't remove these until we have a replacement that allows us to 
differentiate between these tests.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscr...@lucenenet.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to