From 21121a7336c50eb2468a42015818d9953529c32e Mon Sep 17 00:00:00 2001 From: WinCPP Date: Fri, 8 Sep 2017 02:33:31 +0530 Subject: [PATCH] CoreFx #22406 Span based APIs - Text Reader Writer --- .../tests/StreamReader/StreamReaderTests.cs | 53 +- .../StreamWriter/StreamWriter.WriteTests.cs | 41 +- .../tests/StringWriter/StringWriterTests.cs | 41 +- src/System.IO/tests/System.IO.Tests.csproj | 6 + .../tests/TextReader/CharArrayTextReader.cs | 37 ++ .../tests/TextReader/TextReaderTests.cs | 284 +++++++++ .../TextReader/TextReaderTests.netcoreapp.cs | 49 ++ .../tests/TextWriter/CharArrayTextWriter.cs | 29 + .../tests/TextWriter/TextWriterTests.cs | 598 ++++++++++++++++++ .../TextWriter/TextWriterTests.netcoreapp.cs | 38 ++ .../ref/System.Runtime.Extensions.cs | 4 + .../src/Resources/Strings.resx | 64 +- .../src/System/IO/TextReader.cs | 48 ++ .../src/System/IO/TextWriter.cs | 33 + 14 files changed, 1258 insertions(+), 67 deletions(-) create mode 100644 src/System.IO/tests/TextReader/CharArrayTextReader.cs create mode 100644 src/System.IO/tests/TextReader/TextReaderTests.cs create mode 100644 src/System.IO/tests/TextReader/TextReaderTests.netcoreapp.cs create mode 100644 src/System.IO/tests/TextWriter/CharArrayTextWriter.cs create mode 100644 src/System.IO/tests/TextWriter/TextWriterTests.cs create mode 100644 src/System.IO/tests/TextWriter/TextWriterTests.netcoreapp.cs diff --git a/src/System.IO/tests/StreamReader/StreamReaderTests.cs b/src/System.IO/tests/StreamReader/StreamReaderTests.cs index 0a70a82028ec..e61b591fd7c6 100644 --- a/src/System.IO/tests/StreamReader/StreamReaderTests.cs +++ b/src/System.IO/tests/StreamReader/StreamReaderTests.cs @@ -40,32 +40,33 @@ protected virtual Stream GetLargeStream() protected Tuple GetCharArrayStream() { - var chArr = new char[]{ - char.MinValue - ,char.MaxValue - ,'\t' - ,' ' - ,'$' - ,'@' - ,'#' - ,'\0' - ,'\v' - ,'\'' - ,'\u3190' - ,'\uC3A0' - ,'A' - ,'5' - ,'\r' - ,'\uFE70' - ,'-' - ,';' - ,'\r' - ,'\n' - ,'T' - ,'3' - ,'\n' - ,'K' - ,'\u00E6' + var chArr = new char[] + { + char.MinValue, + char.MaxValue, + '\t', + ' ', + '$', + '@', + '#', + '\0', + '\v', + '\'', + '\u3190', + '\uC3A0', + 'A', + '5', + '\r', + '\uFE70', + '-', + ';', + '\r', + '\n', + 'T', + '3', + '\n', + 'K', + '\u00E6' }; var ms = CreateStream(); var sw = new StreamWriter(ms); diff --git a/src/System.IO/tests/StreamWriter/StreamWriter.WriteTests.cs b/src/System.IO/tests/StreamWriter/StreamWriter.WriteTests.cs index 5c913da954f8..698c8378e26e 100644 --- a/src/System.IO/tests/StreamWriter/StreamWriter.WriteTests.cs +++ b/src/System.IO/tests/StreamWriter/StreamWriter.WriteTests.cs @@ -42,26 +42,27 @@ public void WriteChars() private static char[] setupArray() { - return new char[]{ - char.MinValue - ,char.MaxValue - ,'\t' - ,' ' - ,'$' - ,'@' - ,'#' - ,'\0' - ,'\v' - ,'\'' - ,'\u3190' - ,'\uC3A0' - ,'A' - ,'5' - ,'\uFE70' - ,'-' - ,';' - ,'\u00E6' - }; + return new char[] + { + char.MinValue, + char.MaxValue, + '\t', + ' ', + '$', + '@', + '#', + '\0', + '\v', + '\'', + '\u3190', + '\uC3A0', + 'A', + '5', + '\uFE70', + '-', + ';', + '\u00E6' + }; } [Fact] diff --git a/src/System.IO/tests/StringWriter/StringWriterTests.cs b/src/System.IO/tests/StringWriter/StringWriterTests.cs index 6655a2d54862..1bb9e6e50fba 100644 --- a/src/System.IO/tests/StringWriter/StringWriterTests.cs +++ b/src/System.IO/tests/StringWriter/StringWriterTests.cs @@ -19,26 +19,27 @@ public class StringWriterTests private static char[] getCharArray() { - return new char[]{ - char.MinValue - ,char.MaxValue - ,'\t' - ,' ' - ,'$' - ,'@' - ,'#' - ,'\0' - ,'\v' - ,'\'' - ,'\u3190' - ,'\uC3A0' - ,'A' - ,'5' - ,'\uFE70' - ,'-' - ,';' - ,'\u00E6' - }; + return new char[] + { + char.MinValue, + char.MaxValue, + '\t', + ' ', + '$', + '@', + '#', + '\0', + '\v', + '\'', + '\u3190', + '\uC3A0', + 'A', + '5', + '\uFE70', + '-', + ';', + '\u00E6' + }; } private static StringBuilder getSb() diff --git a/src/System.IO/tests/System.IO.Tests.csproj b/src/System.IO/tests/System.IO.Tests.csproj index 104defc428f4..86ac421652a7 100644 --- a/src/System.IO/tests/System.IO.Tests.csproj +++ b/src/System.IO/tests/System.IO.Tests.csproj @@ -59,6 +59,12 @@ Common\System\IO\WrappedMemoryStream.cs + + + + + + diff --git a/src/System.IO/tests/TextReader/CharArrayTextReader.cs b/src/System.IO/tests/TextReader/CharArrayTextReader.cs new file mode 100644 index 000000000000..c82f2bb32188 --- /dev/null +++ b/src/System.IO/tests/TextReader/CharArrayTextReader.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.IO.Tests +{ + public class CharArrayTextReader : TextReader + { + private readonly char[] _charBuffer; + private int _charPos = 0; + + public bool EndOfStream => _charPos >= _charBuffer.Length; + + public CharArrayTextReader(char[] data) + { + _charBuffer = data; + } + + public override int Peek() + { + if (_charPos == _charBuffer.Length) + { + return -1; + } + return _charBuffer[_charPos]; + } + + public override int Read() + { + if (_charPos == _charBuffer.Length) + { + return -1; + } + return _charBuffer[_charPos++]; + } + } +} diff --git a/src/System.IO/tests/TextReader/TextReaderTests.cs b/src/System.IO/tests/TextReader/TextReaderTests.cs new file mode 100644 index 000000000000..768aa4f899d1 --- /dev/null +++ b/src/System.IO/tests/TextReader/TextReaderTests.cs @@ -0,0 +1,284 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace System.IO.Tests +{ + public partial class TextReaderTests + { + protected virtual char[] GetSmallData() + { + return "HELLO".ToCharArray(); + } + + protected virtual char[] GetLargeData() + { + var testData = "HELLO".ToCharArray(); + + var data = new List(); + for (int i = 0; i < 1000; i++) + { + data.AddRange(testData); + } + + return data.ToArray(); + } + + protected (char[] chArr, CharArrayTextReader textReader) GetCharArray() + { + var chArr = new char[] + { + char.MinValue, + char.MaxValue, + '\t', + ' ', + '$', + '@', + '#', + '\0', + '\v', + '\'', + '\u3190', + '\uC3A0', + 'A', + '5', + '\r', + '\uFE70', + '-', + ';', + '\r', + '\n', + 'T', + '3', + '\n', + 'K', + '\u00E6' + }; + + var tr = new CharArrayTextReader(chArr); + + return (chArr, tr); + } + + [Fact] + public void EndOfStream() + { + using (var tr = new CharArrayTextReader(GetSmallData())) + { + var result = tr.ReadToEnd(); + + Assert.Equal("HELLO", result); + + Assert.True(tr.EndOfStream, "End of TextReader was not true after ReadToEnd"); + } + } + + [Fact] + public void NotEndOfStream() + { + using (var tr = new CharArrayTextReader(GetSmallData())) + { + var charBuff = new char[3]; + var result = tr.Read(charBuff, 0, 3); + + Assert.Equal(3, result); + + Assert.Equal("HEL", new string(charBuff)); + + Assert.False(tr.EndOfStream, "End of TextReader was true after ReadToEnd"); + } + } + + [Fact] + public async Task ReadToEndAsync() + { + using (var tr = new CharArrayTextReader(GetLargeData())) + { + var result = await tr.ReadToEndAsync(); + + Assert.Equal(5000, result.Length); + } + } + + [Fact] + public void TestRead() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + int tmp = tr.Read(); + Assert.Equal((int)baseInfo.chArr[i], tmp); + } + + tr.Dispose(); + } + + [Fact] + public void ArgumentNullOnNullArray() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + Assert.Throws(() => tr.Read(null, 0, 0)); + } + + [Fact] + public void ArgumentOutOfRangeOnInvalidOffset() + { + var tr = GetCharArray().textReader; + Assert.Throws(() => tr.Read(new char[0], -1, 0)); + } + + [Fact] + public void ArgumentOutOfRangeOnNegativCount() + { + var tr = GetCharArray().textReader; + AssertExtensions.Throws(null, () => tr.Read(new char[0], 0, 1)); + } + + [Fact] + public void ArgumentExceptionOffsetAndCount() + { + var tr = GetCharArray().textReader; + AssertExtensions.Throws(null, () => tr.Read(new char[0], 2, 0)); + } + + [Fact] + public void EmptyInput() + { + using (var tr = new CharArrayTextReader(new char[] { })) + { + var buffer = new char[10]; + int read = tr.Read(buffer, 0, 1); + Assert.Equal(0, read); + } + } + + [Fact] + public void ReadCharArr() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + + var read = tr.Read(chArr, 0, chArr.Length); + + Assert.Equal(chArr.Length, read); + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i]); + } + } + + [Fact] + public void ReadBlockCharArr() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + + var read = tr.ReadBlock(chArr, 0, chArr.Length); + + Assert.Equal(chArr.Length, read); + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i]); + } + } + + [Fact] + public async void ReadBlockAsyncCharArr() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + + var read = await tr.ReadBlockAsync(chArr, 0, chArr.Length); + + Assert.Equal(chArr.Length, read); + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i]); + } + } + + [Fact] + public async Task ReadAsync() + { + var baseInfo = GetCharArray(); + + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + + var read = await tr.ReadAsync(chArr, 4, 3); + + Assert.Equal(read, 3); + for (int i = 0; i < 3; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i + 4]); + } + } + + [Fact] + public void ReadLines() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + string valueString = new string(baseInfo.chArr); + + + var data = tr.ReadLine(); + Assert.Equal(valueString.Substring(0, valueString.IndexOf('\r')), data); + + data = tr.ReadLine(); + Assert.Equal(valueString.Substring(valueString.IndexOf('\r') + 1, 3), data); + + data = tr.ReadLine(); + Assert.Equal(valueString.Substring(valueString.IndexOf('\n') + 1, 2), data); + + data = tr.ReadLine(); + Assert.Equal((valueString.Substring(valueString.LastIndexOf('\n') + 1)), data); + } + + [Fact] + public void ReadLines2() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + string valueString = new string(baseInfo.chArr); + + var temp = new char[10]; + tr.Read(temp, 0, 1); + var data = tr.ReadLine(); + Assert.Equal(valueString.Substring(1, valueString.IndexOf('\r') - 1), data); + } + + [Fact] + public async Task ReadLineAsyncContinuousNewLinesAndTabs() + { + var newLineTabData = new char[] { '\n', '\n', '\r', '\r', '\n' }; + var tr = new CharArrayTextReader(newLineTabData); + + for (int i = 0; i < 4; i++) + { + var data = await tr.ReadLineAsync(); + Assert.Equal(string.Empty, data); + } + + var eol = await tr.ReadLineAsync(); + Assert.Null(eol); + } + } +} diff --git a/src/System.IO/tests/TextReader/TextReaderTests.netcoreapp.cs b/src/System.IO/tests/TextReader/TextReaderTests.netcoreapp.cs new file mode 100644 index 000000000000..e58f2ac7f5eb --- /dev/null +++ b/src/System.IO/tests/TextReader/TextReaderTests.netcoreapp.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace System.IO.Tests +{ + public partial class TextReaderTests + { + [Fact] + public void ReadSpan() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + var chSpan = new Span(chArr, 0, baseInfo.chArr.Length); + + var read = tr.Read(chSpan); + + Assert.Equal(chArr.Length, read); + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i]); + } + } + + [Fact] + public void ReadBlockSpan() + { + var baseInfo = GetCharArray(); + var tr = baseInfo.textReader; + + var chArr = new char[baseInfo.chArr.Length]; + var chSpan = new Span(chArr, 0, baseInfo.chArr.Length); + + var read = tr.Read(chSpan); + + Assert.Equal(chArr.Length, read); + for (int i = 0; i < baseInfo.chArr.Length; i++) + { + Assert.Equal(baseInfo.chArr[i], chArr[i]); + } + } + } +} diff --git a/src/System.IO/tests/TextWriter/CharArrayTextWriter.cs b/src/System.IO/tests/TextWriter/CharArrayTextWriter.cs new file mode 100644 index 000000000000..0eb9b6194217 --- /dev/null +++ b/src/System.IO/tests/TextWriter/CharArrayTextWriter.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; + +namespace System.IO.Tests +{ + public class CharArrayTextWriter : TextWriter + { + private StringBuilder _sb; + + public override Encoding Encoding => Encoding.Unicode; + + public CharArrayTextWriter() + { + _sb = new StringBuilder(); + } + + public override void Write(char value) + { + _sb.Append(value); + } + + public string Text => _sb.ToString(); + + public void Clear() => _sb.Clear(); + } +} diff --git a/src/System.IO/tests/TextWriter/TextWriterTests.cs b/src/System.IO/tests/TextWriter/TextWriterTests.cs new file mode 100644 index 000000000000..764910f47bfa --- /dev/null +++ b/src/System.IO/tests/TextWriter/TextWriterTests.cs @@ -0,0 +1,598 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace System.IO.Tests +{ + public partial class TextWriterTests + { + protected static string FormatStringOneObject = "Object is {0}"; + protected static string FormatStringTwoObjects = $"Object are '{0}', {SecondObject}"; + protected static string FormatStringThreeObjects = $"Objects are {0}, {SecondObject}, {ThirdObject}"; + protected static string FormatStringMultipleObjects = "Multiple Objects are: {0}, {1}, {2}"; + + protected static object FirstObject = (object)1; + protected static object SecondObject = (object)"[second object]"; + protected static object ThirdObject = (object)""; + protected static object[] MultipleObjects = new object[] { FirstObject, SecondObject, ThirdObject }; + + protected char[] GetCharArray() + { + return new char[] + { + char.MinValue, + char.MaxValue, + '\t', + ' ', + '$', + '@', + '#', + '\0', + '\v', + '\'', + '\u3190', + '\uC3A0', + 'A', + '5', + '\r', + '\uFE70', + '-', + ';', + '\r', + '\n', + 'T', + '3', + '\n', + 'K', + '\u00E6' + }; + } + + protected static CharArrayTextWriter GetTextWriter() + { + var tw = new CharArrayTextWriter(); + tw.NewLine = "---"; + return tw; + } + + #region Write Overloads + + [Fact] + public void WriteCharTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + for (int count = 0; count < chArr.Length; ++count) + { + tw.Write(chArr[count]); + } + Assert.Equal(new string(chArr), tw.Text); + } + } + + [Fact] + public void WriteCharArrayTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(chArr); + Assert.Equal(new string(chArr), tw.Text); + } + } + + [Fact] + public void WriteCharArrayIndexCountTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(chArr, 3, 5); + Assert.Equal(new string(chArr, 3, 5), tw.Text); + } + } + + [Fact] + public void WriteBoolTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(true); + Assert.Equal("True", tw.Text); + + tw.Clear(); + tw.Write(false); + Assert.Equal("False", tw.Text); + } + } + + [Fact] + public void WriteIntTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(int.MinValue); + Assert.Equal(int.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(int.MaxValue); + Assert.Equal(int.MaxValue.ToString(), tw.Text); + } + } + + [Fact] + public void WriteUIntTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(uint.MinValue); + Assert.Equal(uint.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(uint.MaxValue); + Assert.Equal(uint.MaxValue.ToString(), tw.Text); + } + } + + [Fact] + public void WriteLongTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(long.MinValue); + Assert.Equal(long.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(long.MaxValue); + Assert.Equal(long.MaxValue.ToString(), tw.Text); + } + } + + [Fact] + public void WriteULongTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(ulong.MinValue); + Assert.Equal(ulong.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(ulong.MaxValue); + Assert.Equal(ulong.MaxValue.ToString(), tw.Text); + + } + } + + [Fact] + public void WriteFloatTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(float.MinValue); + Assert.Equal(float.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(float.MaxValue); + Assert.Equal(float.MaxValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(float.NaN); + Assert.Equal(float.NaN.ToString(), tw.Text); + } + } + + [Fact] + public void WriteDoubleTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(double.MinValue); + Assert.Equal(double.MinValue.ToString(), tw.Text); + tw.Clear(); + + tw.Write(double.MaxValue); + Assert.Equal(double.MaxValue.ToString(), tw.Text); + tw.Clear(); + + tw.Write(double.NaN); + Assert.Equal(double.NaN.ToString(), tw.Text); + tw.Clear(); + } + } + + [Fact] + public void WriteDecimalTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(decimal.MinValue); + Assert.Equal(decimal.MinValue.ToString(), tw.Text); + + tw.Clear(); + tw.Write(decimal.MaxValue); + Assert.Equal(decimal.MaxValue.ToString(), tw.Text); + } + } + + [Fact] + public void WriteStringTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(new string(GetCharArray())); + Assert.Equal(new string(GetCharArray()), tw.Text); + } + } + + [Fact] + public void WriteObjectTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(FirstObject); + Assert.Equal(FirstObject.ToString(), tw.Text); + } + } + + [Fact] + public void WriteStringObjectTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(FormatStringOneObject, FirstObject); + Assert.Equal(String.Format(FormatStringOneObject, FirstObject), tw.Text); + } + } + + [Fact] + public void WriteStringTwoObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(FormatStringTwoObjects, FirstObject, SecondObject); + Assert.Equal(String.Format(FormatStringTwoObjects, FirstObject, SecondObject), tw.Text); + } + } + + [Fact] + public void WriteStringThreeObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(FormatStringThreeObjects, FirstObject, SecondObject, ThirdObject); + Assert.Equal(String.Format(FormatStringThreeObjects, FirstObject, SecondObject, ThirdObject), tw.Text); + } + } + + [Fact] + public void writeStringMultipleObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.Write(FormatStringMultipleObjects, MultipleObjects); + Assert.Equal(String.Format(FormatStringMultipleObjects, MultipleObjects), tw.Text); + } + } + + #endregion + + #region WriteLine Overloads + + [Fact] + public void WriteLineTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(); + Assert.Equal(tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineCharTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + for (int count = 0; count < chArr.Length; ++count) + { + tw.WriteLine(chArr[count]); + } + Assert.Equal(string.Join(tw.NewLine, chArr.Select(ch => ch.ToString()).ToArray()) + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineCharArrayTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(chArr); + Assert.Equal(new string(chArr) + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineCharArrayIndexCountTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(chArr, 3, 5); + Assert.Equal(new string(chArr, 3, 5) + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineBoolTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(true); + Assert.Equal("True" + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(false); + Assert.Equal("False" + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineIntTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(int.MinValue); + Assert.Equal(int.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(int.MaxValue); + Assert.Equal(int.MaxValue.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineUIntTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(uint.MinValue); + Assert.Equal(uint.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(uint.MaxValue); + Assert.Equal(uint.MaxValue.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineLongTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(long.MinValue); + Assert.Equal(long.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(long.MaxValue); + Assert.Equal(long.MaxValue.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineULongTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(ulong.MinValue); + Assert.Equal(ulong.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(ulong.MaxValue); + Assert.Equal(ulong.MaxValue.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineFloatTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(float.MinValue); + Assert.Equal(float.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(float.MaxValue); + Assert.Equal(float.MaxValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(float.NaN); + Assert.Equal(float.NaN.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineDoubleTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(double.MinValue); + Assert.Equal(double.MinValue.ToString() + tw.NewLine, tw.Text); + tw.Clear(); + + tw.WriteLine(double.MaxValue); + Assert.Equal(double.MaxValue.ToString() + tw.NewLine, tw.Text); + tw.Clear(); + + tw.WriteLine(double.NaN); + Assert.Equal(double.NaN.ToString() + tw.NewLine, tw.Text); + tw.Clear(); + } + } + + [Fact] + public void WriteLineDecimalTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(decimal.MinValue); + Assert.Equal(decimal.MinValue.ToString() + tw.NewLine, tw.Text); + + tw.Clear(); + tw.WriteLine(decimal.MaxValue); + Assert.Equal(decimal.MaxValue.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineStringTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(new string(GetCharArray())); + Assert.Equal(new string(GetCharArray()) + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineObjectTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(FirstObject); + Assert.Equal(FirstObject.ToString() + tw.NewLine, tw.Text); + } + } + + [Fact] + public void WriteLineStringObjectTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(FormatStringOneObject, FirstObject); + Assert.Equal(String.Format(FormatStringOneObject + tw.NewLine, FirstObject), tw.Text); + } + } + + [Fact] + public void WriteLineStringTwoObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(FormatStringTwoObjects, FirstObject, SecondObject); + Assert.Equal(String.Format(FormatStringTwoObjects + tw.NewLine, FirstObject, SecondObject), tw.Text); + } + } + + [Fact] + public void WriteLineStringThreeObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(FormatStringThreeObjects, FirstObject, SecondObject, ThirdObject); + Assert.Equal(String.Format(FormatStringThreeObjects + tw.NewLine, FirstObject, SecondObject, ThirdObject), tw.Text); + } + } + + [Fact] + public void WriteLineStringMultipleObjectsTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + tw.WriteLine(FormatStringMultipleObjects, MultipleObjects); + Assert.Equal(String.Format(FormatStringMultipleObjects + tw.NewLine, MultipleObjects), tw.Text); + } + } + + #endregion + + #region Write Async Overloads + + [Fact] + public async void WriteAsyncCharTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + await tw.WriteAsync('a'); + Assert.Equal("a", tw.Text); + } + } + + [Fact] + public async void WriteAsyncStringTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + var toWrite = new string(GetCharArray()); + await tw.WriteAsync(toWrite); + Assert.Equal(toWrite, tw.Text); + } + } + + [Fact] + public async void WriteAsyncCharArrayIndexCountTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + await tw.WriteAsync(chArr, 3, 5); + Assert.Equal(new string(chArr, 3, 5), tw.Text); + } + } + + #endregion + + #region WriteLineAsync Overloads + + [Fact] + public async void WriteLineAsyncTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + await tw.WriteLineAsync(); + Assert.Equal(tw.NewLine, tw.Text); + } + } + + [Fact] + public async void WriteLineAsyncCharTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + await tw.WriteLineAsync('a'); + Assert.Equal("a" + tw.NewLine, tw.Text); + } + } + + [Fact] + public async void WriteLineAsyncStringTest() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + var toWrite = new string(GetCharArray()); + await tw.WriteLineAsync(toWrite); + Assert.Equal(toWrite + tw.NewLine, tw.Text); + } + } + + [Fact] + public async void WriteLineAsyncCharArrayIndexCount() + { + using (CharArrayTextWriter tw = GetTextWriter()) + { + char[] chArr = GetCharArray(); + await tw.WriteLineAsync(chArr, 3, 5); + Assert.Equal(new string(chArr, 3, 5) + tw.NewLine, tw.Text); + } + } + + #endregion + } +} diff --git a/src/System.IO/tests/TextWriter/TextWriterTests.netcoreapp.cs b/src/System.IO/tests/TextWriter/TextWriterTests.netcoreapp.cs new file mode 100644 index 000000000000..a44fb5f67f69 --- /dev/null +++ b/src/System.IO/tests/TextWriter/TextWriterTests.netcoreapp.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace System.IO.Tests +{ + public partial class TextWriterTests + { + [Fact] + public void WriteCharSpanTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + var rs = new ReadOnlySpan(chArr, 4, 6); + tw.Write(rs); + Assert.Equal(new string(rs), tw.Text); + } + } + + [Fact] + public void WriteLineCharSpanTest() + { + char[] chArr = GetCharArray(); + using (CharArrayTextWriter tw = GetTextWriter()) + { + var rs = new ReadOnlySpan(chArr, 4, 6); + tw.WriteLine(rs); + Assert.Equal(new string(rs) + tw.NewLine, tw.Text); + } + } + } +} diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs index e479c47e0eb4..d43fc5722f07 100644 --- a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs +++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs @@ -1469,8 +1469,10 @@ protected virtual void Dispose(bool disposing) { } public virtual int Peek() { throw null; } public virtual int Read() { throw null; } public virtual int Read(char[] buffer, int index, int count) { throw null; } + public virtual int Read(Span destination) { throw null; } public virtual System.Threading.Tasks.Task ReadAsync(char[] buffer, int index, int count) { throw null; } public virtual int ReadBlock(char[] buffer, int index, int count) { throw null; } + public virtual int ReadBlock(Span destination) { throw null; } public virtual System.Threading.Tasks.Task ReadBlockAsync(char[] buffer, int index, int count) { throw null; } public virtual string ReadLine() { throw null; } public virtual System.Threading.Tasks.Task ReadLineAsync() { throw null; } @@ -1512,6 +1514,7 @@ public virtual void Write(string format, params object[] arg) { } public virtual void Write(uint value) { } [System.CLSCompliantAttribute(false)] public virtual void Write(ulong value) { } + public virtual void Write(ReadOnlySpan source) { } public virtual System.Threading.Tasks.Task WriteAsync(char value) { throw null; } public System.Threading.Tasks.Task WriteAsync(char[] buffer) { throw null; } public virtual System.Threading.Tasks.Task WriteAsync(char[] buffer, int index, int count) { throw null; } @@ -1536,6 +1539,7 @@ public virtual void WriteLine(string format, params object[] arg) { } public virtual void WriteLine(uint value) { } [System.CLSCompliantAttribute(false)] public virtual void WriteLine(ulong value) { } + public virtual void WriteLine(ReadOnlySpan source) { } public virtual System.Threading.Tasks.Task WriteLineAsync() { throw null; } public virtual System.Threading.Tasks.Task WriteLineAsync(char value) { throw null; } public System.Threading.Tasks.Task WriteLineAsync(char[] buffer) { throw null; } diff --git a/src/System.Runtime.Extensions/src/Resources/Strings.resx b/src/System.Runtime.Extensions/src/Resources/Strings.resx index 7dfe4e5ee10c..1ef8c2471b3a 100644 --- a/src/System.Runtime.Extensions/src/Resources/Strings.resx +++ b/src/System.Runtime.Extensions/src/Resources/Strings.resx @@ -1,5 +1,64 @@  + @@ -367,4 +426,7 @@ AppDomain resource monitoring is not supported on this platform. - + + Stream was too long. + + \ No newline at end of file diff --git a/src/System.Runtime.Extensions/src/System/IO/TextReader.cs b/src/System.Runtime.Extensions/src/System/IO/TextReader.cs index a24346120337..d7825127a19c 100644 --- a/src/System.Runtime.Extensions/src/System/IO/TextReader.cs +++ b/src/System.Runtime.Extensions/src/System/IO/TextReader.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; +using System.Buffers; namespace System.IO { @@ -100,6 +101,30 @@ public virtual int Read(char[] buffer, int index, int count) return n; } + // Reads a span of characters. This method will read up to + // count characters from this TextReader into the + // span of characters Returns the actual number of characters read. + // + public virtual int Read(Span destination) + { + char[] buffer = ArrayPool.Shared.Rent(destination.Length); + + try + { + int numRead = Read(buffer, 0, destination.Length); + if ((uint)numRead > destination.Length) + { + throw new IOException(SR.IO_StreamTooLong); + } + new Span(buffer, 0, numRead).CopyTo(destination); + return numRead; + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + // Reads all characters from the current position to the end of the // TextReader, and returns them as one string. public virtual string ReadToEnd() @@ -127,6 +152,29 @@ public virtual int ReadBlock(char[] buffer, int index, int count) return n; } + // Blocking version of read for span of characters. Returns only when count + // characters have been read or the end of the file was reached. + // + public virtual int ReadBlock(Span destination) + { + char[] buffer = ArrayPool.Shared.Rent(destination.Length); + + try + { + int numRead = ReadBlock(buffer, 0, destination.Length); + if ((uint)numRead > destination.Length) + { + throw new IOException(SR.IO_StreamTooLong); + } + new Span(buffer, 0, numRead).CopyTo(destination); + return numRead; + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + // Reads a line. A line is defined as a sequence of characters followed by // a carriage return ('\r'), a line feed ('\n'), or a carriage return // immediately followed by a line feed. The resulting string does not diff --git a/src/System.Runtime.Extensions/src/System/IO/TextWriter.cs b/src/System.Runtime.Extensions/src/System/IO/TextWriter.cs index ee0142115e98..5faee4f3220c 100644 --- a/src/System.Runtime.Extensions/src/System/IO/TextWriter.cs +++ b/src/System.Runtime.Extensions/src/System/IO/TextWriter.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Threading.Tasks; using System.Runtime.CompilerServices; +using System.Buffers; namespace System.IO { @@ -161,6 +162,23 @@ public virtual void Write(char[] buffer, int index, int count) for (int i = 0; i < count; i++) Write(buffer[index + i]); } + // Writes a span of characters to the text stream. + // + public virtual void Write(ReadOnlySpan source) + { + char[] buffer = ArrayPool.Shared.Rent(source.Length); + + try + { + source.CopyTo(new Span(buffer)); + Write(buffer, 0, source.Length); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + // Writes the text representation of a boolean to the text stream. This // method outputs either Boolean.TrueString or Boolean.FalseString. // @@ -328,6 +346,21 @@ public virtual void WriteLine(char[] buffer, int index, int count) WriteLine(); } + public virtual void WriteLine(ReadOnlySpan source) + { + char[] buffer = ArrayPool.Shared.Rent(source.Length); + + try + { + source.CopyTo(new Span(buffer)); + WriteLine(buffer, 0, source.Length); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + // Writes the text representation of a boolean followed by a line // terminator to the text stream. //