Fixed hints and warnings. Many remain because they're unsupported by various .NET versions declared in .csproj.
This commit is contained in:
parent
117df18c56
commit
e62bf46f75
59
readme.md
59
readme.md
@ -137,9 +137,50 @@ As described above, this is a simple interface that wraps an output destination.
|
||||
#### ListOutputTarget
|
||||
This wraps an IList<string> and will store data to it when Output() is called. This is useful for unit testing or other creative workarounds.
|
||||
|
||||
*Example:*
|
||||
|
||||
```csharp
|
||||
// Writes to the console.
|
||||
List<string> expected = ["1", "2", "3"];
|
||||
List<string> actual = [];
|
||||
IOutputTarget outputWriter = new ListOutputTarget(actual);
|
||||
|
||||
for(int j = 1; j <= 3; j++)
|
||||
outputWriter(j.ToString());
|
||||
|
||||
actual.ShouldBe(expected);
|
||||
```
|
||||
|
||||
#### ConsoleOutputTarget
|
||||
This writes data to the StdOut device when Output() is called.
|
||||
|
||||
*Example:*
|
||||
|
||||
```csharp
|
||||
// Writes to the console.
|
||||
IOutputTarget consoleTarget = new ConsoleOutputTarget();
|
||||
consoleTarget.Output("Super Califragilistic Expiyallydocious!");
|
||||
```
|
||||
|
||||
#### ProcessedConsoleOutputTarget
|
||||
This class inherits `ConsoleOutputTarget` but adds a custom function to transform the text befor being output. This is very similar to the `AnonOutputTarget` except that it is specific to console output and it only provides projection / transforms, not filtering.
|
||||
|
||||
*Example:*
|
||||
|
||||
```csharp
|
||||
// Writes to the console.
|
||||
IOutputTarget formattedTarget = new ProcessedConsoleOutputTarget(static s =>
|
||||
{
|
||||
// This class does not directly perform its writes.
|
||||
// That means it can transform the input but cannot filter it.
|
||||
int maxLen = 15;
|
||||
string truncatedString = s.Substring(0, Math.Min(s.Length, maxLen))
|
||||
return $"[{DateTime.Now}] {truncatedString}";
|
||||
};
|
||||
|
||||
formattedTarget.Output("Super Califragilistic Expiyallydocious!");
|
||||
```
|
||||
|
||||
#### AnonOutputTarget
|
||||
This will take an Action<string> parameter in its constructor to instruct it how to behave when Output() is called. This implementation can easily be used to fulfill any output need. Other obvious OutputTarget types (e.g. TextFileOutputTarget) have not been implemented because this method is simpler to use than those classes would be and it gives you more control than you would have with those classes. For example, you can control the access parameters when opening a text file.
|
||||
|
||||
@ -147,15 +188,21 @@ This will take an Action<string> parameter in its constructor to instruct
|
||||
|
||||
```csharp
|
||||
// Writes to the console.
|
||||
IOutputTarget target = new AnonOutputTarget(static s =>
|
||||
IOutputTarget errorLogger = new AnonOutputTarget(static s =>
|
||||
{
|
||||
int maxLen = 15;
|
||||
string truncatedString = s.Substring(0, Math.Min(s.Length, maxLen))
|
||||
string logLine = $"[{DateTime.Now}] {truncatedString}";
|
||||
Console.WriteLine(logLine);
|
||||
// Unlike ProcessedConsoleOutputTarget, the AnonOutputTarget
|
||||
// class is responsible for its own writes. This means it can
|
||||
// filter and transform its output.
|
||||
if (s.ToLower().Contains("error"))
|
||||
{
|
||||
int maxLen = 15;
|
||||
string truncatedString = s.Substring(0, Math.Min(s.Length, maxLen))
|
||||
string logLine = $"[{DateTime.Now}] {truncatedString}";
|
||||
Console.WriteLine(logLine);
|
||||
}
|
||||
};
|
||||
|
||||
target.Output("Super Califragilistic Expiyallydocious!");
|
||||
errorLogger.Output("An error occurred while trying to connect to ...");
|
||||
```
|
||||
|
||||
### Code Usage
|
||||
|
||||
@ -4,12 +4,9 @@ namespace DotnetStandardStreams
|
||||
{
|
||||
public class AnonOutputTarget : IOutputTarget
|
||||
{
|
||||
private readonly Action<string> outputProc;
|
||||
private readonly Action<string> _outputProc;
|
||||
|
||||
public AnonOutputTarget(Action<string> outputProc)
|
||||
{
|
||||
this.outputProc = outputProc;
|
||||
}
|
||||
public AnonOutputTarget(Action<string> outputProc) => _outputProc = outputProc;
|
||||
|
||||
public virtual void Close() { }
|
||||
|
||||
@ -17,7 +14,7 @@ namespace DotnetStandardStreams
|
||||
|
||||
public virtual void Output(string line)
|
||||
{
|
||||
outputProc.Invoke(line);
|
||||
_outputProc.Invoke(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,7 @@ namespace DotnetStandardStreams
|
||||
public class ConsoleOutputTarget : IOutputTarget
|
||||
{
|
||||
public virtual void Open() { }
|
||||
public virtual void Output(string line)
|
||||
{
|
||||
Console.WriteLine(line);
|
||||
}
|
||||
public virtual void Output(string line) => Console.WriteLine(line);
|
||||
public virtual void Close() { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,29 +7,24 @@ using System.IO;
|
||||
|
||||
namespace DotnetStandardStreams
|
||||
{
|
||||
|
||||
// THE GOAL:
|
||||
// READ will return NULL when you read after the last line. This is fine.
|
||||
// EOF will return TRUE when you read the last line.
|
||||
// We want EOF to return FALSE after you read the last line and TRUE when you read AFTER the last line.
|
||||
public class FileTextSource : ITextSource
|
||||
{
|
||||
protected FileStream? file;
|
||||
protected StreamReader? reader;
|
||||
protected string filename;
|
||||
protected string? lastLineRead = string.Empty; // Do NOT make this null at first.
|
||||
private FileStream? _file;
|
||||
private StreamReader? _reader;
|
||||
private readonly string _filename;
|
||||
private string? _lastLineRead = string.Empty; // Do NOT make this null at first.
|
||||
|
||||
public FileTextSource(string filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
file = null;
|
||||
reader = null;
|
||||
this._filename = filename;
|
||||
_file = null;
|
||||
_reader = null;
|
||||
}
|
||||
|
||||
public virtual void Open()
|
||||
{
|
||||
file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
reader = new StreamReader(file);
|
||||
_file = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
_reader = new StreamReader(_file);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> ReadAll()
|
||||
@ -48,8 +43,8 @@ namespace DotnetStandardStreams
|
||||
{
|
||||
if (!Eof())
|
||||
{
|
||||
string? result = reader?.ReadLine();
|
||||
lastLineRead = result;
|
||||
string? result = _reader?.ReadLine();
|
||||
_lastLineRead = result;
|
||||
|
||||
return result ?? string.Empty;
|
||||
}
|
||||
@ -57,29 +52,17 @@ namespace DotnetStandardStreams
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public virtual bool Eof()
|
||||
{
|
||||
//return reader?.EndOfStream ?? true;
|
||||
return lastLineRead == null;
|
||||
}
|
||||
public virtual bool Eof() => _lastLineRead == null;
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Uh... why are we calling Flush() on a file-read operation?
|
||||
file?.Flush();
|
||||
_file?.Close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
file?.Close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
file?.Dispose();
|
||||
}
|
||||
_file?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,22 +9,16 @@ namespace DotnetStandardStreams
|
||||
public class ListOutputTarget : IOutputTarget
|
||||
{
|
||||
public IList<string> OutputList { get; }
|
||||
public ListOutputTarget(IList<string> outputList)
|
||||
{
|
||||
this.OutputList = outputList;
|
||||
}
|
||||
|
||||
public virtual void Open()
|
||||
{
|
||||
}
|
||||
public ListOutputTarget(IList<string> outputList) => OutputList = outputList;
|
||||
|
||||
public virtual void Open() { }
|
||||
|
||||
public virtual void Output(string text)
|
||||
{
|
||||
OutputList.Add(text);
|
||||
}
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
}
|
||||
public virtual void Close() { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,51 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotnetStandardStreams
|
||||
{
|
||||
public class ListTextSource : ITextSource
|
||||
{
|
||||
private bool isEof;
|
||||
private readonly IEnumerable<string> source;
|
||||
private IEnumerator<string>? enumerator;
|
||||
private bool _isEof;
|
||||
private readonly IEnumerable<string> _source;
|
||||
private IEnumerator<string>? _enumerator = null;
|
||||
|
||||
public ListTextSource(IEnumerable<string> source)
|
||||
{
|
||||
this.source = source;
|
||||
enumerator = null;
|
||||
//firstIsRead = false;
|
||||
//nextLine = string.Empty;
|
||||
}
|
||||
public ListTextSource(IEnumerable<string> source) => _source = source;
|
||||
|
||||
public virtual void Open() { }
|
||||
|
||||
public virtual IEnumerable<string> ReadAll() => source.AsEnumerable();
|
||||
public virtual IEnumerable<string> ReadAll() => _source.AsEnumerable();
|
||||
|
||||
public virtual string Read()
|
||||
{
|
||||
if (enumerator == null)
|
||||
enumerator = source.GetEnumerator();
|
||||
_enumerator ??= _source.GetEnumerator();
|
||||
|
||||
//string thisLine;
|
||||
if (!_isEof)
|
||||
_isEof = !_enumerator.MoveNext();
|
||||
|
||||
if (!isEof)
|
||||
isEof = !enumerator.MoveNext();
|
||||
|
||||
if (!isEof)
|
||||
return enumerator.Current;
|
||||
else
|
||||
return string.Empty;
|
||||
return !_isEof
|
||||
? _enumerator.Current
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
public virtual bool Eof() => isEof;
|
||||
public virtual bool Eof() => _isEof;
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
enumerator = null;
|
||||
isEof = false;
|
||||
_enumerator = null;
|
||||
_isEof = false;
|
||||
}
|
||||
|
||||
public void ReadAll(Action<string> readAction)
|
||||
|
||||
@ -1,25 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotnetStandardStreams
|
||||
{
|
||||
public class ProcessedConsoleOutputTarget : ConsoleOutputTarget
|
||||
{
|
||||
protected Func<string, string> processorFunc;
|
||||
public ProcessedConsoleOutputTarget(Func<string, string> processorFunc) : base()
|
||||
{
|
||||
if (processorFunc != null)
|
||||
this.processorFunc = processorFunc;
|
||||
else
|
||||
this.processorFunc = line => line;
|
||||
}
|
||||
private readonly Func<string, string> _processorFunc;
|
||||
|
||||
public ProcessedConsoleOutputTarget(Func<string, string> processorFunc) => _processorFunc = processorFunc;
|
||||
|
||||
public override void Output(string line)
|
||||
{
|
||||
string output = processorFunc?.Invoke(line) ?? string.Empty;
|
||||
string output = _processorFunc(line);
|
||||
Console.WriteLine(output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotnetStandardStreams
|
||||
{
|
||||
public class StdInTextSource : ITextSource
|
||||
{
|
||||
protected bool isEof;
|
||||
private bool _isEof;
|
||||
|
||||
public virtual void Open()
|
||||
{
|
||||
isEof = false;
|
||||
_isEof = false;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> ReadAll()
|
||||
@ -33,7 +30,7 @@ namespace DotnetStandardStreams
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
isEof = true;
|
||||
_isEof = true;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
@ -41,7 +38,7 @@ namespace DotnetStandardStreams
|
||||
return s;
|
||||
}
|
||||
|
||||
public virtual bool Eof() => isEof;
|
||||
public virtual bool Eof() => _isEof;
|
||||
|
||||
public virtual void Close() { }
|
||||
|
||||
|
||||
@ -1,297 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotnetStandardStreams
|
||||
{
|
||||
//public interface ITextSource
|
||||
//{
|
||||
// void Open();
|
||||
// IEnumerable<string> ReadAll();
|
||||
// string Read();
|
||||
// bool Eof();
|
||||
// void Close();
|
||||
//}
|
||||
|
||||
//public class StdInTextSource : ITextSource
|
||||
//{
|
||||
// protected bool isEof;
|
||||
|
||||
// public virtual void Open()
|
||||
// {
|
||||
// isEof = false;
|
||||
// }
|
||||
|
||||
// public virtual IEnumerable<string> ReadAll()
|
||||
// {
|
||||
// string? s = Console.ReadLine();
|
||||
// while (s != null)
|
||||
// {
|
||||
// yield return s;
|
||||
// s = Console.ReadLine();
|
||||
// }
|
||||
// isEof = true;
|
||||
// }
|
||||
|
||||
// public virtual string Read()
|
||||
// {
|
||||
// string? s = Console.ReadLine();
|
||||
// if (s == null)
|
||||
// {
|
||||
// isEof = true;
|
||||
// return string.Empty;
|
||||
// }
|
||||
// else
|
||||
// return s;
|
||||
// }
|
||||
|
||||
// public virtual bool Eof() => isEof;
|
||||
|
||||
// public virtual void Close()
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class FileTextSource : ITextSource
|
||||
//{
|
||||
// protected FileStream? file;
|
||||
// protected StreamReader? reader;
|
||||
// protected string filename;
|
||||
|
||||
// public FileTextSource(string filename)
|
||||
// {
|
||||
// this.filename = filename;
|
||||
// file = null;
|
||||
// reader = null;
|
||||
// }
|
||||
|
||||
// public virtual void Open()
|
||||
// {
|
||||
// file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
// reader = new StreamReader(file);
|
||||
// }
|
||||
|
||||
// public virtual IEnumerable<string> ReadAll()
|
||||
// {
|
||||
// string? line = reader?.ReadLine();
|
||||
// while (line != null)
|
||||
// {
|
||||
// yield return line;
|
||||
// line = reader?.ReadLine();
|
||||
// }
|
||||
// }
|
||||
|
||||
// public virtual string Read()
|
||||
// {
|
||||
// if (!Eof())
|
||||
// return reader?.ReadLine() ?? string.Empty;
|
||||
// else
|
||||
// return string.Empty;
|
||||
// }
|
||||
|
||||
// public virtual bool Eof()
|
||||
// {
|
||||
// return reader?.EndOfStream ?? true;
|
||||
// }
|
||||
|
||||
// public virtual void Close()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// file?.Flush();
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// file?.Close();
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// file?.Dispose();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class ListTextSource : ITextSource
|
||||
//{
|
||||
// private bool isEof;
|
||||
// private readonly IEnumerable<string> source;
|
||||
// private IEnumerator<string>? enumerator;
|
||||
// //private string lastValue;
|
||||
// private bool firstIsRead;
|
||||
// private string nextLine;
|
||||
// public ListTextSource(IEnumerable<string> source)
|
||||
// {
|
||||
// this.source = source;
|
||||
// enumerator = null;
|
||||
// firstIsRead = false;
|
||||
// nextLine = string.Empty;
|
||||
// }
|
||||
|
||||
// public virtual void Open()
|
||||
// {
|
||||
// }
|
||||
|
||||
// public virtual IEnumerable<string> ReadAll()
|
||||
// {
|
||||
// return source.AsEnumerable();
|
||||
// }
|
||||
|
||||
// public virtual string Read()
|
||||
// {
|
||||
// if (enumerator == null)
|
||||
// enumerator = source.GetEnumerator();
|
||||
|
||||
// string thisLine;
|
||||
// if (!firstIsRead)
|
||||
// {
|
||||
// // Read the first, put it in the "last" buffer.
|
||||
// isEof = !enumerator.MoveNext();
|
||||
// nextLine = enumerator.Current;
|
||||
// firstIsRead = true;
|
||||
// }
|
||||
|
||||
// thisLine = nextLine;
|
||||
|
||||
// if (!isEof)
|
||||
// {
|
||||
// isEof = !enumerator.MoveNext();
|
||||
// if (!isEof)
|
||||
// nextLine = enumerator.Current;
|
||||
// else
|
||||
// nextLine = string.Empty;
|
||||
|
||||
// }
|
||||
|
||||
// return thisLine;
|
||||
// }
|
||||
|
||||
// public virtual bool Eof() => isEof;
|
||||
|
||||
// public virtual void Close()
|
||||
// {
|
||||
// enumerator = null;
|
||||
// isEof = false;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public interface IOutputTarget
|
||||
//{
|
||||
// void Open();
|
||||
// void Output(string line);
|
||||
// void Close();
|
||||
//}
|
||||
|
||||
//public class ConsoleOutputTarget : IOutputTarget
|
||||
//{
|
||||
// public virtual void Open()
|
||||
// {
|
||||
// }
|
||||
// public virtual void Output(string line)
|
||||
// {
|
||||
// Console.WriteLine(line);
|
||||
// }
|
||||
// public virtual void Close()
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class ProcessedConsoleOutputTarget : ConsoleOutputTarget
|
||||
//{
|
||||
// protected Func<string, string> processorFunc;
|
||||
// public ProcessedConsoleOutputTarget(Func<string, string> processorFunc) : base()
|
||||
// {
|
||||
// if (processorFunc != null)
|
||||
// this.processorFunc = processorFunc;
|
||||
// else
|
||||
// this.processorFunc = line => line;
|
||||
// }
|
||||
|
||||
// public override void Output(string line)
|
||||
// {
|
||||
// string output = processorFunc?.Invoke(line) ?? string.Empty;
|
||||
// Console.WriteLine(output);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class ListOutputTarget : IOutputTarget
|
||||
//{
|
||||
// public IList<string> OutputList { get; }
|
||||
// public ListOutputTarget(IList<string> outputList)
|
||||
// {
|
||||
// this.OutputList = outputList;
|
||||
// }
|
||||
|
||||
// public virtual void Open()
|
||||
// {
|
||||
// }
|
||||
|
||||
// public virtual void Output(string text)
|
||||
// {
|
||||
// OutputList.Add(text);
|
||||
// }
|
||||
|
||||
// public virtual void Close()
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class BytesReadEventArgs
|
||||
//{
|
||||
// public byte[] Data { get; }
|
||||
// public int Size { get; }
|
||||
// public BytesReadEventArgs(byte[] data, int size)
|
||||
// {
|
||||
// this.Data = data;
|
||||
// this.Size = size;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public delegate void BytesReadEventHandler(object sender, BytesReadEventArgs e);
|
||||
|
||||
//public class BinaryStdinReader
|
||||
//{
|
||||
// protected readonly Action<byte[], int> dataReceiverProc;
|
||||
// protected readonly Action<int> doneProc;
|
||||
// public event BytesReadEventHandler OnBytesRead;
|
||||
// public event EventHandler OnDone;
|
||||
// public BinaryStdinReader(Action<byte[], int> dataReceiverProc, Action<int> doneProc)
|
||||
// {
|
||||
// this.dataReceiverProc = dataReceiverProc;
|
||||
// this.doneProc = doneProc;
|
||||
// }
|
||||
|
||||
// public BinaryStdinReader()
|
||||
// {
|
||||
// }
|
||||
|
||||
// public void ReadBytes(Action<byte[], int> receiverProc, Action<int> doneProc)
|
||||
// {
|
||||
// using System.IO.Stream stdinStream = System.Console.OpenStandardInput();
|
||||
|
||||
// int totalBytesRead = 0;
|
||||
// int bufferSize = 2048;
|
||||
// byte[] buffer = new byte[bufferSize];
|
||||
// int bytesRead = stdinStream.Read(buffer, 0, bufferSize);
|
||||
// while (bytesRead > 0)
|
||||
// {
|
||||
// OnBytesRead?.Invoke(this, new BytesReadEventArgs(buffer, bytesRead));
|
||||
// receiverProc?.Invoke(buffer, bytesRead);
|
||||
|
||||
// if (bytesRead < bufferSize)
|
||||
// break;
|
||||
|
||||
// bytesRead = stdinStream.Read(buffer, 0, bufferSize);
|
||||
// totalBytesRead += bytesRead;
|
||||
// }
|
||||
|
||||
// OnDone?.Invoke(this, new EventArgs());
|
||||
// doneProc?.Invoke(totalBytesRead);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DotnetStandardStreams;
|
||||
using DotnetStandardStreams;
|
||||
using Console = System.Console;
|
||||
|
||||
namespace DotnetStandardStreamsApp;
|
||||
@ -64,10 +60,8 @@ public static class Program
|
||||
source.Open();
|
||||
target.Open();
|
||||
|
||||
for (string? line = source.Read(); !source.Eof(); line = source.Read())
|
||||
{
|
||||
for (string line = source.Read(); !source.Eof(); line = source.Read())
|
||||
target.Output(line);
|
||||
}
|
||||
|
||||
target.Close();
|
||||
source.Close();
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using DotnetStandardStreams;
|
||||
|
||||
namespace DotnetStandardStreamsTests;
|
||||
@ -9,14 +8,14 @@ public class AnonOutputTargetTests
|
||||
[Fact]
|
||||
public void CanConstruct()
|
||||
{
|
||||
_ = new AnonOutputTarget(static s => { });
|
||||
_ = new AnonOutputTarget(static _ => { });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritesEachLine()
|
||||
{
|
||||
List<string> expected = ["1", "2", "", "4", "5", "6", "7", "8", "9", "10"];
|
||||
List<string> actual = new();
|
||||
List<string> actual = [];
|
||||
IOutputTarget target = new AnonOutputTarget(s => actual.Add(s));
|
||||
|
||||
foreach (string s in expected)
|
||||
@ -30,7 +29,7 @@ public class AnonOutputTargetTests
|
||||
{
|
||||
List<string> input = ["1", "2", "", "4", "5", "6", "7", "8", "9", "10"];
|
||||
List<string> expected = ["2", "4", "6", "8", "10"];
|
||||
List<string> actual = new();
|
||||
List<string> actual = [];
|
||||
|
||||
IOutputTarget target = new AnonOutputTarget(s =>
|
||||
{
|
||||
|
||||
@ -1,29 +1,27 @@
|
||||
using System;
|
||||
using DotnetStandardStreams;
|
||||
using DotnetStandardStreams;
|
||||
using DotnetStandardStreamsTests.Testables;
|
||||
|
||||
namespace DotnetStandardStreamsTests
|
||||
namespace DotnetStandardStreamsTests;
|
||||
|
||||
public class ConsoleOutputTargetTests
|
||||
{
|
||||
public class ConsoleOutputTargetTests
|
||||
[Fact]
|
||||
public void WritesToOutputStream()
|
||||
{
|
||||
[Fact]
|
||||
public void WritesToOutputStream()
|
||||
{
|
||||
ListWriter writer = new();
|
||||
IOutputTarget outputTarget = new TestableConsoleOutputTarget(writer);
|
||||
ListWriter writer = new();
|
||||
IOutputTarget outputTarget = new TestableConsoleOutputTarget(writer);
|
||||
|
||||
outputTarget.Open();
|
||||
outputTarget.Output("1");
|
||||
outputTarget.Output("2");
|
||||
outputTarget.Output("");
|
||||
outputTarget.Output("3");
|
||||
outputTarget.Close();
|
||||
outputTarget.Open();
|
||||
outputTarget.Output("1");
|
||||
outputTarget.Output("2");
|
||||
outputTarget.Output("");
|
||||
outputTarget.Output("3");
|
||||
outputTarget.Close();
|
||||
|
||||
writer.Lines.Count.ShouldBe(4);
|
||||
writer.Lines[0].ShouldBe("1");
|
||||
writer.Lines[1].ShouldBe("2");
|
||||
writer.Lines[2].ShouldBe(string.Empty);
|
||||
writer.Lines[3].ShouldBe("3");
|
||||
}
|
||||
writer.Lines.Count.ShouldBe(4);
|
||||
writer.Lines[0].ShouldBe("1");
|
||||
writer.Lines[1].ShouldBe("2");
|
||||
writer.Lines[2].ShouldBe(string.Empty);
|
||||
writer.Lines[3].ShouldBe("3");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Shouldly" Version="4.0.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
|
||||
@ -3,42 +3,41 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DotnetStandardStreams;
|
||||
using DotnetStandardStreamsTests.Testables;
|
||||
|
||||
namespace DotnetStandardStreamsTests;
|
||||
|
||||
public class FileTextSourceTests
|
||||
{
|
||||
private string tempFilename { get; set; }
|
||||
private string _tempFilename = string.Empty;
|
||||
|
||||
private void CleanupTempFile()
|
||||
{
|
||||
if (File.Exists(tempFilename))
|
||||
File.Delete(tempFilename);
|
||||
if (File.Exists(_tempFilename))
|
||||
File.Delete(_tempFilename);
|
||||
}
|
||||
|
||||
private void CreateInputFile()
|
||||
{
|
||||
tempFilename = System.IO.Path.GetTempFileName();
|
||||
_tempFilename = Path.GetTempFileName();
|
||||
const string content = "1\r\n2\r\n\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n";
|
||||
CleanupTempFile();
|
||||
File.WriteAllText(tempFilename, content);
|
||||
File.WriteAllText(_tempFilename, content);
|
||||
}
|
||||
|
||||
private void CreateEmptyInputFile()
|
||||
{
|
||||
tempFilename = System.IO.Path.GetTempFileName();
|
||||
_tempFilename = Path.GetTempFileName();
|
||||
CleanupTempFile();
|
||||
File.WriteAllText(tempFilename, string.Empty);
|
||||
File.WriteAllText(_tempFilename, string.Empty);
|
||||
}
|
||||
|
||||
public void WrapFileTest(Action<ITextSource> testCode, Action? explicitSourceCreation = null)
|
||||
private void WrapFileTest(Action<ITextSource> testCode, Action? explicitSourceCreation = null)
|
||||
{
|
||||
explicitSourceCreation = explicitSourceCreation ?? CreateInputFile;
|
||||
explicitSourceCreation ??= CreateInputFile;
|
||||
explicitSourceCreation();
|
||||
try
|
||||
{
|
||||
ITextSource source = new FileTextSource(tempFilename);
|
||||
ITextSource source = new FileTextSource(_tempFilename);
|
||||
source.Open();
|
||||
try
|
||||
{
|
||||
@ -112,7 +111,7 @@ public class FileTextSourceTests
|
||||
textSource.Eof().ShouldBe(false);
|
||||
s.ShouldBe("10");
|
||||
|
||||
s = textSource.Read();
|
||||
_ = textSource.Read();
|
||||
textSource.Eof().ShouldBe(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotnetStandardStreams;
|
||||
|
||||
namespace DotnetStandardStreamsTests;
|
||||
|
||||
public class ListOutputTargetTests
|
||||
{
|
||||
[Fact]
|
||||
public void WritesToList()
|
||||
{
|
||||
ListOutputTarget target = new(new List<string>());
|
||||
ListOutputTarget target = new([]);
|
||||
target.Output("1");
|
||||
target.Output("2");
|
||||
target.Output("");
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using DotnetStandardStreams;
|
||||
using DotnetStandardStreams;
|
||||
|
||||
namespace DotnetStandardStreamsTests;
|
||||
|
||||
@ -38,8 +37,7 @@ public class ListTextSourceTests
|
||||
public void ReadsFromEmptyList()
|
||||
{
|
||||
ITextSource reader = new ListTextSource([]);
|
||||
string s0 = reader.Read();
|
||||
//s0.ShouldBeNull();
|
||||
_ = reader.Read();
|
||||
reader.Eof().ShouldBe(true);
|
||||
}
|
||||
}
|
||||
@ -9,19 +9,15 @@ namespace DotnetStandardStreamsTests;
|
||||
|
||||
public class StdInTextSourceTests
|
||||
{
|
||||
private static TextReader CreateStdIn()
|
||||
{
|
||||
return new ListTextReader(new[] { "1", "2", "", "3" });
|
||||
}
|
||||
private static TextReader CreateStdIn() => new ListTextReader(["1", "2", "", "3"]);
|
||||
|
||||
private static TextReader CreateEmptyStdIn() => new ListTextReader([]);
|
||||
|
||||
private static void WrapStdInTest(Action<ITextSource> testCode, TextReader? explicitStdIn = null)
|
||||
{
|
||||
if (explicitStdIn == null)
|
||||
explicitStdIn = CreateStdIn();
|
||||
explicitStdIn ??= CreateStdIn();
|
||||
|
||||
var oldInputReader = System.Console.In;
|
||||
TextReader oldInputReader = System.Console.In;
|
||||
try
|
||||
{
|
||||
System.Console.SetIn(explicitStdIn);
|
||||
@ -30,7 +26,7 @@ public class StdInTextSourceTests
|
||||
stdin.Open();
|
||||
try
|
||||
{
|
||||
testCode?.Invoke(stdin);
|
||||
testCode.Invoke(stdin);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -48,7 +44,7 @@ public class StdInTextSourceTests
|
||||
{
|
||||
WrapStdInTest(static stdin =>
|
||||
{
|
||||
var actual = stdin.ReadAll().ToList();
|
||||
List<string> actual = stdin.ReadAll().ToList();
|
||||
actual.Count.ShouldBe(4);
|
||||
actual[0].ShouldBe("1");
|
||||
actual[1].ShouldBe("2");
|
||||
@ -79,7 +75,7 @@ public class StdInTextSourceTests
|
||||
stdin.Eof().ShouldBe(false);
|
||||
s.ShouldBe("3");
|
||||
|
||||
s = stdin.Read();
|
||||
_ = stdin.Read();
|
||||
stdin.Eof().ShouldBe(true);
|
||||
});
|
||||
}
|
||||
@ -90,12 +86,12 @@ public class StdInTextSourceTests
|
||||
WrapStdInTest(static stdin =>
|
||||
{
|
||||
int lineCount = 0;
|
||||
string s = stdin.Read();
|
||||
_ = stdin.Read();
|
||||
|
||||
while (!stdin.Eof())
|
||||
{
|
||||
lineCount++;
|
||||
s = stdin.Read();
|
||||
_ = stdin.Read();
|
||||
}
|
||||
|
||||
lineCount.ShouldBe(4);
|
||||
@ -121,12 +117,12 @@ public class StdInTextSourceTests
|
||||
static stdin =>
|
||||
{
|
||||
int lineCount = 0;
|
||||
string s = stdin.Read();
|
||||
_ = stdin.Read();
|
||||
|
||||
while (!stdin.Eof())
|
||||
{
|
||||
lineCount++;
|
||||
s = stdin.Read();
|
||||
_ = stdin.Read();
|
||||
}
|
||||
|
||||
lineCount.ShouldBe(0);
|
||||
|
||||
@ -1,26 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DotnetStandardStreamsTests.Testables
|
||||
namespace DotnetStandardStreamsTests.Testables;
|
||||
public class ListTextReader : TextReader
|
||||
{
|
||||
public class ListTextReader : TextReader
|
||||
{
|
||||
private readonly IEnumerator<string> enumerator;
|
||||
public ListTextReader(IEnumerable<string> data)
|
||||
{
|
||||
enumerator = data.GetEnumerator();
|
||||
}
|
||||
private readonly IEnumerator<string> _enumerator;
|
||||
|
||||
public override string? ReadLine()
|
||||
{
|
||||
if (enumerator.MoveNext())
|
||||
return enumerator.Current;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public ListTextReader(IEnumerable<string> data) => _enumerator = data.GetEnumerator();
|
||||
|
||||
public override string? ReadLine()
|
||||
=> _enumerator.MoveNext()
|
||||
? _enumerator.Current
|
||||
: null;
|
||||
}
|
||||
|
||||
@ -1,30 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DotnetStandardStreamsTests.Testables
|
||||
namespace DotnetStandardStreamsTests.Testables;
|
||||
|
||||
public class ListWriter : TextWriter
|
||||
{
|
||||
public class ListWriter : TextWriter
|
||||
{
|
||||
public List<string> Lines { get; }
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
public List<string> Lines { get; } = [];
|
||||
|
||||
public ListWriter()
|
||||
{
|
||||
Lines = new();
|
||||
}
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
|
||||
public override void Write(string value)
|
||||
{
|
||||
Lines.Add(value);
|
||||
}
|
||||
public override void Write(string? value) => Lines.Add(value ?? string.Empty);
|
||||
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
Lines.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void WriteLine(string? value) => Lines.Add(value ?? string.Empty);
|
||||
}
|
||||
@ -1,24 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using DotnetStandardStreams;
|
||||
|
||||
namespace DotnetStandardStreamsTests.Testables
|
||||
namespace DotnetStandardStreamsTests.Testables;
|
||||
|
||||
public class TestableConsoleOutputTarget : ConsoleOutputTarget, IDisposable
|
||||
{
|
||||
public class TestableConsoleOutputTarget : ConsoleOutputTarget, IDisposable
|
||||
private readonly TextWriter _previousOutWriter;
|
||||
public TestableConsoleOutputTarget(TextWriter outWriter) : base()
|
||||
{
|
||||
private readonly TextWriter previousOutWriter;
|
||||
public TestableConsoleOutputTarget(TextWriter outWriter) : base()
|
||||
{
|
||||
previousOutWriter = System.Console.Out;
|
||||
System.Console.SetOut(outWriter);
|
||||
}
|
||||
_previousOutWriter = System.Console.Out;
|
||||
System.Console.SetOut(outWriter);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
System.Console.SetOut(previousOutWriter);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
System.Console.SetOut(_previousOutWriter);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user