You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/08/02 04:12:18 UTC

[01/12] lucenenet git commit: Ported StreamTokenizer from Apache Harmony

Repository: lucenenet
Updated Branches:
  refs/heads/master db1f605cd -> ea879c611


Ported StreamTokenizer from Apache Harmony


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

Branch: refs/heads/master
Commit: 05c8a040818010ed608791f71505d2a005f0ed48
Parents: db1f605
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Tue Jul 25 20:16:50 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Tue Jul 25 20:16:50 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   1 +
 .../Support/IO/TestStreamTokenizer.cs           | 514 +++++++++++++
 src/Lucene.Net/Lucene.Net.csproj                |   1 +
 src/Lucene.Net/Support/IO/StreamTokenizer.cs    | 738 +++++++++++++++++++
 4 files changed, 1254 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/05c8a040/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 de94c52..7631329 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -520,6 +520,7 @@
     <Compile Include="Support\IO\TestByteBuffer.cs" />
     <Compile Include="Support\IO\TestHeapByteBuffer.cs" />
     <Compile Include="Support\IO\TestReadOnlyHeapByteBuffer.cs" />
+    <Compile Include="Support\IO\TestStreamTokenizer.cs" />
     <Compile Include="Support\SmallObject.cs" />
     <Compile Include="Support\TestPriorityQueue.cs" />
     <Compile Include="Support\Threading\TestCloseableThreadLocal.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/05c8a040/src/Lucene.Net.Tests/Support/IO/TestStreamTokenizer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/IO/TestStreamTokenizer.cs b/src/Lucene.Net.Tests/Support/IO/TestStreamTokenizer.cs
new file mode 100644
index 0000000..5e50163
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/IO/TestStreamTokenizer.cs
@@ -0,0 +1,514 @@
+// This class was sourced from the Apache Harmony project
+// https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/
+
+using Lucene.Net.Util;
+using NUnit.Framework;
+using System;
+using System.IO;
+using System.Text;
+
+namespace Lucene.Net.Support.IO
+{
+    /*
+     * 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.
+     */
+
+    [TestFixture]
+    public class TestStreamTokenizer : LuceneTestCase
+    {
+        StringReader r;
+
+        StreamTokenizer st;
+
+        String testString;
+
+        /**
+         * @tests java.io.StreamTokenizer#StreamTokenizer(java.io.InputStream)
+         */
+        [Test]
+        public void Test_ConstructorLSystem_IO_InputStream()
+        {
+#pragma warning disable 612, 618
+            st = new StreamTokenizer(new MemoryStream(
+#pragma warning restore 612, 618
+                Encoding.UTF8.GetBytes("/comments\n d 8 'h'")));
+
+
+            assertEquals("the next token returned should be the letter d",
+                     StreamTokenizer.TT_WORD, st.NextToken());
+
+            assertEquals("the next token returned should be the letter d",
+                     "d", st.StringValue);
+
+
+            assertEquals("the next token returned should be the digit 8",
+                     StreamTokenizer.TT_NUMBER, st.NextToken());
+
+            assertEquals("the next token returned should be the digit 8",
+                     8.0, st.NumberValue);
+
+
+            assertEquals("the next token returned should be the quote character",
+                     39, st.NextToken());
+
+            assertEquals("the next token returned should be the quote character",
+                     "h", st.StringValue);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#StreamTokenizer(java.io.Reader)
+         */
+        [Test]
+        public void Test_ConstructorLSystem_IO_TextReader()
+        {
+            setTest("/testing\n d 8 'h' ");
+            assertEquals("the next token returned should be the letter d skipping the comments",
+                     StreamTokenizer.TT_WORD, st.NextToken());
+            assertEquals("the next token returned should be the letter d",
+                     "d", st.StringValue);
+
+            assertEquals("the next token returned should be the digit 8",
+                     StreamTokenizer.TT_NUMBER, st.NextToken());
+            assertEquals("the next token returned should be the digit 8",
+                     8.0, st.NumberValue);
+
+            assertEquals("the next token returned should be the quote character",
+                     39, st.NextToken());
+            assertEquals("the next token returned should be the quote character",
+                     "h", st.StringValue);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#commentChar(int)
+         */
+        [Test]
+        public void Test_commentCharI()
+        {
+            setTest("*comment \n / 8 'h' ");
+            st.OrdinaryChar('/');
+            st.CommentChar('*');
+            assertEquals("nextToken() did not return the character / skiping the comments starting with *",
+                     47, st.NextToken());
+            assertTrue("the next token returned should be the digit 8", st
+                   .NextToken() == StreamTokenizer.TT_NUMBER
+                   && st.NumberValue == 8.0);
+            assertTrue("the next token returned should be the quote character",
+                   st.NextToken() == 39 && st.StringValue.equals("h"));
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#eolIsSignificant(boolean)
+         */
+        [Test]
+        public void Test_eolIsSignificantZ()
+        {
+            setTest("d 8\n");
+            // by default end of line characters are not significant
+            assertTrue("nextToken did not return d",
+                   st.NextToken() == StreamTokenizer.TT_WORD
+                   && st.StringValue.equals("d"));
+            assertTrue("nextToken did not return 8",
+                   st.NextToken() == StreamTokenizer.TT_NUMBER
+                   && st.NumberValue == 8.0);
+            assertTrue("nextToken should be the end of file",
+                   st.NextToken() == StreamTokenizer.TT_EOF);
+            setTest("d\n");
+            st.IsEOLSignificant = (true);
+            // end of line characters are significant
+            assertTrue("nextToken did not return d",
+                   st.NextToken() == StreamTokenizer.TT_WORD
+                   && st.StringValue.equals("d"));
+            assertTrue("nextToken is the end of line",
+                   st.NextToken() == StreamTokenizer.TT_EOL);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#lineno()
+         */
+        [Test]
+        public void Test_lineno()
+        {
+            setTest("d\n 8\n");
+            assertEquals("the lineno should be 1", 1, st.LineNumber);
+            st.NextToken();
+            st.NextToken();
+            assertEquals("the lineno should be 2", 2, st.LineNumber);
+            st.NextToken();
+            assertEquals("the next line no should be 3", 3, st.LineNumber);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#lowerCaseMode(boolean)
+         */
+        [Test]
+        public void Test_lowerCaseModeZ()
+        {
+            // SM.
+            setTest("HELLOWORLD");
+            st.LowerCaseMode = (true);
+
+            st.NextToken();
+            assertEquals("sval not converted to lowercase.", "helloworld", st.StringValue
+                     );
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#nextToken()
+         */
+        [Test]
+        public void Test_nextToken()
+        {
+            // SM.
+            // LUCENENET NOTE: The original test had \257 (which is octal)
+            // that is not supported in a .NET string, so we convert to decimal 175 here.
+            // This also changes the semantics of the test, because for whatever
+            // reason in Java it was expecting the octal number to register as a TT_WORD.
+            // So, we changed to expect a TT_NUMBER as a result of the above change.
+            // Also, we don't need to escape single quotes in .NET.
+            setTest("\r\n/* fje fje 43.4 f \r\n f g */  456.459 \r\n"
+                    + "Hello  / 	\r\n \r\n \n \r 175 Hi 'Hello World'");
+            st.OrdinaryChar('/');
+            st.SlashStarComments = true;
+            st.NextToken();
+            assertTrue("Wrong Token type1: " + (char)st.TokenType,
+                   st.TokenType == StreamTokenizer.TT_NUMBER);
+            st.NextToken();
+            assertTrue("Wrong Token type2: " + st.TokenType,
+                   st.TokenType == StreamTokenizer.TT_WORD);
+            st.NextToken();
+            assertTrue("Wrong Token type3: " + st.TokenType, st.TokenType == '/');
+            st.NextToken();
+            assertTrue("Wrong Token type4: " + st.TokenType,
+                   st.TokenType == StreamTokenizer.TT_NUMBER);
+            st.NextToken();
+            assertTrue("Wrong Token type5: " + st.TokenType,
+                   st.TokenType == StreamTokenizer.TT_WORD);
+            st.NextToken();
+            assertTrue("Wrong Token type6: " + st.TokenType, st.TokenType == '\'');
+            assertTrue("Wrong Token type7: " + st.TokenType, st.StringValue
+                   .equals("Hello World"));
+            st.NextToken();
+            assertTrue("Wrong Token type8: " + st.TokenType, st.TokenType == -1);
+
+            using (var pin = new MemoryStream(Encoding.UTF8.GetBytes("hello\n\r\r")))
+            {
+#pragma warning disable 612, 618
+                StreamTokenizer s = new StreamTokenizer(pin);
+#pragma warning restore 612, 618
+                s.IsEOLSignificant = (true);
+
+                assertTrue("Wrong token 1,1",
+                       s.NextToken() == StreamTokenizer.TT_WORD
+                       && s.StringValue.equals("hello"));
+
+                assertTrue("Wrong token 1,2", s.NextToken() == '\n');
+
+                assertTrue("Wrong token 1,3", s.NextToken() == '\n');
+
+                assertTrue("Wrong token 1,4", s.NextToken() == '\n');
+
+
+                assertTrue("Wrong token 1,5",
+                       s.NextToken() == StreamTokenizer.TT_EOF);
+            }
+            StreamTokenizer tokenizer = new StreamTokenizer(
+                                    new StringReader("\n \r\n#"));
+            tokenizer.OrdinaryChar('\n'); // make \n ordinary
+            tokenizer.IsEOLSignificant = (true);
+
+            assertTrue("Wrong token 2,1", tokenizer.NextToken() == '\n');
+
+            assertTrue("Wrong token 2,2", tokenizer.NextToken() == '\n');
+
+            assertEquals("Wrong token 2,3", '#', tokenizer.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#ordinaryChar(int)
+         */
+        [Test]
+        public void Test_ordinaryCharI()
+        {
+            // SM.
+            setTest("Ffjein 893");
+            st.OrdinaryChar('F');
+            st.NextToken();
+            assertTrue("OrdinaryChar failed." + (char)st.TokenType,
+                       st.TokenType == 'F');
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#ordinaryChars(int, int)
+         */
+        [Test]
+        public void Test_ordinaryCharsII()
+        {
+            // SM.
+            setTest("azbc iof z 893");
+            st.OrdinaryChars('a', 'z');
+            assertEquals("OrdinaryChars failed.", 'a', st.NextToken());
+            assertEquals("OrdinaryChars failed.", 'z', st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#parseNumbers()
+         */
+        [Test]
+        public void Test_parseNumbers()
+        {
+            // SM
+            setTest("9.9 678");
+            assertTrue("Base behavior failed.",
+                       st.NextToken() == StreamTokenizer.TT_NUMBER);
+            st.OrdinaryChars('0', '9');
+            assertEquals("setOrdinary failed.", '6', st.NextToken());
+            st.ParseNumbers();
+            assertTrue("parseNumbers failed.",
+                       st.NextToken() == StreamTokenizer.TT_NUMBER);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#pushBack()
+         */
+        [Test]
+        public void Test_pushBack()
+        {
+            // SM.
+            setTest("Hello 897");
+            st.NextToken();
+            st.PushBack();
+            assertTrue("PushBack failed.",
+                       st.NextToken() == StreamTokenizer.TT_WORD);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#quoteChar(int)
+         */
+        [Test]
+        public void Test_quoteCharI()
+        {
+            // SM
+            setTest("<Hello World<    HelloWorldH");
+            st.QuoteChar('<');
+            assertEquals("QuoteChar failed.", '<', st.NextToken());
+            assertEquals("QuoteChar failed.", "Hello World", st.StringValue);
+            st.QuoteChar('H');
+            st.NextToken();
+            assertEquals("QuoteChar failed for word.", "elloWorld", st.StringValue
+                         );
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#resetSyntax()
+         */
+        [Test]
+        public void Test_resetSyntax()
+        {
+            // SM
+            setTest("H 9\' ello World");
+            st.ResetSyntax();
+            assertTrue("resetSyntax failed1." + (char)st.TokenType,
+                       st.NextToken() == 'H');
+            assertTrue("resetSyntax failed1." + (char)st.TokenType,
+                       st.NextToken() == ' ');
+            assertTrue("resetSyntax failed2." + (char)st.TokenType,
+                       st.NextToken() == '9');
+            assertTrue("resetSyntax failed3." + (char)st.TokenType,
+                       st.NextToken() == '\'');
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashSlashComments(boolean)
+         */
+        [Test]
+        public void Test_slashSlashCommentsZ()
+        {
+            // SM.
+            setTest("// foo \r\n /fiji \r\n -456");
+            st.OrdinaryChar('/');
+            st.SlashSlashComments = (true);
+            assertEquals("Test failed.", '/', st.NextToken());
+            assertTrue("Test failed.",
+                       st.NextToken() == StreamTokenizer.TT_WORD);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashSlashComments(boolean)
+         */
+        [Test]
+        public void Test_slashSlashComments_withSSOpen()
+        {
+            TextReader reader = new StringReader("t // t t t");
+
+            StreamTokenizer st = new StreamTokenizer(reader);
+            st.SlashSlashComments = (true);
+
+            assertEquals(StreamTokenizer.TT_WORD, st.NextToken());
+            assertEquals(StreamTokenizer.TT_EOF, st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashSlashComments(boolean)
+         */
+        [Test]
+        public void Test_slashSlashComments_withSSOpen_NoComment()
+        {
+            TextReader reader = new StringReader("// t");
+
+            StreamTokenizer st = new StreamTokenizer(reader);
+            st.SlashSlashComments = (true);
+            st.OrdinaryChar('/');
+
+            assertEquals(StreamTokenizer.TT_EOF, st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashSlashComments(boolean)
+         */
+        [Test]
+        public void Test_slashSlashComments_withSSClosed()
+        {
+            TextReader reader = new StringReader("// t");
+
+            StreamTokenizer st = new StreamTokenizer(reader);
+            st.SlashSlashComments = (false);
+            st.OrdinaryChar('/');
+
+            assertEquals('/', st.NextToken());
+            assertEquals('/', st.NextToken());
+            assertEquals(StreamTokenizer.TT_WORD, st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashStarComments(boolean)
+         */
+        [Test]
+        public void Test_slashStarCommentsZ()
+        {
+            setTest("/* foo \r\n /fiji \r\n*/ -456");
+            st.OrdinaryChar('/');
+            st.SlashStarComments = (true);
+            assertTrue("Test failed.",
+                       st.NextToken() == StreamTokenizer.TT_NUMBER);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashStarComments(boolean)
+         */
+        [Test]
+        public void Test_slashStarComments_withSTOpen()
+        {
+            TextReader reader = new StringReader("t /* t */ t");
+
+            StreamTokenizer st = new StreamTokenizer(reader);
+            st.SlashStarComments = (true);
+
+            assertEquals(StreamTokenizer.TT_WORD, st.NextToken());
+            assertEquals(StreamTokenizer.TT_WORD, st.NextToken());
+            assertEquals(StreamTokenizer.TT_EOF, st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#slashStarComments(boolean)
+         */
+        [Test]
+        public void Test_slashStarComments_withSTClosed()
+        {
+            TextReader reader = new StringReader("t /* t */ t");
+
+            StreamTokenizer st = new StreamTokenizer(reader);
+            st.SlashStarComments = (false);
+
+            assertEquals(StreamTokenizer.TT_WORD, st.NextToken());
+            assertEquals(StreamTokenizer.TT_EOF, st.NextToken());
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#toString()
+         */
+        [Test]
+        public void Test_toString()
+        {
+            setTest("ABC Hello World");
+            st.NextToken();
+            assertTrue("toString failed." + st.toString(),
+                       st.toString().equals(
+                                "Token[ABC], line 1"));
+
+            // Regression test for HARMONY-4070
+            byte[] data = new byte[] { (byte)'-' };
+#pragma warning disable 612, 618
+            StreamTokenizer tokenizer = new StreamTokenizer(
+                    new MemoryStream(data));
+#pragma warning restore 612, 618
+            tokenizer.NextToken();
+            String result = tokenizer.toString();
+            assertEquals("Token['-'], line 1", result);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#whitespaceChars(int, int)
+         */
+        [Test]
+        public void Test_whitespaceCharsII()
+        {
+            setTest("azbc iof z 893");
+            st.WhitespaceChars('a', 'z');
+            assertTrue("OrdinaryChar failed.",
+                       st.NextToken() == StreamTokenizer.TT_NUMBER);
+        }
+
+        /**
+         * @tests java.io.StreamTokenizer#wordChars(int, int)
+         */
+        [Test]
+        public void Test_wordCharsII()
+        {
+            setTest("A893 -9B87");
+            st.WordChars('0', '9');
+            assertTrue("WordChar failed1.",
+                       st.NextToken() == StreamTokenizer.TT_WORD);
+            assertEquals("WordChar failed2.", "A893", st.StringValue);
+            assertTrue("WordChar failed3.",
+                       st.NextToken() == StreamTokenizer.TT_NUMBER);
+            st.NextToken();
+            assertEquals("WordChar failed4.", "B87", st.StringValue);
+
+            setTest("    Hello World");
+            st.WordChars(' ', ' ');
+            st.NextToken();
+            assertEquals("WordChars failed for whitespace.", "Hello World", st.StringValue
+                         );
+
+            setTest("    Hello World\r\n  \'Hello World\' Hello\' World");
+            st.WordChars(' ', ' ');
+            st.WordChars('\'', '\'');
+            st.NextToken();
+            assertTrue("WordChars failed for whitespace: " + st.StringValue, st.StringValue
+                       .equals("Hello World"));
+            st.NextToken();
+            assertTrue("WordChars failed for quote1: " + st.StringValue, st.StringValue
+                       .equals("\'Hello World\' Hello\' World"));
+        }
+
+        private void setTest(string s)
+        {
+            testString = s;
+            r = new StringReader(testString);
+            st = new StreamTokenizer(r);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/05c8a040/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Lucene.Net.csproj b/src/Lucene.Net/Lucene.Net.csproj
index 3dc6d30..e29c82a 100644
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@ -652,6 +652,7 @@
     <Compile Include="Support\IO\FileStreamExtensions.cs" />
     <Compile Include="Support\ICallable.cs" />
     <Compile Include="Support\ICharSequence.cs" />
+    <Compile Include="Support\IO\StreamTokenizer.cs" />
     <Compile Include="Support\RectangularArrays.cs" />
     <Compile Include="Support\Search\ReferenceContext.cs" />
     <Compile Include="Support\Search\ReferenceManagerExtensions.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/05c8a040/src/Lucene.Net/Support/IO/StreamTokenizer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/IO/StreamTokenizer.cs b/src/Lucene.Net/Support/IO/StreamTokenizer.cs
new file mode 100644
index 0000000..ecfb5d5
--- /dev/null
+++ b/src/Lucene.Net/Support/IO/StreamTokenizer.cs
@@ -0,0 +1,738 @@
+// This class was sourced from the Apache Harmony project
+// https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace Lucene.Net.Support.IO
+{
+    /*
+     * 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>
+    /// Parses a stream into a set of defined tokens, one at a time. The different
+    /// types of tokens that can be found are numbers, identifiers, quoted strings,
+    /// and different comment styles. The class can be used for limited processing
+    /// of source code of programming languages like Java, although it is nowhere
+    /// near a full parser.
+    /// </summary>
+    public class StreamTokenizer
+    {
+        /// <summary>
+        /// Contains a number if the current token is a number 
+        /// (<see cref="TokenType"/> == <see cref="TT_NUMBER"/>).
+        /// </summary>
+        public double NumberValue { get; set; }
+
+        /// <summary>
+        /// Contains a string if the current token is a word 
+        /// (<see cref="TokenType"/> == <see cref="TT_WORD"/>).
+        /// </summary>
+        public string StringValue { get; set; }
+
+        /// <summary>
+        /// The constant representing the end of the stream.
+        /// </summary>
+        public const int TT_EOF = -1;
+
+        /// <summary>
+        /// The constant representing the end of the line.
+        /// </summary>
+        public const int TT_EOL = '\n';
+
+        /// <summary>
+        /// The constant representing a number token.
+        /// </summary>
+        public const int TT_NUMBER = -2;
+
+        /// <summary>
+        /// The constant representing a word token.
+        /// </summary>
+        public const int TT_WORD = -3;
+
+        /// <summary>
+        /// Internal representation of unknown state.
+        /// </summary>
+        private const int TT_UNKNOWN = -4;
+
+        /// <summary>
+        /// After calling {@code nextToken()}, {@code ttype} contains the type of
+        /// token that has been read. When a single character is read, its value
+        /// converted to an integer is stored in {@code ttype}. For a quoted string,
+        /// the value is the quoted character. Otherwise, its value is one of the
+        /// following:
+        /// <list type="bullet">
+        ///     <item><description><see cref="TT_WORD"/> - the token is a word.</description></item>
+        ///     <item><description><see cref="TT_NUMBER"/> - the token is a number.</description></item>
+        ///     <item><description><see cref="TT_EOL"/> - the end of line has been reached. Depends on
+        ///     whether <see cref="IsEOLSignificant"/> is <c>true</c>.</description></item>
+        ///     <item><description><see cref="TT_EOF"/> - the end of the stream has been reached.</description></item>
+        /// </list>
+        /// </summary>
+        public int TokenType { get; private set; } = TT_UNKNOWN;
+
+        /// <summary>
+        /// Internal character meanings, 0 implies TOKEN_ORDINARY
+        /// </summary>
+        private byte[] tokenTypes = new byte[256];
+
+        private static readonly byte TOKEN_COMMENT = 1;
+        private static readonly byte TOKEN_QUOTE = 2;
+        private static readonly byte TOKEN_WHITE = 4;
+        private static readonly byte TOKEN_WORD = 8;
+        private static readonly byte TOKEN_DIGIT = 16;
+
+        private int lineNumber = 1;
+        private bool forceLowercase;
+        private bool isEOLSignificant;
+        private bool slashStarComments;
+        private bool slashSlashComments;
+        private bool pushBackToken;
+        private bool lastCr;
+
+        /// <summary>One of these will have the stream</summary>
+        private Stream inStream;
+        private TextReader inReader;
+        private int peekChar = -2;
+
+        /// <summary>
+        /// Private constructor to initialize the default values according to the
+        /// specification.
+        /// </summary>
+        private StreamTokenizer()
+        {
+            /*
+             * Initialize the default state per specification. All byte values 'A'
+             * through 'Z', 'a' through 'z', and '\u00A0' through '\u00FF' are
+             * considered to be alphabetic.
+             */
+            WordChars('A', 'Z');
+            WordChars('a', 'z');
+            WordChars(160, 255);
+            /**
+             * All byte values '\u0000' through '\u0020' are considered to be white
+             * space.
+             */
+            WhitespaceChars(0, 32);
+            /**
+             * '/' is a comment character. Single quote '\'' and double quote '"'
+             * are string quote characters.
+             */
+            CommentChar('/');
+            QuoteChar('"');
+            QuoteChar('\'');
+            /**
+             * Numbers are parsed.
+             */
+            ParseNumbers();
+            /**
+             * Ends of lines are treated as white space, not as separate tokens.
+             * C-style and C++-style comments are not recognized. These are the
+             * defaults and are not needed in constructor.
+             */
+        }
+
+        /// <summary>
+        /// Constructs a new <see cref="StreamTokenizer"/> with <paramref name="input"/> as source input
+        /// stream. This constructor is deprecated; instead, the constructor that
+        /// takes a <see cref="TextReader"/> as an arugment should be used.
+        /// </summary>
+        /// <param name="input">the source stream from which to parse tokens.</param>
+        /// <exception cref="ArgumentNullException">If <paramref name="input"/> is <c>null</c>.</exception>
+        [Obsolete("Use StreamTokenizer(TextReader)")]
+        public StreamTokenizer(Stream input)
+            : this() // Calls private constructor
+        {
+            if (input == null)
+            {
+                throw new ArgumentNullException("input");
+            }
+            inStream = input;
+        }
+
+        /// <summary>
+        /// Constructs a new {@code StreamTokenizer} with {@code r} as source reader.
+        /// The tokenizer's initial state is as follows:
+        /// <list type="bullet">
+        ///     <item><description>All byte values 'A' through 'Z', 'a' through 'z', and '&#92;u00A0' through '&#92;u00FF' are considered to be alphabetic.</description></item>
+        ///     <item><description>All byte values '&#92;u0000' through '&#92;u0020' are considered to be white space. '/' is a comment character.</description></item>
+        ///     <item><description>Single quote '\'' and double quote '"' are string quote characters.</description></item>
+        ///     <item><description>Numbers are parsed.</description></item>
+        ///     <item><description>End of lines are considered to be white space rather than separate tokens.</description></item>
+        ///     <item><description>C-style and C++-style comments are not recognized.</description></item>
+        /// </list>
+        /// </summary>
+        /// <param name="reader">The source text reader from which to parse tokens.</param>
+        public StreamTokenizer(TextReader reader)
+            : this() // Calls private constructor
+        {
+            if (reader == null)
+            {
+                throw new ArgumentNullException("reader");
+            }
+            inReader = reader;
+        }
+
+        /// <summary>
+        /// Specifies that the character <paramref name="ch"/> shall be treated as a comment
+        /// character.
+        /// </summary>
+        /// <param name="ch">The character to be considered a comment character.</param>
+        public virtual void CommentChar(int ch)
+        {
+            if (0 <= ch && ch < tokenTypes.Length)
+            {
+                tokenTypes[ch] = TOKEN_COMMENT;
+            }
+        }
+
+        /// <summary>
+        /// Specifies whether the end of a line is significant and should be returned
+        /// as <see cref="TT_EOF"/> in <see cref="TokenType"/> by this tokenizer.
+        /// <c>true</c> if EOL is significant, <c>false</c> otherwise.
+        /// </summary>
+        public virtual bool IsEOLSignificant
+        {
+            get { return isEOLSignificant; }
+            set { isEOLSignificant = value; }
+        }
+
+        /// <summary>
+        /// Gets the current line number.
+        /// </summary>
+        public int LineNumber
+        {
+            get { return lineNumber; }
+        }
+
+        /// <summary>
+        /// Specifies whether word tokens should be converted to lower case when they
+        /// are stored in <see cref="StringValue"/>. <c>true</c> if <see cref="StringValue"/>
+        /// should be converted to lower case, <c>false</c> otherwise.
+        /// </summary>
+        public bool LowerCaseMode
+        {
+            get { return forceLowercase; }
+            set { forceLowercase = value; }
+        }
+
+        /// <summary>
+        /// Parses the next token from this tokenizer's source stream or reader. The
+        /// type of the token is stored in the <see cref="TokenType"/> field, additional
+        /// information may be stored in the <see cref="NumberValue"/> or <see cref="StringValue"/> fields.
+        /// </summary>
+        /// <returns>The value of <see cref="TokenType"/>.</returns>
+        /// <exception cref="IOException">If an I/O error occurs while parsing the next token.</exception>
+        public int NextToken()
+        {
+            if (pushBackToken)
+            {
+                pushBackToken = false;
+                if (TokenType != TT_UNKNOWN)
+                {
+                    return TokenType;
+                }
+            }
+            StringValue = null; // Always reset sval to null
+            int currentChar = peekChar == -2 ? Read() : peekChar;
+
+            if (lastCr && currentChar == '\n')
+            {
+                lastCr = false;
+                currentChar = Read();
+            }
+            if (currentChar == -1)
+            {
+                return (TokenType = TT_EOF);
+            }
+
+            byte currentType = currentChar > 255 ? TOKEN_WORD
+                    : tokenTypes[currentChar];
+            while ((currentType & TOKEN_WHITE) != 0)
+            {
+                /**
+                 * Skip over white space until we hit a new line or a real token
+                 */
+                if (currentChar == '\r')
+                {
+                    lineNumber++;
+                    if (isEOLSignificant)
+                    {
+                        lastCr = true;
+                        peekChar = -2;
+                        return (TokenType = TT_EOL);
+                    }
+                    if ((currentChar = Read()) == '\n')
+                    {
+                        currentChar = Read();
+                    }
+                }
+                else if (currentChar == '\n')
+                {
+                    lineNumber++;
+                    if (isEOLSignificant)
+                    {
+                        peekChar = -2;
+                        return (TokenType = TT_EOL);
+                    }
+                    currentChar = Read();
+                }
+                else
+                {
+                    // Advance over this white space character and try again.
+                    currentChar = Read();
+                }
+                if (currentChar == -1)
+                {
+                    return (TokenType = TT_EOF);
+                }
+                currentType = currentChar > 255 ? TOKEN_WORD
+                        : tokenTypes[currentChar];
+            }
+
+            /**
+             * Check for digits before checking for words since digits can be
+             * contained within words.
+             */
+            if ((currentType & TOKEN_DIGIT) != 0)
+            {
+                StringBuilder digits = new StringBuilder(20);
+                bool haveDecimal = false, checkJustNegative = currentChar == '-';
+                while (true)
+                {
+                    if (currentChar == '.')
+                    {
+                        haveDecimal = true;
+                    }
+                    digits.Append((char)currentChar);
+                    currentChar = Read();
+                    if ((currentChar < '0' || currentChar > '9')
+                            && (haveDecimal || currentChar != '.'))
+                    {
+                        break;
+                    }
+                }
+                peekChar = currentChar;
+                if (checkJustNegative && digits.Length == 1)
+                {
+                    // Didn't get any other digits other than '-'
+                    return (TokenType = '-');
+                }
+                try
+                {
+                    NumberValue = double.Parse(digits.ToString(), CultureInfo.InvariantCulture);
+                }
+#pragma warning disable 168
+                catch (FormatException e)
+#pragma warning disable 168
+                {
+                    // Unsure what to do, will write test.
+                    NumberValue = 0;
+                }
+                return (TokenType = TT_NUMBER);
+            }
+            // Check for words
+            if ((currentType & TOKEN_WORD) != 0)
+            {
+                StringBuilder word = new StringBuilder(20);
+                while (true)
+                {
+                    word.Append((char)currentChar);
+                    currentChar = Read();
+                    if (currentChar == -1
+                            || (currentChar < 256 && (tokenTypes[currentChar] & (TOKEN_WORD | TOKEN_DIGIT)) == 0))
+                    {
+                        break;
+                    }
+                }
+                peekChar = currentChar;
+                StringValue = forceLowercase ? word.ToString().ToLowerInvariant() : word
+                       .ToString();
+                return (TokenType = TT_WORD);
+            }
+            // Check for quoted character
+            if (currentType == TOKEN_QUOTE)
+            {
+                int matchQuote = currentChar;
+                StringBuilder quoteString = new StringBuilder();
+                int peekOne = Read();
+                while (peekOne >= 0 && peekOne != matchQuote && peekOne != '\r'
+                        && peekOne != '\n')
+                {
+                    bool readPeek = true;
+                    if (peekOne == '\\')
+                    {
+                        int c1 = Read();
+                        // Check for quoted octal IE: \377
+                        if (c1 <= '7' && c1 >= '0')
+                        {
+                            int digitValue = c1 - '0';
+                            c1 = Read();
+                            if (c1 > '7' || c1 < '0')
+                            {
+                                readPeek = false;
+                            }
+                            else
+                            {
+                                digitValue = digitValue * 8 + (c1 - '0');
+                                c1 = Read();
+                                // limit the digit value to a byte
+                                if (digitValue > 037 || c1 > '7' || c1 < '0')
+                                {
+                                    readPeek = false;
+                                }
+                                else
+                                {
+                                    digitValue = digitValue * 8 + (c1 - '0');
+                                }
+                            }
+                            if (!readPeek)
+                            {
+                                // We've consumed one to many
+                                quoteString.Append((char)digitValue);
+                                peekOne = c1;
+                            }
+                            else
+                            {
+                                peekOne = digitValue;
+                            }
+                        }
+                        else
+                        {
+                            switch (c1)
+                            {
+                                case 'a':
+                                    peekOne = 0x7;
+                                    break;
+                                case 'b':
+                                    peekOne = 0x8;
+                                    break;
+                                case 'f':
+                                    peekOne = 0xc;
+                                    break;
+                                case 'n':
+                                    peekOne = 0xA;
+                                    break;
+                                case 'r':
+                                    peekOne = 0xD;
+                                    break;
+                                case 't':
+                                    peekOne = 0x9;
+                                    break;
+                                case 'v':
+                                    peekOne = 0xB;
+                                    break;
+                                default:
+                                    peekOne = c1;
+                                    break;
+                            }
+                        }
+                    }
+                    if (readPeek)
+                    {
+                        quoteString.Append((char)peekOne);
+                        peekOne = Read();
+                    }
+                }
+                if (peekOne == matchQuote)
+                {
+                    peekOne = Read();
+                }
+                peekChar = peekOne;
+                TokenType = matchQuote;
+                StringValue = quoteString.ToString();
+                return TokenType;
+            }
+            // Do comments, both "//" and "/*stuff*/"
+            if (currentChar == '/' && (slashSlashComments || slashStarComments))
+            {
+                if ((currentChar = Read()) == '*' && slashStarComments)
+                {
+                    int peekOne = Read();
+                    while (true)
+                    {
+                        currentChar = peekOne;
+                        peekOne = Read();
+                        if (currentChar == -1)
+                        {
+                            peekChar = -1;
+                            return (TokenType = TT_EOF);
+                        }
+                        if (currentChar == '\r')
+                        {
+                            if (peekOne == '\n')
+                            {
+                                peekOne = Read();
+                            }
+                            lineNumber++;
+                        }
+                        else if (currentChar == '\n')
+                        {
+                            lineNumber++;
+                        }
+                        else if (currentChar == '*' && peekOne == '/')
+                        {
+                            peekChar = Read();
+                            return NextToken();
+                        }
+                    }
+                }
+                else if (currentChar == '/' && slashSlashComments)
+                {
+                    // Skip to EOF or new line then return the next token
+                    while ((currentChar = Read()) >= 0 && currentChar != '\r'
+                            && currentChar != '\n')
+                    {
+                        // Intentionally empty
+                    }
+                    peekChar = currentChar;
+                    return NextToken();
+                }
+                else if (currentType != TOKEN_COMMENT)
+                {
+                    // Was just a slash by itself
+                    peekChar = currentChar;
+                    return (TokenType = '/');
+                }
+            }
+            // Check for comment character
+            if (currentType == TOKEN_COMMENT)
+            {
+                // Skip to EOF or new line then return the next token
+                while ((currentChar = Read()) >= 0 && currentChar != '\r'
+                        && currentChar != '\n')
+                {
+                    // Intentionally empty
+                }
+                peekChar = currentChar;
+                return NextToken();
+            }
+
+            peekChar = Read();
+            return (TokenType = currentChar);
+        }
+
+        /// <summary>
+        /// Specifies that the character <paramref name="ch"/> shall be treated as an ordinary
+        /// character by this tokenizer. That is, it has no special meaning as a
+        /// comment character, word component, white space, string delimiter or
+        /// number.
+        /// </summary>
+        /// <param name="ch">The character to be considered an ordinary character.</param>
+        public void OrdinaryChar(int ch)
+        {
+            if (0 <= ch && ch < tokenTypes.Length)
+            {
+                tokenTypes[ch] = 0;
+            }
+        }
+
+        /// <summary>
+        /// Specifies that the characters in the range from <paramref name="low"/> to <paramref name="hi"/>
+        /// shall be treated as an ordinary character by this tokenizer. That is,
+        /// they have no special meaning as a comment character, word component,
+        /// white space, string delimiter or number.
+        /// </summary>
+        /// <param name="low">The first character in the range of ordinary characters.</param>
+        /// <param name="hi">The last character in the range of ordinary characters.</param>
+        public void OrdinaryChars(int low, int hi)
+        {
+            if (low < 0)
+            {
+                low = 0;
+            }
+            if (hi > tokenTypes.Length)
+            {
+                hi = tokenTypes.Length - 1;
+            }
+            for (int i = low; i <= hi; i++)
+            {
+                tokenTypes[i] = 0;
+            }
+        }
+
+        /// <summary>
+        /// Specifies that this tokenizer shall parse numbers.
+        /// </summary>
+        public void ParseNumbers()
+        {
+            for (int i = '0'; i <= '9'; i++)
+            {
+                tokenTypes[i] |= TOKEN_DIGIT;
+            }
+            tokenTypes['.'] |= TOKEN_DIGIT;
+            tokenTypes['-'] |= TOKEN_DIGIT;
+        }
+
+        /// <summary>
+        /// Indicates that the current token should be pushed back and returned again
+        /// the next time <see cref="NextToken()"/> is called.
+        /// </summary>
+        public void PushBack()
+        {
+            pushBackToken = true;
+        }
+
+        /// <summary>
+        /// Specifies that the character <paramref name="ch"/> shall be treated as a quote
+        /// character.
+        /// </summary>
+        /// <param name="ch">The character to be considered a quote character.</param>
+        public void QuoteChar(int ch)
+        {
+            if (0 <= ch && ch < tokenTypes.Length)
+            {
+                tokenTypes[ch] = TOKEN_QUOTE;
+            }
+        }
+
+        private int Read()
+        {
+            // Call the read for the appropriate stream
+            if (inStream == null)
+            {
+                return inReader.Read();
+            }
+            return inStream.ReadByte();
+        }
+
+        /// <summary>
+        /// Specifies that all characters shall be treated as ordinary characters.
+        /// </summary>
+        public void ResetSyntax()
+        {
+            for (int i = 0; i < 256; i++)
+            {
+                tokenTypes[i] = 0;
+            }
+        }
+
+        /// <summary>
+        /// Specifies whether "slash-slash" (C++-style) comments shall be recognized.
+        /// This kind of comment ends at the end of the line.
+        /// <c>true</c> if <c>//</c> should be recognized as the start
+        /// of a comment, <c>false</c> otherwise.
+        /// </summary>
+        public bool SlashSlashComments
+        {
+            get { return slashSlashComments; }
+            set { slashSlashComments = value; }
+        }
+
+        /// <summary>
+        /// Specifies whether "slash-star" (C-style) comments shall be recognized.
+        /// Slash-star comments cannot be nested and end when a star-slash
+        /// combination is found.
+        /// <c>true</c> if <c>/*</c> should be recognized as the start
+        /// of a comment, <c>false</c> otherwise.
+        /// </summary>
+        public bool SlashStarComments
+        {
+            get { return slashStarComments; }
+            set { slashStarComments = value; }
+        }
+
+        /// <summary>
+        /// Returns the state of this tokenizer in a readable format.
+        /// </summary>
+        /// <returns>The current state of this tokenizer.</returns>
+        public override string ToString()
+        {
+            // Values determined through experimentation
+            StringBuilder result = new StringBuilder();
+            result.Append("Token["); //$NON-NLS-1$
+            switch (TokenType)
+            {
+                case TT_EOF:
+                    result.Append("EOF"); //$NON-NLS-1$
+                    break;
+                case TT_EOL:
+                    result.Append("EOL"); //$NON-NLS-1$
+                    break;
+                case TT_NUMBER:
+                    result.Append("n="); //$NON-NLS-1$
+                    result.Append(NumberValue);
+                    break;
+                case TT_WORD:
+                    result.Append(StringValue);
+                    break;
+                default:
+                    if (TokenType == TT_UNKNOWN || tokenTypes[TokenType] == TOKEN_QUOTE)
+                    {
+                        result.Append(StringValue);
+                    }
+                    else
+                    {
+                        result.Append('\'');
+                        result.Append((char)TokenType);
+                        result.Append('\'');
+                    }
+                    break;
+            }
+            result.Append("], line "); //$NON-NLS-1$
+            result.Append(lineNumber);
+            return result.ToString();
+        }
+
+        /// <summary>
+        /// Specifies that the characters in the range from <paramref name="low"/> to <paramref name="hi"/>
+        /// shall be treated as whitespace characters by this tokenizer.
+        /// </summary>
+        /// <param name="low">The first character in the range of whitespace characters.</param>
+        /// <param name="hi">The last character in the range of whitespace characters.</param>
+        public void WhitespaceChars(int low, int hi)
+        {
+            if (low < 0)
+            {
+                low = 0;
+            }
+            if (hi > tokenTypes.Length)
+            {
+                hi = tokenTypes.Length - 1;
+            }
+            for (int i = low; i <= hi; i++)
+            {
+                tokenTypes[i] = TOKEN_WHITE;
+            }
+        }
+
+        /// <summary>
+        /// Specifies that the characters in the range from <paramref name="low"/> to <paramref name="hi"/>
+        /// shall be treated as word characters by this tokenizer. A word consists of
+        /// a word character followed by zero or more word or number characters.
+        /// </summary>
+        /// <param name="low">The first character in the range of word characters.</param>
+        /// <param name="hi">The last character in the range of word characters.</param>
+        public void WordChars(int low, int hi)
+        {
+            if (low < 0)
+            {
+                low = 0;
+            }
+            if (hi > tokenTypes.Length)
+            {
+                hi = tokenTypes.Length - 1;
+            }
+            for (int i = low; i <= hi; i++)
+            {
+                tokenTypes[i] |= TOKEN_WORD;
+            }
+        }
+    }
+}


[09/12] lucenenet git commit: Lucene.Net.Support.StringBuilderExtensions: Added IndexOf() extension methods and tests from Apache Harmony

Posted by ni...@apache.org.
Lucene.Net.Support.StringBuilderExtensions: Added IndexOf() extension methods and tests from Apache Harmony


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

Branch: refs/heads/master
Commit: 1b8621b787d3150af86ea64ef7a62c1ad8c6b575
Parents: 6b56e2b
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 13:27:40 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:54:09 2017 +0700

----------------------------------------------------------------------
 .../Support/TestStringBuilderExtensions.cs      | 292 ++++++++++++++++++-
 .../Support/StringBuilderExtensions.cs          |  47 +++
 2 files changed, 338 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1b8621b7/src/Lucene.Net.Tests/Support/TestStringBuilderExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/TestStringBuilderExtensions.cs b/src/Lucene.Net.Tests/Support/TestStringBuilderExtensions.cs
index 7debed1..82911cc 100644
--- a/src/Lucene.Net.Tests/Support/TestStringBuilderExtensions.cs
+++ b/src/Lucene.Net.Tests/Support/TestStringBuilderExtensions.cs
@@ -20,6 +20,7 @@
 */
 
 using Lucene.Net.Attributes;
+using Lucene.Net.Util;
 using NUnit.Framework;
 using System;
 using System.Text;
@@ -27,7 +28,7 @@ using System.Text;
 namespace Lucene.Net.Support
 {
     [TestFixture]
-    public class TestStringBuilderExtensions
+    public class TestStringBuilderExtensions : LuceneTestCase
     {
         [Test, LuceneNetSpecific]
         public virtual void TestReverse()
@@ -89,5 +90,294 @@ namespace Lucene.Net.Support
 
             Assert.Throws<ArgumentException>(() => sb.AppendCodePoint(codePoint));
         }
+
+        #region Apache Harmony Tests
+
+        private void reverseTest(String org, String rev, String back)
+        {
+            // create non-shared StringBuilder
+            StringBuilder sb = new StringBuilder(org);
+            sb.Reverse();
+            String reversed = sb.toString();
+            assertEquals(rev, reversed);
+            // create non-shared StringBuilder
+            sb = new StringBuilder(reversed);
+            sb.Reverse();
+            reversed = sb.toString();
+            assertEquals(back, reversed);
+
+            // test algorithm when StringBuilder is shared
+            sb = new StringBuilder(org);
+            String copy = sb.toString();
+            assertEquals(org, copy);
+            sb.Reverse();
+            reversed = sb.toString();
+            assertEquals(rev, reversed);
+            sb = new StringBuilder(reversed);
+            copy = sb.toString();
+            assertEquals(rev, copy);
+            sb.Reverse();
+            reversed = sb.toString();
+            assertEquals(back, reversed);
+        }
+
+        /**
+         * @tests java.lang.StringBuilder.reverse()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_Reverse()
+        {
+            String fixture = "0123456789";
+            StringBuilder sb = new StringBuilder(fixture);
+            assertSame(sb, sb.Reverse());
+            assertEquals("9876543210", sb.toString());
+
+            sb = new StringBuilder("012345678");
+            assertSame(sb, sb.Reverse());
+            assertEquals("876543210", sb.toString());
+
+            sb.Length=(1);
+            assertSame(sb, sb.Reverse());
+            assertEquals("8", sb.toString());
+
+            sb.Length=(0);
+            assertSame(sb, sb.Reverse());
+            assertEquals("", sb.toString());
+
+            String str;
+            str = "a";
+            reverseTest(str, str, str);
+
+            str = "ab";
+            reverseTest(str, "ba", str);
+
+            str = "abcdef";
+            reverseTest(str, "fedcba", str);
+
+            str = "abcdefg";
+            reverseTest(str, "gfedcba", str);
+
+            str = "\ud800\udc00";
+            reverseTest(str, str, str);
+
+            str = "\udc00\ud800";
+            reverseTest(str, "\ud800\udc00", "\ud800\udc00");
+
+            str = "a\ud800\udc00";
+            reverseTest(str, "\ud800\udc00a", str);
+
+            str = "ab\ud800\udc00";
+            reverseTest(str, "\ud800\udc00ba", str);
+
+            str = "abc\ud800\udc00";
+            reverseTest(str, "\ud800\udc00cba", str);
+
+            str = "\ud800\udc00\udc01\ud801\ud802\udc02";
+            reverseTest(str, "\ud802\udc02\ud801\udc01\ud800\udc00",
+                    "\ud800\udc00\ud801\udc01\ud802\udc02");
+
+            str = "\ud800\udc00\ud801\udc01\ud802\udc02";
+            reverseTest(str, "\ud802\udc02\ud801\udc01\ud800\udc00", str);
+
+            str = "\ud800\udc00\udc01\ud801a";
+            reverseTest(str, "a\ud801\udc01\ud800\udc00",
+                    "\ud800\udc00\ud801\udc01a");
+
+            str = "a\ud800\udc00\ud801\udc01";
+            reverseTest(str, "\ud801\udc01\ud800\udc00a", str);
+
+            str = "\ud800\udc00\udc01\ud801ab";
+            reverseTest(str, "ba\ud801\udc01\ud800\udc00",
+                    "\ud800\udc00\ud801\udc01ab");
+
+            str = "ab\ud800\udc00\ud801\udc01";
+            reverseTest(str, "\ud801\udc01\ud800\udc00ba", str);
+
+            str = "\ud800\udc00\ud801\udc01";
+            reverseTest(str, "\ud801\udc01\ud800\udc00", str);
+
+            str = "a\ud800\udc00z\ud801\udc01";
+            reverseTest(str, "\ud801\udc01z\ud800\udc00a", str);
+
+            str = "a\ud800\udc00bz\ud801\udc01";
+            reverseTest(str, "\ud801\udc01zb\ud800\udc00a", str);
+
+            str = "abc\ud802\udc02\ud801\udc01\ud800\udc00";
+            reverseTest(str, "\ud800\udc00\ud801\udc01\ud802\udc02cba", str);
+
+            str = "abcd\ud802\udc02\ud801\udc01\ud800\udc00";
+            reverseTest(str, "\ud800\udc00\ud801\udc01\ud802\udc02dcba", str);
+        }
+
+        /**
+         * @tests java.lang.StringBuilder.codePointCount(int, int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_CodePointCountII()
+        {
+            assertEquals(1, new StringBuilder("\uD800\uDC00").CodePointCount(0, 2));
+            assertEquals(1, new StringBuilder("\uD800\uDC01").CodePointCount(0, 2));
+            assertEquals(1, new StringBuilder("\uD801\uDC01").CodePointCount(0, 2));
+            assertEquals(1, new StringBuilder("\uDBFF\uDFFF").CodePointCount(0, 2));
+
+            assertEquals(3, new StringBuilder("a\uD800\uDC00b").CodePointCount(0, 4));
+            assertEquals(4, new StringBuilder("a\uD800\uDC00b\uD800").CodePointCount(0, 5));
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("abc");
+            try
+            {
+                sb.CodePointCount(-1, 2);
+                fail("No IOOBE for negative begin index.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+
+            try
+            {
+                sb.CodePointCount(0, 4);
+                fail("No IOOBE for end index that's too large.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+
+            try
+            {
+                sb.CodePointCount(3, 2);
+                fail("No IOOBE for begin index larger than end index.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+        }
+
+        /**
+	     * @tests java.lang.StringBuilder.codePointAt(int)
+	     */
+        [Test, LuceneNetSpecific]
+        public void Test_CodePointAtI()
+        {
+            StringBuilder sb = new StringBuilder("abc");
+            assertEquals('a', sb.CodePointAt(0));
+            assertEquals('b', sb.CodePointAt(1));
+            assertEquals('c', sb.CodePointAt(2));
+
+            sb = new StringBuilder("\uD800\uDC00");
+            assertEquals(0x10000, sb.CodePointAt(0));
+            assertEquals('\uDC00', sb.CodePointAt(1));
+
+            sb = new StringBuilder();
+            sb.append("abc");
+            try
+            {
+                sb.CodePointAt(-1);
+                fail("No IOOBE on negative index.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+
+            try
+            {
+                sb.CodePointAt(sb.Length);
+                fail("No IOOBE on index equal to length.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+
+            try
+            {
+                sb.CodePointAt(sb.Length + 1);
+                fail("No IOOBE on index greater than length.");
+            }
+#pragma warning disable 168
+            catch (IndexOutOfRangeException e)
+#pragma warning restore 168
+            {
+
+            }
+        }
+
+        /**
+         * @tests java.lang.StringBuilder.indexOf(String)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_IndexOfLSystem_String()
+        {
+            String fixture = "0123456789";
+            StringBuilder sb = new StringBuilder(fixture);
+            assertEquals(0, sb.IndexOf("0"));
+            assertEquals(0, sb.IndexOf("012"));
+            assertEquals(-1, sb.IndexOf("02"));
+            assertEquals(8, sb.IndexOf("89"));
+
+            try
+            {
+                sb.IndexOf(null);
+                fail("no NPE");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        /**
+         * @tests java.lang.StringBuilder.indexOf(String, int)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_IndexOfStringInt()
+        {
+            String fixture = "0123456789";
+            StringBuilder sb = new StringBuilder(fixture);
+            assertEquals(0, sb.IndexOf("0"));
+            assertEquals(0, sb.IndexOf("012"));
+            assertEquals(-1, sb.IndexOf("02"));
+            assertEquals(8, sb.IndexOf("89"));
+
+            assertEquals(0, sb.IndexOf("0"), 0);
+            assertEquals(0, sb.IndexOf("012"), 0);
+            assertEquals(-1, sb.IndexOf("02"), 0);
+            assertEquals(8, sb.IndexOf("89"), 0);
+
+            assertEquals(-1, sb.IndexOf("0"), 5);
+            assertEquals(-1, sb.IndexOf("012"), 5);
+            assertEquals(-1, sb.IndexOf("02"), 0);
+            assertEquals(8, sb.IndexOf("89"), 5);
+
+            try
+            {
+                sb.IndexOf(null, 0);
+                fail("no NPE");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        #endregion Apache Harmony Tests
     }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1b8621b7/src/Lucene.Net/Support/StringBuilderExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/StringBuilderExtensions.cs b/src/Lucene.Net/Support/StringBuilderExtensions.cs
index ae68811..6b02511 100644
--- a/src/Lucene.Net/Support/StringBuilderExtensions.cs
+++ b/src/Lucene.Net/Support/StringBuilderExtensions.cs
@@ -169,5 +169,52 @@ namespace Lucene.Net.Support
             text.Append(Character.ToChars(codePoint));
             return text;
         }
+
+        /// <summary>
+        /// Searches for the first index of the specified character. The search for
+        /// the character starts at the beginning and moves towards the end.
+        /// </summary>
+        /// <param name="text">This <see cref="StringBuilder"/>.</param>
+        /// <param name="value">The string to find.</param>
+        /// <returns>The index of the specified character, or -1 if the character isn't found.</returns>
+        public static int IndexOf(this StringBuilder text, string value)
+        {
+            return IndexOf(text, value, 0);
+        }
+
+        /// <summary>
+        /// Searches for the index of the specified character. The search for the
+        /// character starts at the specified offset and moves towards the end.
+        /// </summary>
+        /// <param name="text">This <see cref="StringBuilder"/>.</param>
+        /// <param name="value">The string to find.</param>
+        /// <param name="startIndex">The starting offset.</param>
+        /// <returns>The index of the specified character, or -1 if the character isn't found.</returns>
+        public static int IndexOf(this StringBuilder text, string value, int startIndex)
+        {
+            if (text == null)
+                throw new ArgumentNullException("text");
+            if (value == null)
+                throw new ArgumentNullException("value");
+
+            int index;
+            int length = value.Length;
+            int maxSearchLength = (text.Length - length) + 1;
+
+            for (int i = startIndex; i < maxSearchLength; ++i)
+            {
+                if (text[i] == value[0])
+                {
+                    index = 1;
+                    while ((index < length) && (text[i + index] == value[index]))
+                        ++index;
+
+                    if (index == length)
+                        return i;
+                }
+            }
+
+            return -1;
+        }
     }
 }
\ No newline at end of file


[03/12] lucenenet git commit: Moved SystemProperties from Lucene.Net.TestFramework to Lucene.Net so the defaulting and security exception handling can be used globally

Posted by ni...@apache.org.
Moved SystemProperties from Lucene.Net.TestFramework to Lucene.Net so the defaulting and security exception handling can be used globally


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

Branch: refs/heads/master
Commit: 1a4c3b81daca3e766229d25f85d95132371ccf9f
Parents: 6c6a17b
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 06:46:54 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Mon Jul 31 06:46:54 2017 +0700

----------------------------------------------------------------------
 .../Lucene.Net.TestFramework.csproj             |   6 +-
 .../Support/SystemProperties.cs                 | 173 ------------------
 src/Lucene.Net/Lucene.Net.csproj                |   1 +
 src/Lucene.Net/Support/SystemProperties.cs      | 175 +++++++++++++++++++
 4 files changed, 178 insertions(+), 177 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1a4c3b81/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj b/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
index 533a4ec..ae3c34b 100644
--- a/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
+++ b/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 
  Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,6 @@
  under the License.
 
 -->
-
 <Project ToolsVersion="12.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>
@@ -449,7 +448,6 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Support\ExceptionSerializationTestBase.cs" />
-    <Compile Include="Support\SystemProperties.cs" />
     <Compile Include="Support\ApiScanTestBase.cs" />
     <Compile Include="Util\Automaton\AutomatonTestUtil.cs">
       <SubType>Code</SubType>
@@ -530,4 +528,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1a4c3b81/src/Lucene.Net.TestFramework/Support/SystemProperties.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/Support/SystemProperties.cs b/src/Lucene.Net.TestFramework/Support/SystemProperties.cs
deleted file mode 100644
index fa6fe45..0000000
--- a/src/Lucene.Net.TestFramework/Support/SystemProperties.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *
- * 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 System;
-using System.Security;
-
-namespace Lucene.Net.Support
-{
-    /// <summary>
-    /// Helper for environment variables. This class helps to convert the environment
-    /// variables to int or bool data types and also silently handles read permission
-    /// errors.
-    /// <para/>
-    /// For instructions how to set environment variables for your OS, see 
-    /// <a href="https://www.schrodinger.com/kb/1842">https://www.schrodinger.com/kb/1842</a>.
-    /// <para/>
-    /// Note that if you want to load any of these settings for your application from a
-    /// configuration file, it is recommended your application load them at startup and
-    /// call <see cref="SystemProperties.SetProperty(string, string)"/> to set them.
-    /// <para/>
-    /// Set the environment variable <c>lucene.ignoreSecurityExceptions</c> to <c>false</c>
-    /// to change the read behavior of these methods to throw the underlying exception 
-    /// instead of returning the default value.
-    /// </summary>
-    public static class SystemProperties
-    {
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <returns>The environment variable value.</returns>
-        public static string GetProperty(string key)
-        {
-            return GetProperty(key, null);
-        }
-
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process, 
-        /// with a default value if it doens't exist or the caller doesn't have 
-        /// permission to read the value.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <param name="defaultValue">The value to use if the environment variable does not exist 
-        /// or the caller doesn't have permission to read the value.</param>
-        /// <returns>The environment variable value.</returns>
-        public static string GetProperty(string key, string defaultValue)
-        {
-            return GetProperty<string>(key, defaultValue,
-                (str) =>
-                {
-                    return str;
-                }
-            );
-        }
-
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process
-        /// as <see cref="bool"/>. If the value cannot be cast to <see cref="bool"/>, returns <c>false</c>.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <returns>The environment variable value.</returns>
-        public static bool GetPropertyAsBoolean(string key)
-        {
-            return GetPropertyAsBoolean(key, false);
-        }
-
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process as <see cref="bool"/>, 
-        /// with a default value if it doens't exist, the caller doesn't have permission to read the value, 
-        /// or the value cannot be cast to a <see cref="bool"/>.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <param name="defaultValue">The value to use if the environment variable does not exist,
-        /// the caller doesn't have permission to read the value, or the value cannot be cast to <see cref="bool"/>.</param>
-        /// <returns>The environment variable value.</returns>
-        public static bool GetPropertyAsBoolean(string key, bool defaultValue)
-        {
-            return GetProperty<bool>(key, defaultValue,
-                (str) =>
-                {
-                    bool value;
-                    return bool.TryParse(str, out value) ? value : defaultValue;
-                }
-            );
-        }
-
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process
-        /// as <see cref="int"/>. If the value cannot be cast to <see cref="int"/>, returns <c>0</c>.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <returns>The environment variable value.</returns>
-        public static int GetPropertyAsInt32(string key)
-        {
-            return GetPropertyAsInt32(key, 0);
-        }
-
-        /// <summary>
-        /// Retrieves the value of an environment variable from the current process as <see cref="int"/>, 
-        /// with a default value if it doens't exist, the caller doesn't have permission to read the value, 
-        /// or the value cannot be cast to a <see cref="int"/>.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <param name="defaultValue">The value to use if the environment variable does not exist,
-        /// the caller doesn't have permission to read the value, or the value cannot be cast to <see cref="int"/>.</param>
-        /// <returns>The environment variable value.</returns>
-        public static int GetPropertyAsInt32(string key, int defaultValue)
-        {
-            return GetProperty<int>(key, defaultValue,
-                (str) =>
-                {
-                    int value;
-                    return int.TryParse(str, out value) ? value : defaultValue;
-                }
-            );
-        }
-
-        private static T GetProperty<T>(string key, T defaultValue, Func<string, T> conversionFunction)
-        {
-            string setting;
-            if (ignoreSecurityExceptions)
-            {
-                try
-                {
-                    setting = Environment.GetEnvironmentVariable(key);
-                }
-                catch (SecurityException)
-                {
-                    setting = null;
-                }
-            }
-            else
-            {
-                setting = Environment.GetEnvironmentVariable(key);
-            }
-
-            return string.IsNullOrEmpty(setting)
-                ? defaultValue
-                : conversionFunction(setting);
-        }
-
-        private static bool ignoreSecurityExceptions = GetPropertyAsBoolean("lucene.ignoreSecurityExceptions", false);
-
-        /// <summary>
-        /// Creates, modifies, or deletes an environment variable stored in the current process.
-        /// </summary>
-        /// <param name="key">The name of the environment variable.</param>
-        /// <param name="value">The new environment variable value.</param>
-        /// <exception cref="SecurityException">The caller does not have the required permission to perform this operation.</exception>
-        public static void SetProperty(string key, string value)
-        {
-            Environment.SetEnvironmentVariable(key, value);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1a4c3b81/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Lucene.Net.csproj b/src/Lucene.Net/Lucene.Net.csproj
index e29c82a..8f8fc4b 100644
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@ -656,6 +656,7 @@
     <Compile Include="Support\RectangularArrays.cs" />
     <Compile Include="Support\Search\ReferenceContext.cs" />
     <Compile Include="Support\Search\ReferenceManagerExtensions.cs" />
+    <Compile Include="Support\SystemProperties.cs" />
     <Compile Include="Support\Threading\ICompletionService.cs" />
     <Compile Include="Support\IO\IDataInput.cs" />
     <Compile Include="Support\IO\IDataOutput.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1a4c3b81/src/Lucene.Net/Support/SystemProperties.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/SystemProperties.cs b/src/Lucene.Net/Support/SystemProperties.cs
new file mode 100644
index 0000000..7661eaa
--- /dev/null
+++ b/src/Lucene.Net/Support/SystemProperties.cs
@@ -0,0 +1,175 @@
+// LUCENENET TODO: API: Replace all references to Environment.GetEnvironmentVariable() with this (safer) class.
+
+/*
+ *
+ * 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 System;
+using System.Security;
+
+namespace Lucene.Net.Support
+{
+    /// <summary>
+    /// Helper for environment variables. This class helps to convert the environment
+    /// variables to int or bool data types and also silently handles read permission
+    /// errors.
+    /// <para/>
+    /// For instructions how to set environment variables for your OS, see 
+    /// <a href="https://www.schrodinger.com/kb/1842">https://www.schrodinger.com/kb/1842</a>.
+    /// <para/>
+    /// Note that if you want to load any of these settings for your application from a
+    /// configuration file, it is recommended your application load them at startup and
+    /// call <see cref="SystemProperties.SetProperty(string, string)"/> to set them.
+    /// <para/>
+    /// Set the environment variable <c>lucene.ignoreSecurityExceptions</c> to <c>false</c>
+    /// to change the read behavior of these methods to throw the underlying exception 
+    /// instead of returning the default value.
+    /// </summary>
+    public static class SystemProperties
+    {
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <returns>The environment variable value.</returns>
+        public static string GetProperty(string key)
+        {
+            return GetProperty(key, null);
+        }
+
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process, 
+        /// with a default value if it doens't exist or the caller doesn't have 
+        /// permission to read the value.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <param name="defaultValue">The value to use if the environment variable does not exist 
+        /// or the caller doesn't have permission to read the value.</param>
+        /// <returns>The environment variable value.</returns>
+        public static string GetProperty(string key, string defaultValue)
+        {
+            return GetProperty<string>(key, defaultValue,
+                (str) =>
+                {
+                    return str;
+                }
+            );
+        }
+
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process
+        /// as <see cref="bool"/>. If the value cannot be cast to <see cref="bool"/>, returns <c>false</c>.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <returns>The environment variable value.</returns>
+        public static bool GetPropertyAsBoolean(string key)
+        {
+            return GetPropertyAsBoolean(key, false);
+        }
+
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process as <see cref="bool"/>, 
+        /// with a default value if it doens't exist, the caller doesn't have permission to read the value, 
+        /// or the value cannot be cast to a <see cref="bool"/>.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <param name="defaultValue">The value to use if the environment variable does not exist,
+        /// the caller doesn't have permission to read the value, or the value cannot be cast to <see cref="bool"/>.</param>
+        /// <returns>The environment variable value.</returns>
+        public static bool GetPropertyAsBoolean(string key, bool defaultValue)
+        {
+            return GetProperty<bool>(key, defaultValue,
+                (str) =>
+                {
+                    bool value;
+                    return bool.TryParse(str, out value) ? value : defaultValue;
+                }
+            );
+        }
+
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process
+        /// as <see cref="int"/>. If the value cannot be cast to <see cref="int"/>, returns <c>0</c>.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <returns>The environment variable value.</returns>
+        public static int GetPropertyAsInt32(string key)
+        {
+            return GetPropertyAsInt32(key, 0);
+        }
+
+        /// <summary>
+        /// Retrieves the value of an environment variable from the current process as <see cref="int"/>, 
+        /// with a default value if it doens't exist, the caller doesn't have permission to read the value, 
+        /// or the value cannot be cast to a <see cref="int"/>.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <param name="defaultValue">The value to use if the environment variable does not exist,
+        /// the caller doesn't have permission to read the value, or the value cannot be cast to <see cref="int"/>.</param>
+        /// <returns>The environment variable value.</returns>
+        public static int GetPropertyAsInt32(string key, int defaultValue)
+        {
+            return GetProperty<int>(key, defaultValue,
+                (str) =>
+                {
+                    int value;
+                    return int.TryParse(str, out value) ? value : defaultValue;
+                }
+            );
+        }
+
+        private static T GetProperty<T>(string key, T defaultValue, Func<string, T> conversionFunction)
+        {
+            string setting;
+            if (ignoreSecurityExceptions)
+            {
+                try
+                {
+                    setting = Environment.GetEnvironmentVariable(key);
+                }
+                catch (SecurityException)
+                {
+                    setting = null;
+                }
+            }
+            else
+            {
+                setting = Environment.GetEnvironmentVariable(key);
+            }
+
+            return string.IsNullOrEmpty(setting)
+                ? defaultValue
+                : conversionFunction(setting);
+        }
+
+        internal static bool ignoreSecurityExceptions = GetPropertyAsBoolean("lucene.ignoreSecurityExceptions", true);
+
+        /// <summary>
+        /// Creates, modifies, or deletes an environment variable stored in the current process.
+        /// </summary>
+        /// <param name="key">The name of the environment variable.</param>
+        /// <param name="value">The new environment variable value.</param>
+        /// <exception cref="SecurityException">The caller does not have the required permission to perform this operation.</exception>
+        public static void SetProperty(string key, string value)
+        {
+            Environment.SetEnvironmentVariable(key, value);
+        }
+    }
+}


[11/12] lucenenet git commit: Lucene.Net.Util.SPIClassIterator: Factored out code to get all non-Microsoft referenced assemblies into a new class in Support named AssemblyUtils

Posted by ni...@apache.org.
Lucene.Net.Util.SPIClassIterator: Factored out code to get all non-Microsoft referenced assemblies into a new class in Support named AssemblyUtils


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

Branch: refs/heads/master
Commit: 1e5229375d35371b732e3f1b8f105d6a6a345d0c
Parents: a11ca03
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 13:51:17 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:54:25 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Lucene.Net.csproj        |   1 +
 src/Lucene.Net/Support/AssemblyUtils.cs | 138 +++++++++++++++++++++++++++
 src/Lucene.Net/Util/SPIClassIterator.cs | 115 +---------------------
 3 files changed, 140 insertions(+), 114 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e522937/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Lucene.Net.csproj b/src/Lucene.Net/Lucene.Net.csproj
index 211a013..368597a 100644
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@ -394,6 +394,7 @@
     <Compile Include="Index\TwoStoredFieldsConsumers.cs" />
     <Compile Include="Index\UpgradeIndexMergePolicy.cs" />
     <Compile Include="LucenePackage.cs" />
+    <Compile Include="Support\AssemblyUtils.cs" />
     <Compile Include="Support\Document\DocumentExtensions.cs" />
     <Compile Include="Support\IO\Compression\LZOCompressor.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e522937/src/Lucene.Net/Support/AssemblyUtils.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/AssemblyUtils.cs b/src/Lucene.Net/Support/AssemblyUtils.cs
new file mode 100644
index 0000000..48c7439
--- /dev/null
+++ b/src/Lucene.Net/Support/AssemblyUtils.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+#if NETSTANDARD
+using Microsoft.Extensions.DependencyModel;
+#endif
+
+namespace Lucene.Net.Support
+{
+    /// <summary>
+    /// Methods for working with Assemblies.
+    /// </summary>
+    public class AssemblyUtils
+    {
+        /// <summary>
+        /// Gets a list of the host assembly's referenced assemblies excluding 
+        /// any Microsoft, System, or Mono prefixed assemblies or assemblies with
+        /// official Microsoft key hashes. Essentially, we get a list of all non
+        /// Microsoft assemblies here.
+        /// </summary>
+        /// <returns></returns>
+        public static IList<Assembly> GetReferencedAssemblies()
+        {
+            // .NET Port Hack: We do a 2-level deep check here because if the assembly you're
+            // hoping would be loaded hasn't been loaded yet into the app domain,
+            // it is unavailable. So we go to the next level on each and check each referenced
+            // assembly.
+#if NETSTANDARD
+            var dependencyContext = DependencyContext.Default;
+            var assemblyNames = dependencyContext.RuntimeLibraries
+                .SelectMany(lib => lib.GetDefaultAssemblyNames(dependencyContext))
+                .Where(x => !DotNetFrameworkFilter.IsFrameworkAssembly(x))
+                .Distinct();
+            var assembliesLoaded = LoadAssemblyFromName(assemblyNames);
+#else
+            var assembliesLoaded = AppDomain.CurrentDomain.GetAssemblies();
+#endif
+            assembliesLoaded = assembliesLoaded.Where(x => !DotNetFrameworkFilter.IsFrameworkAssembly(x)).ToArray();
+
+            var referencedAssemblies = assembliesLoaded
+                .SelectMany(assembly =>
+                {
+                    return assembly
+                        .GetReferencedAssemblies()
+                        .Where(reference => !DotNetFrameworkFilter.IsFrameworkAssembly(reference))
+                        .Select(assemblyName => LoadAssemblyFromName(assemblyName));
+                })
+                .Where(x => x != null)
+                .Distinct();
+
+            return assembliesLoaded.Concat(referencedAssemblies).Distinct().ToList();
+        }
+
+        private static IEnumerable<Assembly> LoadAssemblyFromName(IEnumerable<AssemblyName> assemblyNames)
+        {
+            return assemblyNames.Select(x => LoadAssemblyFromName(x)).Where(x => x != null);
+        }
+
+        private static Assembly LoadAssemblyFromName(AssemblyName assemblyName)
+        {
+            try
+            {
+                return Assembly.Load(assemblyName);
+            }
+            catch
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Assembly filter logic from:
+        /// https://raw.githubusercontent.com/Microsoft/dotnet-apiport/master/src/Microsoft.Fx.Portability/Analyzer/DotNetFrameworkFilter.cs
+        /// </summary>
+        public static class DotNetFrameworkFilter
+        {
+            /// <summary>
+            /// These keys are a collection of public key tokens derived from all the reference assemblies in
+            /// "%ProgramFiles%\Reference Assemblies\Microsoft" on a Windows 10 machine with VS 2015 installed
+            /// </summary>
+            private static readonly ICollection<string> s_microsoftKeys = new HashSet<string>(new[]
+            {
+                "b77a5c561934e089", // ECMA
+                "b03f5f7f11d50a3a", // DEVDIV
+                "7cec85d7bea7798e", // SLPLAT
+                "31bf3856ad364e35", // Windows
+                "24eec0d8c86cda1e", // Phone
+                "0738eb9f132ed756", // Mono
+                "ddd0da4d3e678217", // Component model
+                "84e04ff9cfb79065", // Mono Android
+                "842cf8be1de50553"  // Xamarin.iOS
+            }, StringComparer.OrdinalIgnoreCase);
+
+            private static readonly IEnumerable<string> s_frameworkAssemblyNamePrefixes = new[]
+            {
+                "System.",
+                "Microsoft.",
+                "Mono."
+            };
+
+            /// <summary>
+            /// Gets a best guess as to whether this assembly is a .NET Framework assembly or not.
+            /// </summary>
+            public static bool IsFrameworkAssembly(Assembly assembly)
+            {
+                return assembly != null && IsFrameworkAssembly(assembly.GetName());
+            }
+
+            /// <summary>
+            /// Gets a best guess as to whether this assembly is a .NET Framework assembly or not.
+            /// </summary>
+            public static bool IsFrameworkAssembly(AssemblyName assembly)
+            {
+                if (assembly == null)
+                {
+                    return false;
+                }
+
+                if (s_frameworkAssemblyNamePrefixes.Any(p => assembly.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
+                {
+                    return true;
+                }
+
+                var publicKey = assembly.GetPublicKeyToken();
+
+                if (publicKey == default(byte[]))
+                {
+                    return false;
+                }
+
+                var publicKeyToken = string.Concat(publicKey.Select(i => i.ToString("x2")));
+
+                return s_microsoftKeys.Contains(publicKeyToken);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e522937/src/Lucene.Net/Util/SPIClassIterator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Util/SPIClassIterator.cs b/src/Lucene.Net/Util/SPIClassIterator.cs
index 8a75309..f3c08f0 100644
--- a/src/Lucene.Net/Util/SPIClassIterator.cs
+++ b/src/Lucene.Net/Util/SPIClassIterator.cs
@@ -2,9 +2,6 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-#if NETSTANDARD
-using Microsoft.Extensions.DependencyModel;
-#endif
 
 namespace Lucene.Net.Util
 {
@@ -41,34 +38,7 @@ namespace Lucene.Net.Util
         {
             types = new HashSet<Type>();
 
-            // .NET Port Hack: We do a 2-level deep check here because if the assembly you're
-            // hoping would be loaded hasn't been loaded yet into the app domain,
-            // it is unavailable. So we go to the next level on each and check each referenced
-            // assembly.
-#if NETSTANDARD
-            var dependencyContext = DependencyContext.Default;
-            var assemblyNames = dependencyContext.RuntimeLibraries
-                .SelectMany(lib => lib.GetDefaultAssemblyNames(dependencyContext))
-                .Where(x => !DotNetFrameworkFilter.IsFrameworkAssembly(x))
-                .Distinct();
-            var assembliesLoaded = LoadAssemblyFromName(assemblyNames);
-#else
-            var assembliesLoaded = AppDomain.CurrentDomain.GetAssemblies();
-#endif
-            assembliesLoaded = assembliesLoaded.Where(x => !DotNetFrameworkFilter.IsFrameworkAssembly(x)).ToArray();
-
-            var referencedAssemblies = assembliesLoaded
-                .SelectMany(assembly =>
-                {
-                    return assembly
-                        .GetReferencedAssemblies()
-                        .Where(reference => !DotNetFrameworkFilter.IsFrameworkAssembly(reference))
-                        .Select(assemblyName => LoadAssemblyFromName(assemblyName));
-                })
-                .Where(x => x != null)
-                .Distinct();
-
-            var assembliesToExamine = assembliesLoaded.Concat(referencedAssemblies).Distinct().ToList();
+            var assembliesToExamine = Support.AssemblyUtils.GetReferencedAssemblies();
 
             // LUCENENET HACK:
             // Tests such as TestImpersonation.cs expect that the assemblies
@@ -154,89 +124,6 @@ namespace Lucene.Net.Util
         {
             return GetEnumerator();
         }
-
-        private static IEnumerable<Assembly> LoadAssemblyFromName(IEnumerable<AssemblyName> assemblyNames)
-        {
-            return assemblyNames.Select(x => LoadAssemblyFromName(x)).Where(x => x != null);
-        }
-
-        private static Assembly LoadAssemblyFromName(AssemblyName assemblyName)
-        {
-            try
-            {
-                return Assembly.Load(assemblyName);
-            }
-            catch
-            {
-                return null;
-            }
-        }
-
-        /// <summary>
-        /// Assembly filter logic from:
-        /// https://raw.githubusercontent.com/Microsoft/dotnet-apiport/master/src/Microsoft.Fx.Portability/Analyzer/DotNetFrameworkFilter.cs
-        /// </summary>
-        private static class DotNetFrameworkFilter
-        {
-            /// <summary>
-            /// These keys are a collection of public key tokens derived from all the reference assemblies in
-            /// "%ProgramFiles%\Reference Assemblies\Microsoft" on a Windows 10 machine with VS 2015 installed
-            /// </summary>
-            private static readonly ICollection<string> s_microsoftKeys = new HashSet<string>(new[]
-            {
-                "b77a5c561934e089", // ECMA
-                "b03f5f7f11d50a3a", // DEVDIV
-                "7cec85d7bea7798e", // SLPLAT
-                "31bf3856ad364e35", // Windows
-                "24eec0d8c86cda1e", // Phone
-                "0738eb9f132ed756", // Mono
-                "ddd0da4d3e678217", // Component model
-                "84e04ff9cfb79065", // Mono Android
-                "842cf8be1de50553"  // Xamarin.iOS
-            }, StringComparer.OrdinalIgnoreCase);
-
-            private static readonly IEnumerable<string> s_frameworkAssemblyNamePrefixes = new[]
-            {
-                "System.",
-                "Microsoft.",
-                "Mono."
-            };
-
-            /// <summary>
-            /// Gets a best guess as to whether this assembly is a .NET Framework assembly or not.
-            /// </summary>
-            public static bool IsFrameworkAssembly(Assembly assembly)
-            {
-                return assembly != null && IsFrameworkAssembly(assembly.GetName());
-            }
-
-            /// <summary>
-            /// Gets a best guess as to whether this assembly is a .NET Framework assembly or not.
-            /// </summary>
-            public static bool IsFrameworkAssembly(AssemblyName assembly)
-            {
-                if (assembly == null)
-                {
-                    return false;
-                }
-
-                if (s_frameworkAssemblyNamePrefixes.Any(p => assembly.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
-                {
-                    return true;
-                }
-
-                var publicKey = assembly.GetPublicKeyToken();
-
-                if (publicKey == default(byte[]))
-                {
-                    return false;
-                }
-
-                var publicKeyToken = string.Concat(publicKey.Select(i => i.ToString("x2")));
-
-                return s_microsoftKeys.Contains(publicKeyToken);
-            }
-        }
     }
 
     /* Being Re-written


[08/12] lucenenet git commit: Lucene.Net.Support.StringExtensions: Added a TrimEnd() method that can be used on string arrays. This is to mimic Java's Split() method that removes only the null or empty elements from the end of the array that is returned,

Posted by ni...@apache.org.
Lucene.Net.Support.StringExtensions: Added a TrimEnd() method that can be used on string arrays. This is to mimic Java's Split() method that removes only the null or empty elements from the end of the array that is returned, but leaves any prior empty elements intact.


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

Branch: refs/heads/master
Commit: 6b56e2bd2448ffa201cb413e812defe9fbadc2b6
Parents: 51a6c52
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 12:48:17 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:53:59 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Support/StringExtensions.cs | 30 +++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6b56e2bd/src/Lucene.Net/Support/StringExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/StringExtensions.cs b/src/Lucene.Net/Support/StringExtensions.cs
index 3828a72..b8e4bbd 100644
--- a/src/Lucene.Net/Support/StringExtensions.cs
+++ b/src/Lucene.Net/Support/StringExtensions.cs
@@ -1,5 +1,6 @@
 using Lucene.Net.Util;
 using System;
+using System.Collections.Generic;
 using System.Text;
 
 namespace Lucene.Net.Support
@@ -136,5 +137,34 @@ namespace Lucene.Net.Support
             // codePoint is negative or not found in string
             return -1;
         }
+
+        // LUCENENET TODO: BUG Replace all calls to .Split("", StringSplitOptions.RemoveEmptyEntries)
+        // and Regex.Split("") with .Split("").TrimEnd() and Regex.Split("").TrimEnd() to match the 
+        // behavior of Java's Split() method.
+
+        /// <summary>
+        /// Removes null or empty elements from the end of a string array.
+        /// </summary>
+        /// <param name="input">This string array.</param>
+        /// <returns>The array with any null or empty elements removed from the end.</returns>
+        public static string[] TrimEnd(this string[] input)
+        {
+            if (input == null)
+                return null;
+            int lastElement;
+            for (lastElement = input.Length - 1; lastElement >= 0; lastElement--)
+            {
+                if (!string.IsNullOrEmpty(input[lastElement]))
+                    break;
+            }
+            if (lastElement > 0 && lastElement < input.Length)
+            {
+                int end = lastElement + 1;
+                string[] result = new string[end];
+                Array.Copy(input, result, end);
+                return result;
+            }
+            return input;
+        }
     }
 }
\ No newline at end of file


[12/12] lucenenet git commit: Corrected bug in Lifetime reference count

Posted by ni...@apache.org.
Corrected bug in Lifetime reference count


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

Branch: refs/heads/master
Commit: ea879c611912b15b27991d86bfa3548d8e71ae34
Parents: 1e52293
Author: Vincent Van Den Berghe <vv...@bvdep.com>
Authored: Sun Jul 30 18:40:47 2017 +0200
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 11:03:19 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Search/SearcherLifetimeManager.cs | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/ea879c61/src/Lucene.Net/Search/SearcherLifetimeManager.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Search/SearcherLifetimeManager.cs b/src/Lucene.Net/Search/SearcherLifetimeManager.cs
index 8b7b3d4..7c51a58 100644
--- a/src/Lucene.Net/Search/SearcherLifetimeManager.cs
+++ b/src/Lucene.Net/Search/SearcherLifetimeManager.cs
@@ -145,7 +145,7 @@ namespace Lucene.Net.Search
         // TODO: we could get by w/ just a "set"; need to have
         // Tracker hash by its version and have compareTo(Long)
         // compare to its version
-        private readonly ConcurrentDictionary<long, SearcherTracker> _searchers = new ConcurrentDictionary<long, SearcherTracker>();
+        private readonly ConcurrentDictionary<long, Lazy<SearcherTracker>> _searchers = new ConcurrentDictionary<long, Lazy<SearcherTracker>>();
 
         private void EnsureOpen()
         {
@@ -177,7 +177,7 @@ namespace Lucene.Net.Search
             // bug isolation if we assign our own private ID:
             var version = ((DirectoryReader)searcher.IndexReader).Version;
             var factoryMethodCalled = false;
-            var tracker = _searchers.GetOrAdd(version, l => { factoryMethodCalled = true; return new SearcherTracker(searcher); });
+				var tracker = _searchers.GetOrAdd(version, l => new Lazy<SearcherTracker>(() => { factoryMethodCalled = true; return new SearcherTracker(searcher); })).Value;
             if (!factoryMethodCalled && tracker.Searcher != searcher)
             {
                 throw new ArgumentException("the provided searcher has the same underlying reader version yet the searcher instance differs from before (new=" + searcher + " vs old=" + tracker.Searcher);
@@ -203,10 +203,10 @@ namespace Lucene.Net.Search
         public virtual IndexSearcher Acquire(long version)
         {
             EnsureOpen();
-            SearcherTracker tracker;
-            if (_searchers.TryGetValue(version, out tracker) && tracker != null && tracker.Searcher.IndexReader.TryIncRef())
+            Lazy<SearcherTracker> tracker;
+            if (_searchers.TryGetValue(version, out tracker) && tracker.IsValueCreated && tracker.Value.Searcher.IndexReader.TryIncRef())
             {
-                return tracker.Searcher;
+                return tracker.Value.Searcher;
             }
 
             return null;
@@ -279,7 +279,7 @@ namespace Lucene.Net.Search
                 // (not thread-safe since the values can change while
                 // ArrayList is init'ing itself); must instead iterate
                 // ourselves:
-                var trackers = _searchers.Values.ToList();
+                var trackers = _searchers.Values.Select(item => item.Value).ToList();
                 trackers.Sort();
                 var lastRecordTimeSec = 0.0;
                 double now = Time.NanoTime() / NANOS_PER_SEC;
@@ -301,7 +301,7 @@ namespace Lucene.Net.Search
                     if (pruner.DoPrune(ageSec, tracker.Searcher))
                     {
                         //System.out.println("PRUNE version=" + tracker.version + " age=" + ageSec + " ms=" + System.currentTimeMillis());
-                        SearcherTracker _;
+                        Lazy<SearcherTracker> _;
                         _searchers.TryRemove(tracker.Version, out _);
                         tracker.Dispose();
                     }
@@ -326,13 +326,13 @@ namespace Lucene.Net.Search
             lock (this)
             {
                 _closed = true;
-                IList<SearcherTracker> toClose = new List<SearcherTracker>(_searchers.Values);
+                IList<SearcherTracker> toClose = new List<SearcherTracker>(_searchers.Values.Select(item => item.Value));
 
                 // Remove up front in case exc below, so we don't
                 // over-decRef on double-close:
                 foreach (var tracker in toClose)
                 {
-                    SearcherTracker _;
+                    Lazy<SearcherTracker> _;
                     _searchers.TryRemove(tracker.Version, out _);
                 }
 


[05/12] lucenenet git commit: Lucene.Net.Support.DictionaryExtensions: Added Load and Store methods from Apache Harmony, so an IDictionary can be used the same way the Properties class is used in Java (saving and loading the same format).

Posted by ni...@apache.org.
Lucene.Net.Support.DictionaryExtensions: Added Load and Store methods from Apache Harmony, so an IDictionary<string, string> can be used the same way the Properties class is used in Java (saving and loading the same format).


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

Branch: refs/heads/master
Commit: cd2d3514e3fcda42ec1168667e91657f64aac5f6
Parents: dc67a55
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 06:55:19 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:53:09 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   2 +
 .../Support/TestDictionaryExtensions.cs         | 411 +++++++++++++++++++
 .../Support/hyts_PropertiesTest.properties      |  29 ++
 src/Lucene.Net/Support/DictionaryExtensions.cs  | 409 +++++++++++++++++-
 4 files changed, 850 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/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 7631329..13282e1 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -118,6 +118,7 @@
     <None Include="Lucene.Net.snk" />
     <None Include="Lucene.Net.Tests.project.json" />
     <EmbeddedResource Include="Store\LUCENENET521.zip" />
+    <EmbeddedResource Include="Support\hyts_PropertiesTest.properties" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Analysis.Common\Lucene.Net.Analysis.Common.csproj">
@@ -522,6 +523,7 @@
     <Compile Include="Support\IO\TestReadOnlyHeapByteBuffer.cs" />
     <Compile Include="Support\IO\TestStreamTokenizer.cs" />
     <Compile Include="Support\SmallObject.cs" />
+    <Compile Include="Support\TestDictionaryExtensions.cs" />
     <Compile Include="Support\TestPriorityQueue.cs" />
     <Compile Include="Support\Threading\TestCloseableThreadLocal.cs" />
     <Compile Include="Support\TestCollections.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs b/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
new file mode 100644
index 0000000..540d964
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
@@ -0,0 +1,411 @@
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.Tests.Support
+{
+    public class TestDictionaryExtensions : LuceneTestCase
+    {
+        [Test]
+        public void Test_loadLSystem_IO_Stream_ArgumentNullException()
+        {
+            Dictionary<string, string> p = new Dictionary<string, string>();
+            try
+            {
+                p.Load((Stream)null);
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        /**
+     * @tests java.util.Properties#load(java.io.InputStream)
+     */
+        [Test]
+        public void Test_loadLSystem_IO_Stream()
+        {
+            Dictionary<string, string> prop = new Dictionary<string, string>();
+            using (Stream @is = new MemoryStream(writeProperties()))
+            {
+                prop.Load(@is);
+            }
+            assertEquals("Failed to load correct properties", "harmony.tests", prop.get("test.pkg"));
+            assertNull("Load failed to parse incorrectly", prop
+                    .get("commented.entry"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=".getBytes()));
+            assertEquals("Failed to add empty key", "", prop.get(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" = ".getBytes()));
+            assertEquals("Failed to add empty key2", "", prop.get(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" a= b".getBytes()));
+            assertEquals("Failed to ignore whitespace", "b", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" a b".getBytes()));
+            assertEquals("Failed to interpret whitespace as =", "b", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("#comment\na=value"
+                    .getBytes("UTF-8")));
+            assertEquals("value", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("#\u008d\u00d2\na=\u008d\u00d3"
+                    .getBytes("ISO-8859-1")));
+            assertEquals("Failed to parse chars >= 0x80", "\u008d\u00d3", prop
+                    .get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(
+                    "#properties file\r\nfred=1\r\n#last comment"
+                            .getBytes("ISO-8859-1")));
+            assertEquals("Failed to load when last line contains a comment", "1",
+                    prop.get("fred"));
+
+            // Regression tests for HARMONY-5414
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("a=\\u1234z".getBytes()));
+
+            prop = new Dictionary<string, string>();
+            try
+            {
+                prop.Load(new MemoryStream("a=\\u123".getBytes()));
+                fail("should throw IllegalArgumentException");
+            }
+#pragma warning disable 168
+            catch (ArgumentException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+
+            prop = new Dictionary<string, string>();
+            try
+            {
+                prop.Load(new MemoryStream("a=\\u123z".getBytes()));
+                fail("should throw IllegalArgumentException");
+            }
+            catch (ArgumentException /*expected*/)
+            {
+                // Expected
+            }
+
+            prop = new Dictionary<string, string>();
+            Dictionary<string, string> expected = new Dictionary<string, string>();
+            expected.Put("a", "\u0000");
+            prop.Load(new MemoryStream("a=\\".getBytes()));
+            assertEquals("Failed to read trailing slash value", expected, prop);
+
+            prop = new Dictionary<string, string>();
+            expected = new Dictionary<string, string>();
+            expected.Put("a", "\u1234\u0000");
+            prop.Load(new MemoryStream("a=\\u1234\\".getBytes()));
+            assertEquals("Failed to read trailing slash value #2", expected, prop);
+
+            prop = new Dictionary<string, string>();
+            expected = new Dictionary<string, string>();
+            expected.Put("a", "q");
+            prop.Load(new MemoryStream("a=\\q".getBytes()));
+            assertEquals("Failed to read slash value #3", expected, prop);
+        }
+
+        /**
+         * @tests java.util.Properties#load(java.io.InputStream)
+         */
+        [Test]
+        public void Test_loadLSystem_IO_Stream_Special()
+        {
+            // Test for method void java.util.Properties.load(java.io.InputStream)
+            Dictionary<string, string> prop = null;
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=\r\n".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=\n\r".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+        }
+
+        /**
+         * @tests java.util.Properties#load(java.io.InputStream)
+         */
+        [Test]
+        public void Test_loadLSystem_IO_Stream_subtest0()
+        {
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            using (Stream input = GetType().getResourceAsStream("hyts_PropertiesTest.properties"))
+                props.Load(input);
+
+            assertEquals("1", "\n \t \f", props.getProperty(" \r"));
+            assertEquals("2", "a", props.getProperty("a"));
+            assertEquals("3", "bb as,dn   ", props.getProperty("b"));
+            assertEquals("4", ":: cu", props.getProperty("c\r \t\nu"));
+            assertEquals("5", "bu", props.getProperty("bu"));
+            assertEquals("6", "d\r\ne=e", props.getProperty("d"));
+            assertEquals("7", "fff", props.getProperty("f"));
+            assertEquals("8", "g", props.getProperty("g"));
+            assertEquals("9", "", props.getProperty("h h"));
+            assertEquals("10", "i=i", props.getProperty(" "));
+            assertEquals("11", "   j", props.getProperty("j"));
+            assertEquals("12", "   c", props.getProperty("space"));
+            assertEquals("13", "\\", props.getProperty("dblbackslash"));
+        }
+
+        /**
+     * @tests java.util.Properties#store(java.io.OutputStream, java.lang.String)
+     */
+        [Test]
+        public void Test_storeLSystem_IO_StreamLSystem_String()
+        {
+            Dictionary<string, string> myProps = new Dictionary<string, string>();
+            myProps.Put("Property A", " aye\\\f\t\n\r\b");
+            myProps.Put("Property B", "b ee#!=:");
+            myProps.Put("Property C", "see");
+
+            MemoryStream @out = new MemoryStream();
+            myProps.Store(@out, "A Header");
+            @out.Dispose();
+
+            MemoryStream @in = new MemoryStream(@out.ToArray());
+            Dictionary<string, string> myProps2 = new Dictionary<string, string>();
+            myProps2.Load(@in);
+            @in.Dispose();
+
+            using (var e = myProps.Keys.GetEnumerator())
+            {
+                String nextKey;
+                while (e.MoveNext())
+                {
+                    nextKey = e.Current;
+                    assertTrue("Stored property list not equal to original", myProps2
+                        .getProperty(nextKey).equals(myProps.getProperty(nextKey)));
+                }
+            }
+        }
+
+        /**
+        * if loading from single line like "hello" without "\n\r" neither "=", it
+        * should be same as loading from "hello="
+        */
+        [Test]
+        public void TestLoadSingleLine()
+        {
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            Stream sr = new MemoryStream("hello".getBytes());
+            props.Load(sr);
+            assertEquals(1, props.size());
+        }
+
+        private String comment1 = "comment1";
+
+        private String comment2 = "comment2";
+
+        private void validateOutput(String[] expectStrings, byte[] output)
+        {
+            MemoryStream bais = new MemoryStream(output);
+            TextReader br = new StreamReader(bais,
+                    Encoding.GetEncoding("ISO-8859-1"));
+            foreach (String expectString in expectStrings)
+            {
+                assertEquals(expectString, br.ReadLine());
+            }
+            br.ReadLine();
+            assertNull(br.ReadLine());
+            br.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario0()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario1()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario2()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario3()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario4()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario5()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario6()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario7()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario8()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario9()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario10()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario11()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+
+
+        protected byte[] writeProperties()
+        {
+            MemoryStream bout = new MemoryStream();
+            TextWriter ps = new StreamWriter(bout);
+            ps.WriteLine("#commented.entry=Bogus");
+            ps.WriteLine("test.pkg=harmony.tests");
+            ps.WriteLine("test.proj=Automated Tests");
+            ps.Dispose();
+            return bout.ToArray();
+        }
+
+    }
+
+    public static class Extensions
+    {
+        public static byte[] getBytes(this string input)
+        {
+            return Encoding.UTF8.GetBytes(input);
+        }
+
+        public static byte[] getBytes(this string input, string encoding)
+        {
+            return Encoding.GetEncoding(encoding).GetBytes(input);
+        }
+
+        public static string get(this IDictionary<string, string> dict, string key)
+        {
+            string result;
+            dict.TryGetValue(key, out result);
+            return result;
+        }
+
+        public static string getProperty(this IDictionary<string, string> dict, string key)
+        {
+            string result;
+            dict.TryGetValue(key, out result);
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties b/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
new file mode 100644
index 0000000..6c1b950
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
@@ -0,0 +1,29 @@
+
+
+    
+    		
+   \ \r \n \t \f
+   
+            					
+! dshfjklahfjkldashgjl;as
+     #jdfagdfjagkdjfghksdajfd
+     
+!!properties
+
+a=a
+b bb as,dn   
+c\r\ \t\nu =:: cu
+bu= b\
+		u
+d=d\r\ne=e
+f   :f\
+f\
+			f
+g		g
+h\u0020h
+\   i=i
+j=\   j
+space=\   c
+
+dblbackslash=\\
+                        
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net/Support/DictionaryExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/DictionaryExtensions.cs b/src/Lucene.Net/Support/DictionaryExtensions.cs
index 18acd6a..0f616cb 100644
--- a/src/Lucene.Net/Support/DictionaryExtensions.cs
+++ b/src/Lucene.Net/Support/DictionaryExtensions.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
 
 namespace Lucene.Net.Support
 {
@@ -50,5 +53,409 @@ namespace Lucene.Net.Support
             dict[key] = value;
             return oldValue;
         }
+
+        private static readonly int NONE = 0, SLASH = 1, UNICODE = 2, CONTINUE = 3,
+            KEY_DONE = 4, IGNORE = 5;
+        private static string lineSeparator = Environment.NewLine;
+
+
+        // LUCENENET NOTE: Sourced from Apache Harmony:
+
+        /// <summary>
+        /// Loads properties from the specified <see cref="Stream"/>. The encoding is
+        /// ISO8859-1. 
+        /// </summary>
+        /// <remarks>
+        /// The Properties file is interpreted according to the
+        /// following rules:
+        /// <list type="bullet">
+        ///     <item><description>
+        ///         Empty lines are ignored.
+        ///     </description></item>
+        ///     <item><description>
+        ///         Lines starting with either a "#" or a "!" are comment lines and are
+        ///         ignored.
+        ///     </description></item>
+        ///     <item><description>
+        ///         A backslash at the end of the line escapes the following newline
+        ///         character ("\r", "\n", "\r\n"). If there's a whitespace after the
+        ///         backslash it will just escape that whitespace instead of concatenating
+        ///         the lines. This does not apply to comment lines.
+        ///     </description></item>
+        ///     <item><description>
+        ///         A property line consists of the key, the space between the key and
+        ///         the value, and the value. The key goes up to the first whitespace, "=" or
+        ///         ":" that is not escaped. The space between the key and the value contains
+        ///         either one whitespace, one "=" or one ":" and any number of additional
+        ///         whitespaces before and after that character. The value starts with the
+        ///         first character after the space between the key and the value.
+        ///     </description></item>
+        ///     <item><description>
+        ///         Following escape sequences are recognized: "\ ", "\\", "\r", "\n",
+        ///         "\!", "\#", "\t", "\b", "\f", and "&#92;uXXXX" (unicode character).
+        ///     </description></item>
+        /// </list>
+        /// <para/>
+        /// This method is to mimic and interoperate with the Properties class in Java, which
+        /// is essentially a string dictionary that natively supports importing and exporting to this format.
+        /// </remarks>
+        /// <param name="dict">This dictionary.</param>
+        /// <param name="input">The <see cref="Stream"/>.</param>
+        /// <exception cref="IOException">If error occurs during reading from the <see cref="Stream"/>.</exception>
+        public static void Load(this IDictionary<string, string> dict, Stream input)
+        {
+            if (input == null)
+            {
+                throw new ArgumentNullException("input");
+            }
+            lock (dict)
+            {
+                int mode = NONE, unicode = 0, count = 0;
+                char nextChar;
+                char[] buf = new char[40];
+                int offset = 0, keyLength = -1, intVal;
+                bool firstChar = true;
+                Stream bis = input;
+
+                while (true)
+                {
+                    intVal = bis.ReadByte();
+                    if (intVal == -1)
+                    {
+                        // if mode is UNICODE but has less than 4 hex digits, should
+                        // throw an IllegalArgumentException
+                        // luni.08=Invalid Unicode sequence: expected format \\uxxxx
+                        if (mode == UNICODE && count < 4)
+                        {
+                            throw new ArgumentException("Invalid Unicode sequence: expected format \\uxxxx"); //$NON-NLS-1$
+                        }
+                        // if mode is SLASH and no data is read, should append '\u0000'
+                        // to buf
+                        if (mode == SLASH)
+                        {
+                            buf[offset++] = '\u0000';
+                        }
+                        break;
+                    }
+                    nextChar = (char)(intVal & 0xff);
+
+                    if (offset == buf.Length)
+                    {
+                        char[] newBuf = new char[buf.Length * 2];
+                        System.Array.Copy(buf, 0, newBuf, 0, offset);
+                        buf = newBuf;
+                    }
+                    if (mode == UNICODE)
+                    {
+                        int digit = Character.Digit(nextChar, 16);
+                        if (digit >= 0)
+                        {
+                            unicode = (unicode << 4) + digit;
+                            if (++count < 4)
+                            {
+                                continue;
+                            }
+                        }
+                        else if (count <= 4)
+                        {
+                            // luni.09=Invalid Unicode sequence: illegal character
+                            throw new ArgumentException("Invalid Unicode sequence: illegal character"); //$NON-NLS-1$
+                        }
+                        mode = NONE;
+                        buf[offset++] = (char)unicode;
+                        if (nextChar != '\n')
+                        {
+                            continue;
+                        }
+                    }
+                    if (mode == SLASH)
+                    {
+                        mode = NONE;
+                        switch (nextChar)
+                        {
+                            case '\r':
+                                mode = CONTINUE; // Look for a following \n
+                                continue;
+                            case '\n':
+                                mode = IGNORE; // Ignore whitespace on the next line
+                                continue;
+                            case 'b':
+                                nextChar = '\b';
+                                break;
+                            case 'f':
+                                nextChar = '\f';
+                                break;
+                            case 'n':
+                                nextChar = '\n';
+                                break;
+                            case 'r':
+                                nextChar = '\r';
+                                break;
+                            case 't':
+                                nextChar = '\t';
+                                break;
+                            case 'u':
+                                mode = UNICODE;
+                                unicode = count = 0;
+                                continue;
+                        }
+                    }
+                    else
+                    {
+                        switch (nextChar)
+                        {
+                            case '#':
+                            case '!':
+                                if (firstChar)
+                                {
+                                    while (true)
+                                    {
+                                        intVal = bis.ReadByte();
+                                        if (intVal == -1)
+                                        {
+                                            break;
+                                        }
+                                        // & 0xff not required
+                                        nextChar = (char)intVal;
+                                        if (nextChar == '\r' || nextChar == '\n')
+                                        {
+                                            break;
+                                        }
+                                    }
+                                    continue;
+                                }
+                                break;
+                            case '\n':
+                                if (mode == CONTINUE)
+                                { // Part of a \r\n sequence
+                                    mode = IGNORE; // Ignore whitespace on the next line
+                                    continue;
+                                }
+                                // fall into the next case
+                                mode = NONE;
+                                firstChar = true;
+                                if (offset > 0 || (offset == 0 && keyLength == 0))
+                                {
+                                    if (keyLength == -1)
+                                    {
+                                        keyLength = offset;
+                                    }
+                                    string temp = new string(buf, 0, offset);
+                                    dict.Put(temp.Substring(0, keyLength), temp
+                                            .Substring(keyLength));
+                                }
+                                keyLength = -1;
+                                offset = 0;
+                                continue;
+                            case '\r':
+                                mode = NONE;
+                                firstChar = true;
+                                if (offset > 0 || (offset == 0 && keyLength == 0))
+                                {
+                                    if (keyLength == -1)
+                                    {
+                                        keyLength = offset;
+                                    }
+                                    string temp = new string(buf, 0, offset);
+                                    dict.Put(temp.Substring(0, keyLength), temp
+                                            .Substring(keyLength));
+                                }
+                                keyLength = -1;
+                                offset = 0;
+                                continue;
+                            case '\\':
+                                if (mode == KEY_DONE)
+                                {
+                                    keyLength = offset;
+                                }
+                                mode = SLASH;
+                                continue;
+                            case ':':
+                            case '=':
+                                if (keyLength == -1)
+                                { // if parsing the key
+                                    mode = NONE;
+                                    keyLength = offset;
+                                    continue;
+                                }
+                                break;
+                        }
+                        if (nextChar < 256 && char.IsWhiteSpace(nextChar))
+                        {
+                            if (mode == CONTINUE)
+                            {
+                                mode = IGNORE;
+                            }
+                            // if key length == 0 or value length == 0
+                            if (offset == 0 || offset == keyLength || mode == IGNORE)
+                            {
+                                continue;
+                            }
+                            if (keyLength == -1)
+                            { // if parsing the key
+                                mode = KEY_DONE;
+                                continue;
+                            }
+                        }
+                        if (mode == IGNORE || mode == CONTINUE)
+                        {
+                            mode = NONE;
+                        }
+                    }
+                    firstChar = false;
+                    if (mode == KEY_DONE)
+                    {
+                        keyLength = offset;
+                        mode = NONE;
+                    }
+                    buf[offset++] = nextChar;
+                }
+                if (keyLength == -1 && offset > 0)
+                {
+                    keyLength = offset;
+                }
+                if (keyLength >= 0)
+                {
+                    string temp = new string(buf, 0, offset);
+                    dict.Put(temp.Substring(0, keyLength), temp.Substring(keyLength));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Stores the mappings in this Properties to the specified
+        /// <see cref="Stream"/>, putting the specified comment at the beginning. The
+        /// output from this method is suitable for being read by the
+        /// <see cref="Load(IDictionary{string, string}, Stream)"/> method.
+        /// </summary>
+        /// <param name="dict">This dictionary.</param>
+        /// <param name="output">The output <see cref="Stream"/> to write to.</param>
+        /// <param name="comments">The comments to put at the beginning.</param>
+        /// <exception cref="IOException">If an error occurs during the write to the <see cref="Stream"/>.</exception>
+        /// <exception cref="InvalidCastException">If the key or value of a mapping is not a <see cref="string"/>.</exception>
+        public static void Store(this IDictionary<string, string> dict, Stream output, string comments)
+        {
+            lock (dict)
+            {
+                StreamWriter writer = new StreamWriter(output, Encoding.GetEncoding("iso-8859-1")); //$NON-NLS-1$
+                if (comments != null)
+                {
+                    WriteComments(writer, comments);
+                }
+                writer.Write('#');
+                writer.Write(new DateTime().ToString("yyyy-MM-dd"));
+                writer.Write(lineSeparator);
+
+                StringBuilder buffer = new StringBuilder(200);
+                foreach (var entry in dict)
+                {
+                    string key = entry.Key;
+                    DumpString(buffer, key, true);
+                    buffer.Append('=');
+                    DumpString(buffer, entry.Value, false);
+                    buffer.Append(lineSeparator);
+                    writer.Write(buffer.ToString());
+                    buffer.Length = 0;
+                }
+                writer.Flush();
+            }
+        }
+
+        private static void WriteComments(TextWriter writer, string comments)
+        {
+            writer.Write('#');
+            char[] chars = comments.ToCharArray();
+            for (int index = 0; index < chars.Length; index++)
+            {
+                if (chars[index] == '\r' || chars[index] == '\n')
+                {
+                    int indexPlusOne = index + 1;
+                    if (chars[index] == '\r' && indexPlusOne < chars.Length
+                            && chars[indexPlusOne] == '\n')
+                    {
+                        // "\r\n"
+                        continue;
+                    }
+                    writer.Write(lineSeparator);
+                    if (indexPlusOne < chars.Length
+                            && (chars[indexPlusOne] == '#' || chars[indexPlusOne] == '!'))
+                    {
+                        // return char with either '#' or '!' afterward
+                        continue;
+                    }
+                    writer.Write('#');
+                }
+                else
+                {
+                    writer.Write(chars[index]);
+                }
+            }
+            writer.Write(lineSeparator);
+        }
+
+        private static void DumpString(StringBuilder buffer, string str, bool isKey)
+        {
+            int index = 0, length = str.Length;
+            if (!isKey && index < length && str[index] == ' ')
+            {
+                buffer.Append("\\ "); //$NON-NLS-1$
+                index++;
+            }
+
+            for (; index < length; index++)
+            {
+                char ch = str[index];
+                switch (ch)
+                {
+                    case '\t':
+                        buffer.Append("\\t"); //$NON-NLS-1$
+                        break;
+                    case '\n':
+                        buffer.Append("\\n"); //$NON-NLS-1$
+                        break;
+                    case '\f':
+                        buffer.Append("\\f"); //$NON-NLS-1$
+                        break;
+                    case '\r':
+                        buffer.Append("\\r"); //$NON-NLS-1$
+                        break;
+                    default:
+                        if ("\\#!=:".IndexOf(ch) >= 0 || (isKey && ch == ' '))
+                        {
+                            buffer.Append('\\');
+                        }
+                        if (ch >= ' ' && ch <= '~')
+                        {
+                            buffer.Append(ch);
+                        }
+                        else
+                        {
+                            buffer.Append(ToHexaDecimal(ch));
+                        }
+                        break;
+                }
+            }
+        }
+
+        private static char[] ToHexaDecimal(int ch)
+        {
+            char[] hexChars = { '\\', 'u', '0', '0', '0', '0' };
+            int hexChar, index = hexChars.Length, copyOfCh = ch;
+            do
+            {
+                hexChar = copyOfCh & 15;
+                if (hexChar > 9)
+                {
+                    hexChar = hexChar - 10 + 'A';
+                }
+                else
+                {
+                    hexChar += '0';
+                }
+                hexChars[--index] = (char)hexChar;
+                //} while ((copyOfCh >>>= 4) != 0);
+            } while ((copyOfCh = (int)((uint)copyOfCh >> 4)) != 0);
+            return hexChars;
+        }
     }
 }
\ No newline at end of file


[10/12] lucenenet git commit: Lucene.Net.Support.Time: Added a CurrentTimeMilliseconds() method that is similar, but more accurate than Java's System.currentTimeMillis() method and can safely be used for elapsed timing

Posted by ni...@apache.org.
Lucene.Net.Support.Time: Added a CurrentTimeMilliseconds() method that is similar, but more accurate than Java's System.currentTimeMillis() method and can safely be used for elapsed timing


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

Branch: refs/heads/master
Commit: a11ca03b83c6e67edbea6d99d4db5d2e2c73d78a
Parents: 1b8621b
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 13:39:26 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:54:15 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Support/Time.cs | 9 +++++++++
 1 file changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/a11ca03b/src/Lucene.Net/Support/Time.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/Time.cs b/src/Lucene.Net/Support/Time.cs
index cfa5079..cec17e8 100644
--- a/src/Lucene.Net/Support/Time.cs
+++ b/src/Lucene.Net/Support/Time.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 
 namespace Lucene.Net.Support
 {
@@ -27,6 +28,14 @@ namespace Lucene.Net.Support
         public static long NanoTime()
         {
             return DateTime.Now.Ticks * TICKS_PER_NANOSECOND;
+            // LUCENENET TODO: Change to
+            // return (Stopwatch.GetTimestamp() / Stopwatch.Frequency) * 1000000000;
+            // for better accuracy that is not affected by the system clock
+        }
+
+        public static long CurrentTimeMilliseconds()
+        {
+            return (Stopwatch.GetTimestamp() / Stopwatch.Frequency) * 1000;
         }
     }
 }
\ No newline at end of file


[04/12] lucenenet git commit: Lucene.Net.Support.Character: Ported Digit(char, int) method from Apache Harmony for use in Benchmark

Posted by ni...@apache.org.
Lucene.Net.Support.Character: Ported Digit(char, int) method from Apache Harmony for use in Benchmark


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

Branch: refs/heads/master
Commit: dc67a5578ac1dc6e71d729c7b57d5c5a0d130126
Parents: 1a4c3b8
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 06:48:57 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Mon Jul 31 06:48:57 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Support/Character.cs | 76 ++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/dc67a557/src/Lucene.Net/Support/Character.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/Character.cs b/src/Lucene.Net/Support/Character.cs
index 81fdffb..84e4a91 100644
--- a/src/Lucene.Net/Support/Character.cs
+++ b/src/Lucene.Net/Support/Character.cs
@@ -51,6 +51,82 @@ namespace Lucene.Net.Support
 
         public const int MIN_SUPPLEMENTARY_CODE_POINT = 0x010000;
 
+        private static readonly string digitKeys = "0Aa\u0660\u06f0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be7\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1369\u17e0\u1810\uff10\uff21\uff41";
+
+        private static readonly char[] digitValues = "90Z7zW\u0669\u0660\u06f9\u06f0\u096f\u0966\u09ef\u09e6\u0a6f\u0a66\u0aef\u0ae6\u0b6f\u0b66\u0bef\u0be6\u0c6f\u0c66\u0cef\u0ce6\u0d6f\u0d66\u0e59\u0e50\u0ed9\u0ed0\u0f29\u0f20\u1049\u1040\u1371\u1368\u17e9\u17e0\u1819\u1810\uff19\uff10\uff3a\uff17\uff5a\uff37"
+            .ToCharArray();
+
+        /// <summary>
+        /// Convenience method to determine the value of the specified character
+        /// <paramref name="c"/> in the supplied radix. The value of <paramref name="radix"/> must be
+        /// between <see cref="MIN_RADIX"/> and <see cref="MAX_RADIX"/>.
+        /// </summary>
+        /// <param name="c">The character to determine the value of.</param>
+        /// <param name="radix">The radix.</param>
+        /// <returns>
+        /// The value of <paramref name="c"/> in <paramref name="radix"/> if <paramref name="radix"/> lies
+        /// between <see cref="MIN_RADIX"/> and <see cref="MAX_RADIX"/>; -1 otherwise.
+        /// </returns>
+        public static int Digit(char c, int radix)
+        {
+            int result = -1;
+            if (radix >= MIN_RADIX && radix <= MAX_RADIX)
+            {
+                if (c < 128)
+                {
+                    // Optimized for ASCII
+                    if ('0' <= c && c <= '9')
+                    {
+                        result = c - '0';
+                    }
+                    else if ('a' <= c && c <= 'z')
+                    {
+                        result = c - ('a' - 10);
+                    }
+                    else if ('A' <= c && c <= 'Z')
+                    {
+                        result = c - ('A' - 10);
+                    }
+                    return result < radix ? result : -1;
+                }
+                result = BinarySearchRange(digitKeys, c);
+                if (result >= 0 && c <= digitValues[result * 2])
+                {
+                    int value = (char)(c - digitValues[result * 2 + 1]);
+                    if (value >= radix)
+                    {
+                        return -1;
+                    }
+                    return value;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Search the sorted characters in the string and return the nearest index.
+        /// </summary>
+        /// <param name="data">The String to search.</param>
+        /// <param name="c">The character to search for.</param>
+        /// <returns>The nearest index.</returns>
+        private static int BinarySearchRange(string data, char c)
+        {
+            char value = (char)0;
+            int low = 0, mid = -1, high = data.Length - 1;
+            while (low <= high)
+            {
+                mid = (low + high) >> 1;
+                value = data[mid];
+                if (c > value)
+                    low = mid + 1;
+                else if (c == value)
+                    return mid;
+                else
+                    high = mid - 1;
+            }
+            return mid - (c < value ? 1 : 0);
+        }
+
         /// <summary>
         ///
         /// </summary>


[06/12] lucenenet git commit: Lucene.Net.Support.StringTokenizer: Did a fresh port from Apache Harmony and ported tests

Posted by ni...@apache.org.
Lucene.Net.Support.StringTokenizer: Did a fresh port from Apache Harmony and ported tests


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

Branch: refs/heads/master
Commit: eaf47793073e0465c590c708d8a80b9c33140f58
Parents: cd2d351
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 12:28:03 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:53:19 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   1 +
 .../Support/TestStringTokenizer.cs              | 353 +++++++++++++++
 src/Lucene.Net/Support/StringTokenizer.cs       | 438 ++++++++++---------
 3 files changed, 581 insertions(+), 211 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/eaf47793/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 13282e1..495bd1f 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -525,6 +525,7 @@
     <Compile Include="Support\SmallObject.cs" />
     <Compile Include="Support\TestDictionaryExtensions.cs" />
     <Compile Include="Support\TestPriorityQueue.cs" />
+    <Compile Include="Support\TestStringTokenizer.cs" />
     <Compile Include="Support\Threading\TestCloseableThreadLocal.cs" />
     <Compile Include="Support\TestCollections.cs" />
     <Compile Include="Support\TestEquatableList.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/eaf47793/src/Lucene.Net.Tests/Support/TestStringTokenizer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/TestStringTokenizer.cs b/src/Lucene.Net.Tests/Support/TestStringTokenizer.cs
new file mode 100644
index 0000000..5de8588
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/TestStringTokenizer.cs
@@ -0,0 +1,353 @@
+// This class was sourced from the Apache Harmony project
+// https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/
+
+using Lucene.Net.Attributes;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using System;
+
+namespace Lucene.Net.Support
+{
+    /*
+     * 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.
+     */
+
+    public class TestStringTokenizer : LuceneTestCase
+    {
+        /**
+	     * @tests java.util.StringTokenizer#StringTokenizer(java.lang.String)
+	     */
+        [Test, LuceneNetSpecific]
+        public void Test_ConstructorLjava_lang_String()
+        {
+            // Test for method java.util.StringTokenizer(java.lang.String)
+            assertTrue("Used in tests", true);
+        }
+
+        /**
+         * @tests java.util.StringTokenizer#StringTokenizer(java.lang.String,
+         *        java.lang.String)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ConstructorLjava_lang_StringLjava_lang_String()
+        {
+            // Test for method java.util.StringTokenizer(java.lang.String,
+            // java.lang.String)
+            StringTokenizer st = new StringTokenizer("This:is:a:test:String", ":");
+            assertTrue("Created incorrect tokenizer", st.CountTokens() == 5
+                    && (st.NextToken().equals("This")));
+        }
+
+        /**
+         * @tests java.util.StringTokenizer#StringTokenizer(java.lang.String,
+         *        java.lang.String, boolean)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_ConstructorLjava_lang_StringLjava_lang_StringZ()
+        {
+            // Test for method java.util.StringTokenizer(java.lang.String,
+            // java.lang.String, boolean)
+            StringTokenizer st = new StringTokenizer("This:is:a:test:String", ":",
+                    true);
+            st.NextToken();
+            assertTrue("Created incorrect tokenizer", st.CountTokens() == 8
+                    && (st.NextToken().equals(":")));
+        }
+
+        /**
+         * @tests java.util.StringTokenizer#countTokens()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_countTokens()
+        {
+            // Test for method int java.util.StringTokenizer.countTokens()
+            StringTokenizer st = new StringTokenizer("This is a test String");
+
+            assertEquals("Incorrect token count returned", 5, st.CountTokens());
+        }
+
+        ///**
+        // * @tests java.util.StringTokenizer#hasMoreElements()
+        // */
+        //[Test, LuceneNetSpecific]
+        //public void test_hasMoreElements()
+        //{
+        //    // Test for method boolean java.util.StringTokenizer.hasMoreElements()
+
+        //    StringTokenizer st = new StringTokenizer("This is a test String");
+        //    st.NextToken();
+        //    assertTrue("hasMoreElements returned incorrect value", st
+        //            .hasMoreElements());
+        //    st.NextToken();
+        //    st.NextToken();
+        //    st.NextToken();
+        //    st.NextToken();
+        //    assertTrue("hasMoreElements returned incorrect value", !st
+        //            .hasMoreElements());
+        //}
+
+        /**
+         * @tests java.util.StringTokenizer#hasMoreTokens()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_hasMoreTokens()
+        {
+            // Test for method boolean java.util.StringTokenizer.hasMoreTokens()
+            StringTokenizer st = new StringTokenizer("This is a test String");
+            for (int counter = 0; counter < 5; counter++)
+            {
+                assertTrue(
+                        "StringTokenizer incorrectly reports it has no more tokens",
+                        st.HasMoreTokens());
+                st.NextToken();
+            }
+            assertTrue("StringTokenizer incorrectly reports it has more tokens",
+                    !st.HasMoreTokens());
+        }
+
+        ///**
+        // * @tests java.util.StringTokenizer#nextElement()
+        // */
+        //[Test, LuceneNetSpecific]
+        //public void test_nextElement()
+        //{
+        //    // Test for method java.lang.Object
+        //    // java.util.StringTokenizer.nextElement()
+        //    StringTokenizer st = new StringTokenizer("This is a test String");
+        //    assertEquals("nextElement returned incorrect value", "This", ((String)st
+        //            .NextToken()));
+        //    assertEquals("nextElement returned incorrect value", "is", ((String)st
+        //            .NextToken()));
+        //    assertEquals("nextElement returned incorrect value", "a", ((String)st
+        //            .NextToken()));
+        //    assertEquals("nextElement returned incorrect value", "test", ((String)st
+        //            .NextToken()));
+        //    assertEquals("nextElement returned incorrect value", "String", ((String)st
+        //            .NextToken()));
+        //    try
+        //    {
+        //        st.NextToken();
+        //        fail(
+        //                "nextElement failed to throw a NoSuchElementException when it should have been out of elements");
+        //    }
+        //    catch (InvalidOperationException e)
+        //    {
+        //        return;
+        //    }
+        //}
+
+        /**
+         * @tests java.util.StringTokenizer#nextToken()
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_nextToken()
+        {
+            // Test for method java.lang.String
+            // java.util.StringTokenizer.nextToken()
+            StringTokenizer st = new StringTokenizer("This is a test String");
+            assertEquals("nextToken returned incorrect value",
+                    "This", st.NextToken());
+            assertEquals("nextToken returned incorrect value",
+                    "is", st.NextToken());
+            assertEquals("nextToken returned incorrect value",
+                    "a", st.NextToken());
+            assertEquals("nextToken returned incorrect value",
+                    "test", st.NextToken());
+            assertEquals("nextToken returned incorrect value",
+                    "String", st.NextToken());
+            try
+            {
+                st.NextToken();
+                fail(
+                        "nextToken failed to throw a NoSuchElementException when it should have been out of elements");
+            }
+#pragma warning disable 168
+            catch (InvalidOperationException e)
+#pragma warning restore 168
+            {
+                return;
+            }
+        }
+
+        /**
+         * @tests java.util.StringTokenizer#nextToken(java.lang.String)
+         */
+        [Test, LuceneNetSpecific]
+        public void Test_nextTokenLjava_lang_String()
+        {
+            // Test for method java.lang.String
+            // java.util.StringTokenizer.nextToken(java.lang.String)
+            StringTokenizer st = new StringTokenizer("This is a test String");
+            assertEquals("nextToken(String) returned incorrect value with normal token String",
+                    "This", st.NextToken(" "));
+            assertEquals("nextToken(String) returned incorrect value with custom token String",
+                    " is a ", st.NextToken("tr"));
+            assertEquals("calling nextToken() did not use the new default delimiter list",
+                    "es", st.NextToken());
+        }
+
+        //[Test, LuceneNetSpecific]
+        //public void test_hasMoreElements_NPE()
+        //{
+        //    StringTokenizer stringTokenizer = new StringTokenizer(new String(),
+        //            (String)null, true);
+        //    try
+        //    {
+        //        stringTokenizer.HasMoreElements();
+        //        fail("should throw NullPointerException");
+        //    }
+        //    catch (NullPointerException e)
+        //    {
+        //        // Expected
+        //    }
+
+        //    stringTokenizer = new StringTokenizer(new String(), (String)null);
+        //    try
+        //    {
+        //        stringTokenizer.hasMoreElements();
+        //        fail("should throw NullPointerException");
+        //    }
+        //    catch (NullPointerException e)
+        //    {
+        //        // Expected
+        //    }
+        //}
+
+        [Test, LuceneNetSpecific]
+        public void Test_hasMoreTokens_NPE()
+        {
+            StringTokenizer stringTokenizer = new StringTokenizer("",
+                    (String)null, true);
+            try
+            {
+                stringTokenizer.HasMoreTokens();
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+
+            stringTokenizer = new StringTokenizer("", (String)null);
+            try
+            {
+                stringTokenizer.HasMoreTokens();
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        //[Test, LuceneNetSpecific]
+        //public void test_nextElement_NPE()
+        //{
+        //    StringTokenizer stringTokenizer = new StringTokenizer(new string(),
+        //            (String)null, true);
+        //    try
+        //    {
+        //        stringTokenizer.NextToken();
+        //        fail("should throw NullPointerException");
+        //    }
+        //    catch (ArgumentNullException e)
+        //    {
+        //        // Expected
+        //    }
+
+        //    stringTokenizer = new StringTokenizer(new String(), (String)null);
+        //    try
+        //    {
+        //        stringTokenizer.NextToken();
+        //        fail("should throw NullPointerException");
+        //    }
+        //    catch (ArgumentNullException e)
+        //    {
+        //        // Expected
+        //    }
+        //}
+
+        [Test, LuceneNetSpecific]
+        public void Test_nextToken_NPE()
+        {
+            StringTokenizer stringTokenizer = new StringTokenizer("",
+                    (String)null, true);
+            try
+            {
+                stringTokenizer.NextToken();
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+
+            stringTokenizer = new StringTokenizer("", (String)null);
+            try
+            {
+                stringTokenizer.NextToken();
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        [Test, LuceneNetSpecific]
+        public void Test_nextTokenLjava_lang_String_NPE()
+        {
+            StringTokenizer stringTokenizer = new StringTokenizer("");
+            try
+            {
+                stringTokenizer.NextToken(null);
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        /**
+         * Sets up the fixture, for example, open a network connection. This method
+         * is called before a test is executed.
+         */
+        public override void SetUp()
+        {
+            base.SetUp();
+        }
+
+        /**
+         * Tears down the fixture, for example, close a network connection. This
+         * method is called after a test is executed.
+         */
+        public override void TearDown()
+        {
+            base.TearDown();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/eaf47793/src/Lucene.Net/Support/StringTokenizer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/StringTokenizer.cs b/src/Lucene.Net/Support/StringTokenizer.cs
index 46843d3..1ab0db4 100644
--- a/src/Lucene.Net/Support/StringTokenizer.cs
+++ b/src/Lucene.Net/Support/StringTokenizer.cs
@@ -1,254 +1,270 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+// This class was sourced from the Apache Harmony project
+// https://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/
+
+using System;
 
 namespace Lucene.Net.Support
 {
     /*
-	 * 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.
-	 */
-
-    public sealed class StringTokenizer
+     * 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>
+    /// The <see cref="StringTokenizer"/> class allows an application to break a string
+    /// into tokens by performing code point comparison. The <see cref="StringTokenizer"/>
+    /// methods do not distinguish among identifiers, numbers, and quoted strings,
+    /// nor do they recognize and skip comments.
+    /// </summary>
+    /// <remarks>
+    /// The set of delimiters (the codepoints that separate tokens) may be specified
+    /// either at creation time or on a per-token basis.
+    /// <p>
+    /// An instance of <see cref="StringTokenizer"/> behaves in one of three ways,
+    /// depending on whether it was created with the <c>returnDelimiters</c> flag
+    /// having the value <c>true</c> or <c>false</c>:
+    /// <list type="bullet">
+    /// <item><description>If returnDelims is <c>false</c>, delimiter code points serve to separate
+    /// tokens. A token is a maximal sequence of consecutive code points that are not
+    /// delimiters.</description>
+    /// <item><description>If returnDelims is <c>true</c>, delimiter code points are themselves
+    /// considered to be tokens. In this case a token will be received for each
+    /// delimiter code point.</description></item>
+    /// </list>
+    /// <para/>
+    /// A token is thus either one delimiter code point, or a maximal sequence of
+    /// consecutive code points that are not delimiters.
+    /// <para/>
+    /// A <see cref="StringTokenizer"/> object internally maintains a current position
+    /// within the string to be tokenized. Some operations advance this current
+    /// position past the code point processed.
+    /// <para/>
+    /// A token is returned by taking a substring of the string that was used to
+    /// create the <see cref="StringTokenizer"/> object.
+    /// <para/>
+    /// Here's an example of the use of the default delimiter <see cref="StringTokenizer"/>:
+    ///
+    /// <code>
+    /// StringTokenizer st = new StringTokenizer(&quot;this is a test&quot;);
+    /// while (st.HasMoreTokens()) {
+    ///     println(st.NextToken());
+    /// }
+    /// </code>
+    ///
+    /// <para/>
+    /// This prints the following output: 
+    ///
+    /// <code>
+    ///     this
+    ///     is
+    ///     a
+    ///     test
+    /// </code>
+    ///
+    /// <para/>
+    /// Here's an example of how to use a <see cref="StringTokenizer"/> with a user
+    /// specified delimiter: 
+    ///
+    /// <code>
+    /// StringTokenizer st = new StringTokenizer(
+    ///         &quot;this is a test with supplementary characters \ud800\ud800\udc00\udc00&quot;,
+    ///         &quot; \ud800\udc00&quot;);
+    /// while (st.HasMoreTokens()) {
+    ///     println(st.NextToken());
+    /// }
+    /// </code>
+    ///
+    /// <para/>
+    /// This prints the following output:
+    ///
+    /// <code>
+    ///     this
+    ///     is
+    ///     a
+    ///     test
+    ///     with
+    ///     supplementary
+    ///     characters
+    ///     \ud800
+    ///     \udc00
+    /// </code>
+    ///
+    /// </remarks>
+    public class StringTokenizer
     {
-        private readonly TokenParsingStrategy _strategy;
-
-        private const int _preprocessThreshold = 1024; // 1024 chars -- TODO: empirically determine best threshold
-
-        public StringTokenizer(string str, string delim, bool returnDelims)
-        {
-            if (str == null)
-                throw new ArgumentNullException("str");
-
-            if (string.IsNullOrEmpty(delim))
-                throw new ArgumentException("No delimiter characters given!");
-
-            var delimSet = new HashSet<char>(delim.ToCharArray());
-
-            if (str.Length > _preprocessThreshold)
-            {
-                _strategy = new StringBuilderTokenParsingStrategy(str, delimSet, returnDelims);
-            }
-            else
-            {
-                _strategy = new PreProcessTokenParsingStrategy(str, delimSet, returnDelims);
-            }
-        }
-
-        public StringTokenizer(string str, string delim)
-            : this(str, delim, false)
-        {
-        }
-
+        private string str;
+        private string delimiters;
+        private bool returnDelimiters;
+        private int position;
+
+        /// <summary>
+        /// Constructs a new <see cref="StringTokenizer"/> for the parameter string using
+        /// whitespace as the delimiter. The <see cref="returnDelimiters"/> flag is set to
+        /// <c>false</c>.
+        /// </summary>
+        /// <param name="str">The string to be tokenized.</param>      
         public StringTokenizer(string str)
             : this(str, " \t\n\r\f", false)
         {
         }
 
-        public bool HasMoreTokens()
-        {
-            return _strategy.HasMoreTokens();
-        }
-
-        public string NextToken()
-        {
-            return _strategy.NextToken();
-        }
-
-        //public string NextToken(string delim)
-        //{
-        //    if (string.IsNullOrEmpty(delim))
-        //        throw new ArgumentException("No delimiter characters given!");
-
-        //    _delims.Clear();
-        //    _delims.UnionWith(delim.ToCharArray());
-
-        //    return NextToken();
-        //}
-
-        public int CountTokens()
+        /// <summary>
+        /// Constructs a new <see cref="StringTokenizer"/> for the parameter string using
+        /// the specified delimiters. The <see cref="returnDelimiters"/> flag is set to
+        /// <c>false</c>. If <paramref name="delimiters"/> is <c>null</c>, this constructor
+        /// doesn't throw an <see cref="Exception"/>, but later calls to some methods might
+        /// throw an <see cref="ArgumentNullException"/> or <see cref="InvalidOperationException"/>.
+        /// </summary>
+        /// <param name="str">The string to be tokenized.</param>
+        /// <param name="delimiters">The delimiters to use.</param>
+        public StringTokenizer(string str, string delimiters)
+            : this(str, delimiters, false)
         {
-            return _strategy.CountTokens();
         }
 
-        private abstract class TokenParsingStrategy
+        /// <summary>
+        /// Constructs a new <see cref="StringTokenizer"/> for the parameter string using
+        /// the specified delimiters, returning the delimiters as tokens if the
+        /// parameter <paramref name="returnDelimiters"/> is <c>true</c>. If <paramref name="delimiters"/>
+        /// is null this constructor doesn't throw an <see cref="Exception"/>, but later
+        /// calls to some methods might throw an <see cref="ArgumentNullException"/> or <see cref="InvalidOperationException"/>.
+        /// </summary>
+        /// <param name="str">The string to be tokenized.</param>
+        /// <param name="delimiters">The delimiters to use.</param>
+        /// <param name="returnDelimiters"><c>true</c> to return each delimiter as a token.</param>
+        public StringTokenizer(string str, string delimiters,
+                bool returnDelimiters)
         {
-            public abstract bool HasMoreTokens();
-
-            public abstract string NextToken();
-
-            public abstract int CountTokens();
-        }
-
-        private class StringBuilderTokenParsingStrategy : TokenParsingStrategy
-        {
-            private readonly string _str;
-            private readonly ISet<char> _delims;
-            private readonly bool _returnDelims;
-
-            private int _position = 0;
-
-            public StringBuilderTokenParsingStrategy(string str, ISet<char> delims, bool returnDelims)
+            if (str != null)
             {
-                _str = str;
-                _delims = delims;
-                _returnDelims = returnDelims;
+                this.str = str;
+                this.delimiters = delimiters;
+                this.returnDelimiters = returnDelimiters;
+                this.position = 0;
             }
+            else
+                throw new ArgumentNullException("str");
+        }
 
-            public override bool HasMoreTokens()
+        /// <summary>
+        /// Returns the number of unprocessed tokens remaining in the string.
+        /// </summary>
+        /// <returns>number of tokens that can be retreived before an 
+        /// <see cref="Exception"/> will result from a call to <see cref="NextToken()"/>.</returns>
+        public virtual int CountTokens()
+        {
+            int count = 0;
+            bool inToken = false;
+            for (int i = position, length = str.Length; i < length; i++)
             {
-                if (_position >= _str.Length)
-                    return false;
-
-                if (_returnDelims)
-                    return true; // since we're not at end of string, there has to be a token left if returning delimiters
-
-                for (int i = _position; i < _str.Length; i++)
+                if (delimiters.IndexOf(str[i], 0) >= 0)
                 {
-                    if (!_delims.Contains(_str[i]))
-                        return true;
-                }
-
-                return false; // only delims left
-            }
-
-            public override string NextToken()
-            {
-                if (_position >= _str.Length)
-                    throw new InvalidOperationException("Past end of string.");
-
-                if (_returnDelims && _delims.Contains(_str[_position]))
-                {
-                    _position++;
-                    return _str[_position].ToString();
-                }
-
-                StringBuilder sb = new StringBuilder();
-
-                for (int i = _position; i < _str.Length; i++)
-                {
-                    char c = _str[i];
-
-                    _position = i;
-
-                    if (_delims.Contains(c))
+                    if (returnDelimiters)
+                        count++;
+                    if (inToken)
                     {
-                        break;
-                    }
-                    else
-                    {
-                        sb.Append(c);
+                        count++;
+                        inToken = false;
                     }
                 }
-
-                return sb.ToString();
-            }
-
-            public override int CountTokens()
-            {
-                if (_position >= _str.Length)
-                    return 0;
-
-                int count = 0;
-                bool lastWasDelim = true; // consider start of string/substring a delim
-
-                for (int i = _position; i < _str.Length; i++)
+                else
                 {
-                    char c = _str[i];
-
-                    if (_delims.Contains(c))
-                    {
-                        if (!lastWasDelim)
-                            count++; // increase since now we're at a delim
-
-                        lastWasDelim = true;
-
-                        if (_returnDelims)
-                            count++; // this delim counts as a token
-                    }
-                    else
-                    {
-                        lastWasDelim = false;
-                    }
+                    inToken = true;
                 }
-
-                if (!lastWasDelim)
-                    count++; // string ended with non-delim
-
-                return count;
             }
+            if (inToken)
+                count++;
+            return count;
         }
 
-        private class PreProcessTokenParsingStrategy : TokenParsingStrategy
+        /// <summary>
+        /// Returns <c>true</c> if unprocessed tokens remain.
+        /// </summary>
+        /// <returns><c>true</c> if unprocessed tokens remain.</returns>
+        public bool HasMoreTokens()
         {
-            private readonly string _str;
-            private readonly ISet<char> _delims;
-            private readonly bool _returnDelims;
-            private readonly List<string> _tokens = new List<string>();
-            private int _index = 0;
-
-            public PreProcessTokenParsingStrategy(string str, ISet<char> delims, bool returnDelims)
+            if (delimiters == null)
             {
-                _str = str;
-                _delims = delims;
-                _returnDelims = returnDelims;
-
-                Preprocess();
+                throw new ArgumentNullException("delimiters");
             }
-
-            private void Preprocess()
+            int length = str.Length;
+            if (position < length)
             {
-                StringBuilder sb = new StringBuilder();
-
-                foreach (char c in _str)
-                {
-                    if (_delims.Contains(c))
-                    {
-                        if (sb.Length > 0)
-                        {
-                            _tokens.Add(sb.ToString());
-                            sb.Clear();
-                        }
+                if (returnDelimiters)
+                    return true; // there is at least one character and even if
+                                 // it is a delimiter it is a token
 
-                        if (_returnDelims)
-                            _tokens.Add(c.ToString());
-                    }
-                    else
-                    {
-                        sb.Append(c);
-                    }
-                }
-
-                if (sb.Length > 0)
-                    _tokens.Add(sb.ToString());
+                // otherwise find a character which is not a delimiter
+                for (int i = position; i < length; i++)
+                    if (delimiters.IndexOf(str[i], 0) == -1)
+                        return true;
             }
+            return false;
+        }
 
-            public override bool HasMoreTokens()
+        /// <summary>
+        /// Returns the next token in the string as a <see cref="string"/>.
+        /// </summary>
+        /// <returns>Next token in the string as a <see cref="string"/>.</returns>
+        /// <exception cref="InvalidOperationException">If no tokens remain.</exception>
+        public string NextToken()
+        {
+            if (delimiters == null)
             {
-                return _index < _tokens.Count;
+                throw new ArgumentNullException();
             }
+            int i = position;
+            int length = str.Length;
 
-            public override string NextToken()
+            if (i < length)
             {
-                return _tokens[_index++];
-            }
+                if (returnDelimiters)
+                {
+                    if (delimiters.IndexOf(str[position], 0) >= 0)
+                        return str[position++].ToString();
+                    for (position++; position < length; position++)
+                        if (delimiters.IndexOf(str[position], 0) >= 0)
+                            return str.Substring(i, position - i);
+                    return str.Substring(i);
+                }
 
-            public override int CountTokens()
-            {
-                return _tokens.Count - _index;
+                while (i < length && delimiters.IndexOf(str[i], 0) >= 0)
+                    i++;
+                position = i;
+                if (i < length)
+                {
+                    for (position++; position < length; position++)
+                        if (delimiters.IndexOf(str[position], 0) >= 0)
+                            return str.Substring(i, position - i);
+                    return str.Substring(i);
+                }
             }
+            throw new InvalidOperationException("No more elements");
+        }
+
+        /// <summary>
+        /// Returns the next token in the string as a <see cref="string"/>. The delimiters
+        /// used are changed to the specified delimiters.
+        /// </summary>
+        /// <param name="delims">The new delimiters to use.</param>
+        /// <returns>Next token in the string as a <see cref="string"/>.</returns>
+        /// <exception cref="InvalidOperationException">If no tokens remain.</exception>
+        public string NextToken(string delims)
+        {
+            this.delimiters = delims;
+            return NextToken();
         }
     }
 }
\ No newline at end of file


[07/12] lucenenet git commit: Lucene.Net.Support: Added a SystemConsole class as a stand-in for System.Console, but with the ability to swap Out and Error to a different destination than System.Out and System.Error.

Posted by ni...@apache.org.
Lucene.Net.Support: Added a SystemConsole class as a stand-in for System.Console, but with the ability to swap Out and Error to a different destination than System.Out and System.Error.


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

Branch: refs/heads/master
Commit: 51a6c52b39ce4183c6f18ba3af158bc132b12390
Parents: eaf4779
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 12:43:54 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Wed Aug 2 09:53:48 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net/Lucene.Net.csproj             |   1 +
 src/Lucene.Net/Support/SystemConsole.cs      | 411 ++++++++++++++++++++++
 src/Lucene.Net/Util/PrintStreamInfoStream.cs |  12 +-
 3 files changed, 421 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/51a6c52b/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Lucene.Net.csproj b/src/Lucene.Net/Lucene.Net.csproj
index 8f8fc4b..211a013 100644
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@ -656,6 +656,7 @@
     <Compile Include="Support\RectangularArrays.cs" />
     <Compile Include="Support\Search\ReferenceContext.cs" />
     <Compile Include="Support\Search\ReferenceManagerExtensions.cs" />
+    <Compile Include="Support\SystemConsole.cs" />
     <Compile Include="Support\SystemProperties.cs" />
     <Compile Include="Support\Threading\ICompletionService.cs" />
     <Compile Include="Support\IO\IDataInput.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/51a6c52b/src/Lucene.Net/Support/SystemConsole.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/SystemConsole.cs b/src/Lucene.Net/Support/SystemConsole.cs
new file mode 100644
index 0000000..4a08ad1
--- /dev/null
+++ b/src/Lucene.Net/Support/SystemConsole.cs
@@ -0,0 +1,411 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+#if !NETSTANDARD
+using System.Security.Permissions;
+#endif
+
+namespace Lucene.Net.Support
+{
+    /*
+     * 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.
+     */
+
+    // LUCENENET TODO: Replace all interaction with System.Console with this class
+    // so we can swap all input/ouput during testing or production scenarios
+
+    /// <summary>
+    /// Mimics <see cref="System.Console"/>, but allows for swapping
+    /// the <see cref="TextWriter"/> of 
+    /// <see cref="Out"/> and <see cref="Error"/>, or the <see cref="TextReader"/> of <see cref="In"/>
+    /// with user-defined implementations.
+    /// </summary>
+    public static class SystemConsole
+    {
+        public static TextWriter Out { get; set; } = Console.Out;
+        public static TextWriter Error { get; set; } = Console.Error;
+        public static TextReader In { get; set; } = Console.In;
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(bool value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(char value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(char[] buffer)
+        {
+            Out.Write(buffer);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(decimal value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(double value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(int value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(long value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(object value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(float value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(string value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(uint value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(ulong value)
+        {
+            Out.Write(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(string format, object arg0)
+        {
+            Out.Write(format, arg0);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(string format, params object[] arg)
+        {
+            if (arg == null)
+            {
+                Out.Write(format, null, null);
+            }
+            else
+            {
+                Out.Write(format, arg);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(char[] buffer, int index, int count)
+        {
+            Out.Write(buffer, index, count);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(string format, object arg0, object arg1)
+        {
+            Out.Write(format, arg0, arg1);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void Write(string format, object arg0, object arg1, object arg2)
+        {
+            Out.Write(format, arg0, arg1, arg2);
+        }
+
+#if !NETSTANDARD
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+        public static void Write(string format, object arg0, object arg1, object arg2, object arg3, __arglist)
+        {
+            ArgIterator iterator = new ArgIterator(__arglist);
+            int num = iterator.GetRemainingCount() + 4;
+            object[] arg = new object[num];
+            arg[0] = arg0;
+            arg[1] = arg1;
+            arg[2] = arg2;
+            arg[3] = arg3;
+            for (int i = 4; i < num; i++)
+            {
+                arg[i] = TypedReference.ToObject(iterator.GetNextArg());
+            }
+            Out.Write(format, arg);
+        }
+#endif
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine()
+        {
+            Out.WriteLine();
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(bool value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(char value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(char[] buffer)
+        {
+            Out.WriteLine(buffer);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(decimal value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(double value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(int value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(long value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(object value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(float value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(string value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(uint value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(ulong value)
+        {
+            Out.WriteLine(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(string format, object arg0)
+        {
+            Out.WriteLine(format, arg0);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(string format, params object[] arg)
+        {
+            if (arg == null)
+            {
+                Out.WriteLine(format, null, null);
+            }
+            else
+            {
+                Out.WriteLine(format, arg);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(char[] buffer, int index, int count)
+        {
+            Out.WriteLine(buffer, index, count);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(string format, object arg0, object arg1)
+        {
+            Out.WriteLine(format, arg0, arg1);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+#if !NETSTANDARD
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+#endif
+        public static void WriteLine(string format, object arg0, object arg1, object arg2)
+        {
+            Out.WriteLine(format, arg0, arg1, arg2);
+        }
+
+#if !NETSTANDARD
+        [MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)]
+        [HostProtection(SecurityAction.LinkDemand, UI = true)]
+        public static void WriteLine(string format, object arg0, object arg1, object arg2, object arg3, __arglist)
+        {
+            ArgIterator iterator = new ArgIterator(__arglist);
+            int num = iterator.GetRemainingCount() + 4;
+            object[] arg = new object[num];
+            arg[0] = arg0;
+            arg[1] = arg1;
+            arg[2] = arg2;
+            arg[3] = arg3;
+            for (int i = 4; i < num; i++)
+            {
+                arg[i] = TypedReference.ToObject(iterator.GetNextArg());
+            }
+            Out.WriteLine(format, arg);
+        }
+#endif
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/51a6c52b/src/Lucene.Net/Util/PrintStreamInfoStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Util/PrintStreamInfoStream.cs b/src/Lucene.Net/Util/PrintStreamInfoStream.cs
index ebbb8d3..e8d6d4c 100644
--- a/src/Lucene.Net/Util/PrintStreamInfoStream.cs
+++ b/src/Lucene.Net/Util/PrintStreamInfoStream.cs
@@ -1,6 +1,8 @@
 using Lucene.Net.Support;
+using Lucene.Net.Support.IO;
 using System;
 using System.IO;
+using System.Reflection;
 using System.Threading;
 
 namespace Lucene.Net.Util
@@ -51,8 +53,8 @@ namespace Lucene.Net.Util
         private static readonly AtomicInt32 MESSAGE_ID = new AtomicInt32();
 
         protected readonly int m_messageID;
-
         protected readonly TextWriter m_stream;
+        private readonly bool isSystemStream;
 
         public TextWriterInfoStream(TextWriter stream)
             : this(stream, MESSAGE_ID.GetAndIncrement())
@@ -61,7 +63,11 @@ namespace Lucene.Net.Util
 
         public TextWriterInfoStream(TextWriter stream, int messageID)
         {
-            this.m_stream = stream;
+            // LUCENENET: Since we are wrapping our TextWriter to make it safe to use
+            // after calling Dispose(), we need to determine whether it is a system stream
+            // here instead of on demand.
+            this.isSystemStream = stream == SystemConsole.Out || stream == SystemConsole.Error;
+            this.m_stream = typeof(SafeTextWriterWrapper).GetTypeInfo().IsAssignableFrom(stream.GetType()) ? stream : new SafeTextWriterWrapper(stream);
             this.m_messageID = messageID;
         }
 
@@ -87,7 +93,7 @@ namespace Lucene.Net.Util
         {
             get
             {
-                return m_stream == Console.Out || m_stream == Console.Error;
+                return isSystemStream;
             }
         }
     }


[02/12] lucenenet git commit: BUG: Lucene.Net.Analysis.Common\Analysis\CharFilter\MappingCharFilterFactory: fixed escaping problem in parsing regex

Posted by ni...@apache.org.
BUG: Lucene.Net.Analysis.Common\Analysis\CharFilter\MappingCharFilterFactory: fixed escaping problem in parsing regex


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

Branch: refs/heads/master
Commit: 6c6a17bda3b1863c70aa687c870d7a24199dc4a1
Parents: 05c8a04
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Mon Jul 31 06:40:34 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Mon Jul 31 06:40:34 2017 +0700

----------------------------------------------------------------------
 .../Analysis/CharFilter/MappingCharFilterFactory.cs                | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6c6a17bd/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilterFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilterFactory.cs b/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilterFactory.cs
index d16965c..ce116da 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilterFactory.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/CharFilter/MappingCharFilterFactory.cs
@@ -92,7 +92,7 @@ namespace Lucene.Net.Analysis.CharFilters
         }
 
         // "source" => "target"
-        private static Regex p = new Regex(@"\""(.*)\""\\s*=>\\s*\""(.*)\""\\s*$", RegexOptions.Compiled);
+        private static Regex p = new Regex(@"\""(.*)\""\s*=>\s*\""(.*)\""\s*$", RegexOptions.Compiled);
 
         protected virtual void ParseRules(IList<string> rules, NormalizeCharMap.Builder builder)
         {