From 7c9c2513c348978f0691e8ef98441a8e6bf5ffa0 Mon Sep 17 00:00:00 2001 From: Latency McLaughlin Date: Tue, 17 Mar 2020 19:29:01 -0700 Subject: [PATCH 1/2] Moved SRC and Test folders to root directory. Refactored static ReadLine class to a true singleton. Changed unit tests to use NUnit instead of XUnit. Fixed Ctrl+C issue #59 (Add option to return CTRL+C) Updated version. --- Artifacts/ReadLine.2.0.4.nupkg | Bin 0 -> 43580 bytes .../AutoCompleteHandler.cs | 56 +- .../Program.cs | 62 +- .../ReadLine.Demo.csproj | 30 +- .../Abstractions/Console2.cs | 0 .../AutoCompleteHandler.cs | 0 .../CharExtensions.cs | 2 + .../ConsoleKeyInfoExtensions.cs | 1 + .../KeyHandlerTests.cs | 156 ++-- ReadLine.Tests/ReadLine.Tests.csproj | 22 + ReadLine.Tests/ReadLineTests.cs | 51 ++ ReadLine.sln | 10 +- .../Abstractions/Console2.cs | 0 .../Abstractions/IConsole.cs | 0 .../IAutoCompleteHandler.cs | 0 ReadLine/IReadLine.cs | 12 + {src/ReadLine => ReadLine}/KeyHandler.cs | 709 +++++++++--------- {src/ReadLine => ReadLine}/ReadLine.cs | 24 +- {src/ReadLine => ReadLine}/ReadLine.csproj | 2 +- {src/ReadLine => ReadLine}/snKey.snk | Bin artifacts/ReadLine.2.0.3.nupkg | Bin 41824 -> 0 bytes test/ReadLine.Tests/ReadLine.Tests.csproj | 19 - test/ReadLine.Tests/ReadLineTests.cs | 46 -- 23 files changed, 618 insertions(+), 584 deletions(-) create mode 100644 Artifacts/ReadLine.2.0.4.nupkg rename {src/ReadLine.Demo => ReadLine.Demo}/AutoCompleteHandler.cs (95%) rename {src/ReadLine.Demo => ReadLine.Demo}/Program.cs (65%) mode change 100755 => 100644 rename {src/ReadLine.Demo => ReadLine.Demo}/ReadLine.Demo.csproj (96%) mode change 100755 => 100644 rename {test/ReadLine.Tests => ReadLine.Tests}/Abstractions/Console2.cs (100%) rename {test/ReadLine.Tests => ReadLine.Tests}/AutoCompleteHandler.cs (100%) rename {test/ReadLine.Tests => ReadLine.Tests}/CharExtensions.cs (96%) rename {test/ReadLine.Tests => ReadLine.Tests}/ConsoleKeyInfoExtensions.cs (96%) rename {test/ReadLine.Tests => ReadLine.Tests}/KeyHandlerTests.cs (69%) create mode 100644 ReadLine.Tests/ReadLine.Tests.csproj create mode 100644 ReadLine.Tests/ReadLineTests.cs rename {src/ReadLine => ReadLine}/Abstractions/Console2.cs (100%) rename {src/ReadLine => ReadLine}/Abstractions/IConsole.cs (100%) rename {src/ReadLine => ReadLine}/IAutoCompleteHandler.cs (100%) create mode 100644 ReadLine/IReadLine.cs rename {src/ReadLine => ReadLine}/KeyHandler.cs (96%) rename {src/ReadLine => ReadLine}/ReadLine.cs (61%) mode change 100755 => 100644 rename {src/ReadLine => ReadLine}/ReadLine.csproj (98%) mode change 100755 => 100644 rename {src/ReadLine => ReadLine}/snKey.snk (100%) delete mode 100644 artifacts/ReadLine.2.0.3.nupkg delete mode 100755 test/ReadLine.Tests/ReadLine.Tests.csproj delete mode 100755 test/ReadLine.Tests/ReadLineTests.cs diff --git a/Artifacts/ReadLine.2.0.4.nupkg b/Artifacts/ReadLine.2.0.4.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..250e9154d0416f1500cb1a840f7bc9fe95b7a59e GIT binary patch literal 43580 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
2jdX$!o>CM5txUWBBNL$csS} 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 literal 0 HcmV?d00001 diff --git a/src/ReadLine.Demo/AutoCompleteHandler.cs b/ReadLine.Demo/AutoCompleteHandler.cs similarity index 95% rename from src/ReadLine.Demo/AutoCompleteHandler.cs rename to ReadLine.Demo/AutoCompleteHandler.cs index 44e188b..8fa9a11 100644 --- a/src/ReadLine.Demo/AutoCompleteHandler.cs +++ b/ReadLine.Demo/AutoCompleteHandler.cs @@ -1,28 +1,28 @@ -namespace ReadLine.Demo -{ - internal class AutoCompletionHandler : IAutoCompleteHandler - { - public char[] Separators { get; set; } = - { - ' ', - '.', - '/', - '\\', - ':' - }; - - - public string[] GetSuggestions(string text, int index) - { - return text.StartsWith("git ") - ? new[] - { - "init", - "clone", - "pull", - "push" - } - : null; - } - } -} +namespace ReadLine.Demo +{ + internal class AutoCompletionHandler : IAutoCompleteHandler + { + public char[] Separators { get; set; } = + { + ' ', + '.', + '/', + '\\', + ':' + }; + + + public string[] GetSuggestions(string text, int index) + { + return text.StartsWith("git ") + ? new[] + { + "init", + "clone", + "pull", + "push" + } + : null; + } + } +} diff --git a/src/ReadLine.Demo/Program.cs b/ReadLine.Demo/Program.cs old mode 100755 new mode 100644 similarity index 65% rename from src/ReadLine.Demo/Program.cs rename to ReadLine.Demo/Program.cs index 896f066..5be4213 --- a/src/ReadLine.Demo/Program.cs +++ b/ReadLine.Demo/Program.cs @@ -1,31 +1,33 @@ -using System; - - -namespace ReadLine.Demo -{ - public class Program - { - public static void Main(string[] args) - { - Console.WriteLine("ReadLine Library Demo"); - Console.WriteLine("---------------------"); - Console.WriteLine(); - - string[] history = - { - "ls -a", - "dotnet run", - "git init" - }; - ReadLine.AddHistory(history); - - ReadLine.AutoCompletionHandler = new AutoCompletionHandler(); - - var input = ReadLine.Read("(prompt)> "); - Console.WriteLine(input); - - input = ReadLine.ReadPassword("Enter Password> "); - Console.WriteLine(input); - } - } +using System; + + +namespace ReadLine.Demo +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("ReadLine Library Demo"); + Console.WriteLine("---------------------"); + Console.WriteLine(); + + string[] history = + { + "ls -a", + "dotnet run", + "git init" + }; + + IReadLine readLine = ReadLine.Instance; + readLine.AddHistory(history); + + readLine.AutoCompletionHandler = new AutoCompletionHandler(); + + var input = readLine.Read("(prompt)> "); + Console.WriteLine(input); + + input = readLine.ReadPassword("Enter Password> "); + Console.WriteLine(input); + } + } } \ No newline at end of file diff --git a/src/ReadLine.Demo/ReadLine.Demo.csproj b/ReadLine.Demo/ReadLine.Demo.csproj old mode 100755 new mode 100644 similarity index 96% rename from src/ReadLine.Demo/ReadLine.Demo.csproj rename to ReadLine.Demo/ReadLine.Demo.csproj index a1a89cb..039c0da --- a/src/ReadLine.Demo/ReadLine.Demo.csproj +++ b/ReadLine.Demo/ReadLine.Demo.csproj @@ -1,15 +1,15 @@ - - - - netcoreapp2.2 - portable - ReadLine.Demo - Exe - ReadLine.Demo - - - - - - - + + + + netcoreapp2.2 + portable + ReadLine.Demo + Exe + ReadLine.Demo + + + + + + + diff --git a/test/ReadLine.Tests/Abstractions/Console2.cs b/ReadLine.Tests/Abstractions/Console2.cs similarity index 100% rename from test/ReadLine.Tests/Abstractions/Console2.cs rename to ReadLine.Tests/Abstractions/Console2.cs diff --git a/test/ReadLine.Tests/AutoCompleteHandler.cs b/ReadLine.Tests/AutoCompleteHandler.cs similarity index 100% rename from test/ReadLine.Tests/AutoCompleteHandler.cs rename to ReadLine.Tests/AutoCompleteHandler.cs diff --git a/test/ReadLine.Tests/CharExtensions.cs b/ReadLine.Tests/CharExtensions.cs similarity index 96% rename from test/ReadLine.Tests/CharExtensions.cs rename to ReadLine.Tests/CharExtensions.cs index 7d0e892..2888008 100644 --- a/test/ReadLine.Tests/CharExtensions.cs +++ b/ReadLine.Tests/CharExtensions.cs @@ -11,6 +11,7 @@ public static class CharExtensions public const char CtrlA = '\u0001'; public const char CtrlB = '\u0002'; + public const char CtrlC = '\u0003'; public const char CtrlD = '\u0004'; public const char CtrlE = '\u0005'; public const char CtrlF = '\u0006'; @@ -29,6 +30,7 @@ public static class CharExtensions {Space, Tuple.Create(ConsoleKey.Spacebar, NoModifiers())}, {CtrlA, Tuple.Create(ConsoleKey.A, ConsoleModifiers.Control)}, {CtrlB, Tuple.Create(ConsoleKey.B, ConsoleModifiers.Control)}, + {CtrlC, Tuple.Create(ConsoleKey.C, ConsoleModifiers.Control)}, {CtrlD, Tuple.Create(ConsoleKey.D, ConsoleModifiers.Control)}, {CtrlE, Tuple.Create(ConsoleKey.E, ConsoleModifiers.Control)}, {CtrlF, Tuple.Create(ConsoleKey.F, ConsoleModifiers.Control)}, diff --git a/test/ReadLine.Tests/ConsoleKeyInfoExtensions.cs b/ReadLine.Tests/ConsoleKeyInfoExtensions.cs similarity index 96% rename from test/ReadLine.Tests/ConsoleKeyInfoExtensions.cs rename to ReadLine.Tests/ConsoleKeyInfoExtensions.cs index e604a17..e2497e9 100644 --- a/test/ReadLine.Tests/ConsoleKeyInfoExtensions.cs +++ b/ReadLine.Tests/ConsoleKeyInfoExtensions.cs @@ -23,6 +23,7 @@ public static class ConsoleKeyInfoExtensions public static readonly ConsoleKeyInfo Space = CharExtensions.Space.ToConsoleKeyInfo(); public static readonly ConsoleKeyInfo CtrlA = CharExtensions.CtrlA.ToConsoleKeyInfo(); public static readonly ConsoleKeyInfo CtrlB = CharExtensions.CtrlB.ToConsoleKeyInfo(); + public static readonly ConsoleKeyInfo CtrlC = CharExtensions.CtrlC.ToConsoleKeyInfo(); public static readonly ConsoleKeyInfo CtrlD = CharExtensions.CtrlD.ToConsoleKeyInfo(); public static readonly ConsoleKeyInfo CtrlE = CharExtensions.CtrlE.ToConsoleKeyInfo(); public static readonly ConsoleKeyInfo CtrlF = CharExtensions.CtrlF.ToConsoleKeyInfo(); diff --git a/test/ReadLine.Tests/KeyHandlerTests.cs b/ReadLine.Tests/KeyHandlerTests.cs similarity index 69% rename from test/ReadLine.Tests/KeyHandlerTests.cs rename to ReadLine.Tests/KeyHandlerTests.cs index 30705e1..4a48dad 100644 --- a/test/ReadLine.Tests/KeyHandlerTests.cs +++ b/ReadLine.Tests/KeyHandlerTests.cs @@ -1,23 +1,25 @@ using System; using System.Collections.Generic; using System.Linq; +using NUnit.Framework; using ReadLine.Abstractions; using ReadLine.Tests.Abstractions; -using Xunit; using static ReadLine.Tests.ConsoleKeyInfoExtensions; namespace ReadLine.Tests { + [TestFixture] public class KeyHandlerTests { private KeyHandler _keyHandler; - private readonly List _history; - private readonly AutoCompleteHandler _autoCompleteHandler; - private readonly string[] _completions; - private readonly IConsole _console; + private List _history; + private AutoCompleteHandler _autoCompleteHandler; + private string[] _completions; + private IConsole _console; - public KeyHandlerTests() + [SetUp] + public void Initialize() { _autoCompleteHandler = new AutoCompleteHandler(); _completions = _autoCompleteHandler.GetSuggestions("", 0); @@ -31,59 +33,65 @@ public KeyHandlerTests() .ForEach(_keyHandler.Handle); } - [Fact] + [Test] public void TestWriteChar() { - Assert.Equal("Hello", _keyHandler.Text); + Assert.AreEqual("Hello", _keyHandler.Text); " World".Select(c => c.ToConsoleKeyInfo()) .ToList() .ForEach(_keyHandler.Handle); - Assert.Equal("Hello World", _keyHandler.Text); + Assert.AreEqual("Hello World", _keyHandler.Text); } - [Fact] + [Test] public void TestBackspace() { _keyHandler.Handle(Backspace); - Assert.Equal("Hell", _keyHandler.Text); + Assert.AreEqual("Hell", _keyHandler.Text); } - [Fact] + [Test] public void TestDelete() { new List() { LeftArrow, Delete } .ForEach(_keyHandler.Handle); - Assert.Equal("Hell", _keyHandler.Text); + Assert.AreEqual("Hell", _keyHandler.Text); } - [Fact] + [Test] public void TestDelete_EndOfLine() { _keyHandler.Handle(Delete); - Assert.Equal("Hello", _keyHandler.Text); + Assert.AreEqual("Hello", _keyHandler.Text); } - [Fact] + [Test] + public void TestControlC() { + //_keyHandler.Handle(CtrlC); + Assert.Ignore("Unable to test."); + } + + [Test] public void TestControlH() { _keyHandler.Handle(CtrlH); - Assert.Equal("Hell", _keyHandler.Text); + Assert.AreEqual("Hell", _keyHandler.Text); } - [Fact] + [Test] public void TestControlT() { var initialCursorCol = _console.CursorLeft; _keyHandler.Handle(CtrlT); - Assert.Equal("Helol", _keyHandler.Text); - Assert.Equal(initialCursorCol, _console.CursorLeft); + Assert.AreEqual("Helol", _keyHandler.Text); + Assert.AreEqual(initialCursorCol, _console.CursorLeft); } - [Fact] + [Test] public void TestControlT_LeftOnce_CursorMovesToEnd() { var initialCursorCol = _console.CursorLeft; @@ -91,11 +99,11 @@ public void TestControlT_LeftOnce_CursorMovesToEnd() new List() { LeftArrow, CtrlT } .ForEach(_keyHandler.Handle); - Assert.Equal("Helol", _keyHandler.Text); - Assert.Equal(initialCursorCol, _console.CursorLeft); + Assert.AreEqual("Helol", _keyHandler.Text); + Assert.AreEqual(initialCursorCol, _console.CursorLeft); } - [Fact] + [Test] public void TestControlT_CursorInMiddleOfLine() { Enumerable @@ -107,11 +115,11 @@ public void TestControlT_CursorInMiddleOfLine() _keyHandler.Handle(CtrlT); - Assert.Equal("Hlelo", _keyHandler.Text); - Assert.Equal(initialCursorCol + 1, _console.CursorLeft); + Assert.AreEqual("Hlelo", _keyHandler.Text); + Assert.AreEqual(initialCursorCol + 1, _console.CursorLeft); } - [Fact] + [Test] public void TestControlT_CursorAtBeginningOfLine_HasNoEffect() { _keyHandler.Handle(CtrlA); @@ -120,47 +128,47 @@ public void TestControlT_CursorAtBeginningOfLine_HasNoEffect() _keyHandler.Handle(CtrlT); - Assert.Equal("Hello", _keyHandler.Text); - Assert.Equal(initialCursorCol, _console.CursorLeft); + Assert.AreEqual("Hello", _keyHandler.Text); + Assert.AreEqual(initialCursorCol, _console.CursorLeft); } - [Fact] + [Test] public void TestHome() { new List() { Home, 'S'.ToConsoleKeyInfo() } .ForEach(_keyHandler.Handle); - Assert.Equal("SHello", _keyHandler.Text); + Assert.AreEqual("SHello", _keyHandler.Text); } - [Fact] + [Test] public void TestControlA() { new List() { CtrlA, 'S'.ToConsoleKeyInfo() } .ForEach(_keyHandler.Handle); - Assert.Equal("SHello", _keyHandler.Text); + Assert.AreEqual("SHello", _keyHandler.Text); } - [Fact] + [Test] public void TestEnd() { new List() { Home, End, ExclamationPoint } .ForEach(_keyHandler.Handle); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.AreEqual("Hello!", _keyHandler.Text); } - [Fact] + [Test] public void TestControlE() { new List() { CtrlA, CtrlE, ExclamationPoint } .ForEach(_keyHandler.Handle); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.AreEqual("Hello!", _keyHandler.Text); } - [Fact] + [Test] public void TestLeftArrow() { " N".Select(c => c.ToConsoleKeyInfo()) @@ -168,10 +176,10 @@ public void TestLeftArrow() .ToList() .ForEach(_keyHandler.Handle); - Assert.Equal("Hell No", _keyHandler.Text); + Assert.AreEqual("Hell No", _keyHandler.Text); } - [Fact] + [Test] public void TestControlB() { " N".Select(c => c.ToConsoleKeyInfo()) @@ -179,19 +187,19 @@ public void TestControlB() .ToList() .ForEach(_keyHandler.Handle); - Assert.Equal("Hell No", _keyHandler.Text); + Assert.AreEqual("Hell No", _keyHandler.Text); } - [Fact] + [Test] public void TestRightArrow() { new List() { LeftArrow, RightArrow, ExclamationPoint } .ForEach(_keyHandler.Handle); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.AreEqual("Hello!", _keyHandler.Text); } - [Fact] + [Test] public void TestControlD() { Enumerable.Repeat(LeftArrow, 4) @@ -199,44 +207,44 @@ public void TestControlD() .ToList() .ForEach(_keyHandler.Handle); - Assert.Equal("Hllo", _keyHandler.Text); + Assert.AreEqual("Hllo", _keyHandler.Text); } - [Fact] + [Test] public void TestControlF() { new List() { LeftArrow, CtrlF, ExclamationPoint } .ForEach(_keyHandler.Handle); - Assert.Equal("Hello!", _keyHandler.Text); + Assert.AreEqual("Hello!", _keyHandler.Text); } - [Fact] + [Test] public void TestControlL() { _keyHandler.Handle(CtrlL); - Assert.Equal(string.Empty, _keyHandler.Text); + Assert.AreEqual(string.Empty, _keyHandler.Text); } - [Fact] + [Test] public void TestUpArrow() { _history.AsEnumerable().Reverse().ToList().ForEach((history) => { _keyHandler.Handle(UpArrow); - Assert.Equal(history, _keyHandler.Text); + Assert.AreEqual(history, _keyHandler.Text); }); } - [Fact] + [Test] public void TestControlP() { _history.AsEnumerable().Reverse().ToList().ForEach((history) => { _keyHandler.Handle(CtrlP); - Assert.Equal(history, _keyHandler.Text); + Assert.AreEqual(history, _keyHandler.Text); }); } - [Fact] + [Test] public void TestDownArrow() { Enumerable.Repeat(UpArrow, _history.Count) @@ -244,12 +252,12 @@ public void TestDownArrow() .ForEach(_keyHandler.Handle); _history.ForEach( history => { - Assert.Equal(history, _keyHandler.Text); + Assert.AreEqual(history, _keyHandler.Text); _keyHandler.Handle(DownArrow); }); } - [Fact] + [Test] public void TestControlN() { Enumerable.Repeat(UpArrow, _history.Count) @@ -257,40 +265,40 @@ public void TestControlN() .ForEach(_keyHandler.Handle); _history.ForEach( history => { - Assert.Equal(history, _keyHandler.Text); + Assert.AreEqual(history, _keyHandler.Text); _keyHandler.Handle(CtrlN); }); } - [Fact] + [Test] public void TestControlU() { _keyHandler.Handle(LeftArrow); _keyHandler.Handle(CtrlU); - Assert.Equal("o", _keyHandler.Text); + Assert.AreEqual("o", _keyHandler.Text); _keyHandler.Handle(End); _keyHandler.Handle(CtrlU); - Assert.Equal(string.Empty, _keyHandler.Text); + Assert.AreEqual(string.Empty, _keyHandler.Text); } - [Fact] + [Test] public void TestControlK() { _keyHandler.Handle(LeftArrow); _keyHandler.Handle(CtrlK); - Assert.Equal("Hell", _keyHandler.Text); + Assert.AreEqual("Hell", _keyHandler.Text); _keyHandler.Handle(Home); _keyHandler.Handle(CtrlK); - Assert.Equal(string.Empty, _keyHandler.Text); + Assert.AreEqual(string.Empty, _keyHandler.Text); } - [Fact] + [Test] public void TestControlW() { " World".Select(c => c.ToConsoleKeyInfo()) @@ -298,20 +306,20 @@ public void TestControlW() .ToList() .ForEach(_keyHandler.Handle); - Assert.Equal("Hello ", _keyHandler.Text); + Assert.AreEqual("Hello ", _keyHandler.Text); _keyHandler.Handle(Backspace); _keyHandler.Handle(CtrlW); - Assert.Equal(string.Empty, _keyHandler.Text); + Assert.AreEqual(string.Empty, _keyHandler.Text); } - [Fact] + [Test] public void TestTab() { _keyHandler.Handle(Tab); // Nothing happens when no auto complete handler is set - Assert.Equal("Hello", _keyHandler.Text); + Assert.AreEqual("Hello", _keyHandler.Text); _keyHandler = new KeyHandler(new Console2(), _history, _autoCompleteHandler); @@ -319,17 +327,17 @@ public void TestTab() _completions.ToList().ForEach(completion => { _keyHandler.Handle(Tab); - Assert.Equal($"Hi {completion}", _keyHandler.Text); + Assert.AreEqual($"Hi {completion}", _keyHandler.Text); }); } - [Fact] + [Test] public void TestBackwardsTab() { _keyHandler.Handle(Tab); // Nothing happens when no auto complete handler is set - Assert.Equal("Hello", _keyHandler.Text); + Assert.AreEqual("Hello", _keyHandler.Text); _keyHandler = new KeyHandler(new Console2(), _history, _autoCompleteHandler); @@ -340,17 +348,17 @@ public void TestBackwardsTab() _completions.Reverse().ToList().ForEach(completion => { _keyHandler.Handle(ShiftTab); - Assert.Equal($"Hi {completion}", _keyHandler.Text); + Assert.AreEqual($"Hi {completion}", _keyHandler.Text); }); } - [Fact] + [Test] public void MoveCursorThenPreviousHistory() { _keyHandler.Handle(LeftArrow); _keyHandler.Handle(UpArrow); - Assert.Equal("clear", _keyHandler.Text); + Assert.AreEqual("clear", _keyHandler.Text); } } } \ No newline at end of file diff --git a/ReadLine.Tests/ReadLine.Tests.csproj b/ReadLine.Tests/ReadLine.Tests.csproj new file mode 100644 index 0000000..568a4fb --- /dev/null +++ b/ReadLine.Tests/ReadLine.Tests.csproj @@ -0,0 +1,22 @@ + + + + net472 + ReadLine.Tests + ReadLine.Tests + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/ReadLine.Tests/ReadLineTests.cs b/ReadLine.Tests/ReadLineTests.cs new file mode 100644 index 0000000..f07e200 --- /dev/null +++ b/ReadLine.Tests/ReadLineTests.cs @@ -0,0 +1,51 @@ +using System.Linq; +using NUnit.Framework; + + +namespace ReadLine.Tests +{ + [TestFixture] + public class ReadLineTests + { + private readonly IReadLine _readLine = ReadLine.Instance; + private static readonly string[] History = { "ls -a", "dotnet run", "git init" }; + + [SetUp] + public void Initialize() { + _readLine.AddHistory(History); + } + + [TearDown] + public void Destruct() { + _readLine.ClearHistory(); + } + + [Test] + public void TestClearHistory() { + _readLine.ClearHistory(); + Assert.AreEqual(0, _readLine.GetHistory().Count); + } + + [Test] + public void TestNoInitialHistory() + { + Assert.AreEqual(3, _readLine.GetHistory().Count); + } + + [Test] + public void TestUpdatesHistory() + { + _readLine.AddHistory("mkdir"); + Assert.AreEqual(4, _readLine.GetHistory().Count); + Assert.AreEqual("mkdir", _readLine.GetHistory().Last()); + } + + [Test] + public void TestGetCorrectHistory() + { + Assert.AreEqual("ls -a", _readLine.GetHistory()[0]); + Assert.AreEqual("dotnet run", _readLine.GetHistory()[1]); + Assert.AreEqual("git init", _readLine.GetHistory()[2]); + } + } +} diff --git a/ReadLine.sln b/ReadLine.sln index d0fa19b..489bf7c 100755 --- a/ReadLine.sln +++ b/ReadLine.sln @@ -2,15 +2,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{06FC0E85-E73C-4DC1-B6FD-A583B7B1DFE4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine", "ReadLine\ReadLine.csproj", "{9EB290C9-BB52-4B24-9779-5A816AC75E18}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine", "src\ReadLine\ReadLine.csproj", "{9EB290C9-BB52-4B24-9779-5A816AC75E18}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine.Demo", "ReadLine.Demo\ReadLine.Demo.csproj", "{4C512FD1-A0E8-4908-B0A4-B0D85947716A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine.Demo", "src\ReadLine.Demo\ReadLine.Demo.csproj", "{4C512FD1-A0E8-4908-B0A4-B0D85947716A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{38C56AEB-DB08-4CBF-AAC0-EBFC2B0EE045}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine.Tests", "test\ReadLine.Tests\ReadLine.Tests.csproj", "{631582D9-EEEA-4F9D-8069-71ECA24ED282}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadLine.Tests", "ReadLine.Tests\ReadLine.Tests.csproj", "{631582D9-EEEA-4F9D-8069-71ECA24ED282}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/ReadLine/Abstractions/Console2.cs b/ReadLine/Abstractions/Console2.cs similarity index 100% rename from src/ReadLine/Abstractions/Console2.cs rename to ReadLine/Abstractions/Console2.cs diff --git a/src/ReadLine/Abstractions/IConsole.cs b/ReadLine/Abstractions/IConsole.cs similarity index 100% rename from src/ReadLine/Abstractions/IConsole.cs rename to ReadLine/Abstractions/IConsole.cs diff --git a/src/ReadLine/IAutoCompleteHandler.cs b/ReadLine/IAutoCompleteHandler.cs similarity index 100% rename from src/ReadLine/IAutoCompleteHandler.cs rename to ReadLine/IAutoCompleteHandler.cs diff --git a/ReadLine/IReadLine.cs b/ReadLine/IReadLine.cs new file mode 100644 index 0000000..e7ab988 --- /dev/null +++ b/ReadLine/IReadLine.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace ReadLine { + public interface IReadLine { + IAutoCompleteHandler AutoCompletionHandler { get; set; } + void AddHistory(params string[] text); + List GetHistory(); + void ClearHistory(); + string Read(string prompt = "", string @default = ""); + string ReadPassword(string prompt = ""); + } +} diff --git a/src/ReadLine/KeyHandler.cs b/ReadLine/KeyHandler.cs similarity index 96% rename from src/ReadLine/KeyHandler.cs rename to ReadLine/KeyHandler.cs index 075700e..5fb3824 100644 --- a/src/ReadLine/KeyHandler.cs +++ b/ReadLine/KeyHandler.cs @@ -1,355 +1,356 @@ -using System; -using System.Collections.Generic; -using System.Text; -using ReadLine.Abstractions; - - -namespace ReadLine -{ - public class KeyHandler - { - private readonly IConsole _console2; - private readonly List _history; - private readonly Dictionary _keyActions; - private readonly StringBuilder _text; - private string[] _completions; - private int _completionsIndex; - private int _completionStart; - private int _cursorLimit; - private int _cursorPos; - private int _historyIndex; - private ConsoleKeyInfo _keyInfo; - - public KeyHandler(IConsole console, List history, IAutoCompleteHandler autoCompleteHandler) - { - _console2 = console; - - _history = history ?? new List(); - _historyIndex = _history.Count; - _text = new StringBuilder(); - _keyActions = new Dictionary - { - ["LeftArrow"] = MoveCursorLeft, - ["Home"] = MoveCursorHome, - ["End"] = MoveCursorEnd, - ["ControlA"] = MoveCursorHome, - ["ControlB"] = MoveCursorLeft, - ["RightArrow"] = MoveCursorRight, - ["ControlF"] = MoveCursorRight, - ["ControlE"] = MoveCursorEnd, - ["Backspace"] = Backspace, - ["Delete"] = Delete, - ["ControlD"] = Delete, - ["ControlH"] = Backspace, - ["ControlL"] = ClearLine, - ["Escape"] = ClearLine, - ["UpArrow"] = PrevHistory, - ["ControlP"] = PrevHistory, - ["DownArrow"] = NextHistory, - ["ControlN"] = NextHistory, - ["ControlU"] = () => { Backspace(_cursorPos); }, - ["ControlK"] = () => - { - var pos = _cursorPos; - MoveCursorEnd(); - Backspace(_cursorPos - pos); - }, - ["ControlW"] = () => - { - while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') - Backspace(); - }, - ["ControlT"] = TransposeChars, - ["Tab"] = () => - { - if (IsInAutoCompleteMode()) - { - NextAutoComplete(); - } - else - { - if (autoCompleteHandler == null || !IsEndOfLine()) - return; - - var text = _text.ToString(); - - _completionStart = text.LastIndexOfAny(autoCompleteHandler.Separators); - _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; - - _completions = autoCompleteHandler.GetSuggestions(text, _completionStart); - _completions = _completions?.Length == 0 ? null : _completions; - - if (_completions == null) - return; - - StartAutoComplete(); - } - }, - ["ShiftTab"] = () => - { - if (IsInAutoCompleteMode()) - PreviousAutoComplete(); - } - }; - } - - - public string Text => _text.ToString(); - - - private bool IsStartOfLine() => _cursorPos == 0; - - - private bool IsEndOfLine() => _cursorPos == _cursorLimit; - - - private bool IsStartOfBuffer() => _console2.CursorLeft == 0; - - - private bool IsEndOfBuffer() => _console2.CursorLeft == _console2.BufferWidth - 1; - - - private bool IsInAutoCompleteMode() => _completions != null; - - - private void MoveCursorLeft() => MoveCursorLeft(1); - - private void MoveCursorLeft(int count) - { - if (count > _cursorPos) - count = _cursorPos; - - if (count > _console2.CursorLeft) - _console2.SetCursorPosition(_console2.BufferWidth - 1, _console2.CursorTop - 1); - else - _console2.SetCursorPosition(_console2.CursorLeft - 1, _console2.CursorTop); - - _cursorPos -= count; - } - - - private void MoveCursorHome() - { - while (!IsStartOfLine()) - MoveCursorLeft(); - } - - - private string BuildKeyInput() => _keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); - - - private void MoveCursorRight() - { - if (IsEndOfLine()) - return; - - if (IsEndOfBuffer()) - _console2.SetCursorPosition(0, _console2.CursorTop + 1); - else - _console2.SetCursorPosition(_console2.CursorLeft + 1, _console2.CursorTop); - - _cursorPos++; - } - - - private void MoveCursorEnd() - { - while (!IsEndOfLine()) - MoveCursorRight(); - } - - - private void ClearLine() - { - MoveCursorEnd(); - Backspace(_cursorPos); - } - - - private void WriteNewString(string str) - { - ClearLine(); - WriteString(str); - } - - - private void WriteString(string str) - { - foreach (var character in str) - WriteChar(character); - } - - - private void WriteChar() => WriteChar(_keyInfo.KeyChar); - - - private void WriteChar(char c) - { - if (IsEndOfLine()) - { - _text.Append(c); - _console2.Write(c.ToString()); - _cursorPos++; - } - else - { - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - var str = _text.ToString().Substring(_cursorPos); - _text.Insert(_cursorPos, c); - _console2.Write(c + str); - _console2.SetCursorPosition(left, top); - MoveCursorRight(); - } - - _cursorLimit++; - } - - - private void Backspace() => Backspace(1); - - private void Backspace(int count) - { - if (count > _cursorPos) - count = _cursorPos; - - MoveCursorLeft(count); - var index = _cursorPos; - _text.Remove(index, count); - var replacement = _text.ToString().Substring(index); - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - var spaces = new string(' ', count); - _console2.Write($"{replacement}{spaces}"); - _console2.SetCursorPosition(left, top); - _cursorLimit -= count; - } - - - private void Delete() - { - if (IsEndOfLine()) - return; - - var index = _cursorPos; - _text.Remove(index, 1); - var replacement = _text.ToString().Substring(index); - var left = _console2.CursorLeft; - var top = _console2.CursorTop; - _console2.Write($"{replacement} "); - _console2.SetCursorPosition(left, top); - _cursorLimit--; - } - - - private void TransposeChars() - { - // local helper functions - bool AlmostEndOfLine() => _cursorLimit - _cursorPos == 1; - - int IncrementIf(Func expression, int index) => expression() ? index + 1 : index; - - int DecrementIf(Func expression, int index) => expression() ? index - 1 : index; - - if (IsStartOfLine()) - return; - - var firstIdx = DecrementIf(IsEndOfLine, _cursorPos - 1); - var secondIdx = DecrementIf(IsEndOfLine, _cursorPos); - - var secondChar = _text[secondIdx]; - _text[secondIdx] = _text[firstIdx]; - _text[firstIdx] = secondChar; - - var left = IncrementIf(AlmostEndOfLine, _console2.CursorLeft); - var cursorPosition = IncrementIf(AlmostEndOfLine, _cursorPos); - - WriteNewString(_text.ToString()); - - _console2.SetCursorPosition(left, _console2.CursorTop); - _cursorPos = cursorPosition; - - MoveCursorRight(); - } - - - private void StartAutoComplete() - { - Backspace(_cursorPos - _completionStart); - - _completionsIndex = 0; - - WriteString(_completions[_completionsIndex]); - } - - - private void NextAutoComplete() - { - Backspace(_cursorPos - _completionStart); - - _completionsIndex++; - - if (_completionsIndex == _completions.Length) - _completionsIndex = 0; - - WriteString(_completions[_completionsIndex]); - } - - - private void PreviousAutoComplete() - { - Backspace(_cursorPos - _completionStart); - - _completionsIndex--; - - if (_completionsIndex == -1) - _completionsIndex = _completions.Length - 1; - - WriteString(_completions[_completionsIndex]); - } - - - private void PrevHistory() - { - if (_historyIndex > 0) - { - _historyIndex--; - WriteNewString(_history[_historyIndex]); - } - } - - - private void NextHistory() - { - if (_historyIndex < _history.Count) - { - _historyIndex++; - if (_historyIndex == _history.Count) - ClearLine(); - else - WriteNewString(_history[_historyIndex]); - } - } - - - private void ResetAutoComplete() - { - _completions = null; - _completionsIndex = 0; - } - - - public void Handle(ConsoleKeyInfo keyInfo) - { - _keyInfo = keyInfo; - - // If in auto complete mode and Tab wasn't pressed - if (IsInAutoCompleteMode() && _keyInfo.Key != ConsoleKey.Tab) - ResetAutoComplete(); - - _keyActions.TryGetValue(BuildKeyInput(), out var action); - action = action ?? WriteChar; - action.Invoke(); - } - } +using System; +using System.Collections.Generic; +using System.Text; +using ReadLine.Abstractions; + + +namespace ReadLine +{ + public class KeyHandler + { + private readonly IConsole _console2; + private readonly List _history; + private readonly Dictionary _keyActions; + private readonly StringBuilder _text; + private string[] _completions; + private int _completionsIndex; + private int _completionStart; + private int _cursorLimit; + private int _cursorPos; + private int _historyIndex; + private ConsoleKeyInfo _keyInfo; + + public KeyHandler(IConsole console, List history, IAutoCompleteHandler autoCompleteHandler) + { + _console2 = console; + + _history = history ?? new List(); + _historyIndex = _history.Count; + _text = new StringBuilder(); + _keyActions = new Dictionary + { + ["LeftArrow"] = MoveCursorLeft, + ["Home"] = MoveCursorHome, + ["End"] = MoveCursorEnd, + ["ControlA"] = MoveCursorHome, + ["ControlB"] = MoveCursorLeft, + ["ControlC"] = () => Environment.Exit(0), + ["RightArrow"] = MoveCursorRight, + ["ControlF"] = MoveCursorRight, + ["ControlE"] = MoveCursorEnd, + ["Backspace"] = Backspace, + ["Delete"] = Delete, + ["ControlD"] = Delete, + ["ControlH"] = Backspace, + ["ControlL"] = ClearLine, + ["Escape"] = ClearLine, + ["UpArrow"] = PrevHistory, + ["ControlP"] = PrevHistory, + ["DownArrow"] = NextHistory, + ["ControlN"] = NextHistory, + ["ControlU"] = () => { Backspace(_cursorPos); }, + ["ControlK"] = () => + { + var pos = _cursorPos; + MoveCursorEnd(); + Backspace(_cursorPos - pos); + }, + ["ControlW"] = () => + { + while (!IsStartOfLine() && _text[_cursorPos - 1] != ' ') + Backspace(); + }, + ["ControlT"] = TransposeChars, + ["Tab"] = () => + { + if (IsInAutoCompleteMode()) + { + NextAutoComplete(); + } + else + { + if (autoCompleteHandler == null || !IsEndOfLine()) + return; + + var text = _text.ToString(); + + _completionStart = text.LastIndexOfAny(autoCompleteHandler.Separators); + _completionStart = _completionStart == -1 ? 0 : _completionStart + 1; + + _completions = autoCompleteHandler.GetSuggestions(text, _completionStart); + _completions = _completions?.Length == 0 ? null : _completions; + + if (_completions == null) + return; + + StartAutoComplete(); + } + }, + ["ShiftTab"] = () => + { + if (IsInAutoCompleteMode()) + PreviousAutoComplete(); + } + }; + } + + + public string Text => _text.ToString(); + + + private bool IsStartOfLine() => _cursorPos == 0; + + + private bool IsEndOfLine() => _cursorPos == _cursorLimit; + + + private bool IsStartOfBuffer() => _console2.CursorLeft == 0; + + + private bool IsEndOfBuffer() => _console2.CursorLeft == _console2.BufferWidth - 1; + + + private bool IsInAutoCompleteMode() => _completions != null; + + + private void MoveCursorLeft() => MoveCursorLeft(1); + + private void MoveCursorLeft(int count) + { + if (count > _cursorPos) + count = _cursorPos; + + if (count > _console2.CursorLeft) + _console2.SetCursorPosition(_console2.BufferWidth - 1, _console2.CursorTop - 1); + else + _console2.SetCursorPosition(_console2.CursorLeft - 1, _console2.CursorTop); + + _cursorPos -= count; + } + + + private void MoveCursorHome() + { + while (!IsStartOfLine()) + MoveCursorLeft(); + } + + + private string BuildKeyInput() => _keyInfo.Modifiers != ConsoleModifiers.Control && _keyInfo.Modifiers != ConsoleModifiers.Shift ? _keyInfo.Key.ToString() : _keyInfo.Modifiers + _keyInfo.Key.ToString(); + + + private void MoveCursorRight() + { + if (IsEndOfLine()) + return; + + if (IsEndOfBuffer()) + _console2.SetCursorPosition(0, _console2.CursorTop + 1); + else + _console2.SetCursorPosition(_console2.CursorLeft + 1, _console2.CursorTop); + + _cursorPos++; + } + + + private void MoveCursorEnd() + { + while (!IsEndOfLine()) + MoveCursorRight(); + } + + + private void ClearLine() + { + MoveCursorEnd(); + Backspace(_cursorPos); + } + + + private void WriteNewString(string str) + { + ClearLine(); + WriteString(str); + } + + + private void WriteString(string str) + { + foreach (var character in str) + WriteChar(character); + } + + + private void WriteChar() => WriteChar(_keyInfo.KeyChar); + + + private void WriteChar(char c) + { + if (IsEndOfLine()) + { + _text.Append(c); + _console2.Write(c.ToString()); + _cursorPos++; + } + else + { + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + var str = _text.ToString().Substring(_cursorPos); + _text.Insert(_cursorPos, c); + _console2.Write(c + str); + _console2.SetCursorPosition(left, top); + MoveCursorRight(); + } + + _cursorLimit++; + } + + + private void Backspace() => Backspace(1); + + private void Backspace(int count) + { + if (count > _cursorPos) + count = _cursorPos; + + MoveCursorLeft(count); + var index = _cursorPos; + _text.Remove(index, count); + var replacement = _text.ToString().Substring(index); + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + var spaces = new string(' ', count); + _console2.Write($"{replacement}{spaces}"); + _console2.SetCursorPosition(left, top); + _cursorLimit -= count; + } + + + private void Delete() + { + if (IsEndOfLine()) + return; + + var index = _cursorPos; + _text.Remove(index, 1); + var replacement = _text.ToString().Substring(index); + var left = _console2.CursorLeft; + var top = _console2.CursorTop; + _console2.Write($"{replacement} "); + _console2.SetCursorPosition(left, top); + _cursorLimit--; + } + + + private void TransposeChars() + { + // local helper functions + bool AlmostEndOfLine() => _cursorLimit - _cursorPos == 1; + + int IncrementIf(Func expression, int index) => expression() ? index + 1 : index; + + int DecrementIf(Func expression, int index) => expression() ? index - 1 : index; + + if (IsStartOfLine()) + return; + + var firstIdx = DecrementIf(IsEndOfLine, _cursorPos - 1); + var secondIdx = DecrementIf(IsEndOfLine, _cursorPos); + + var secondChar = _text[secondIdx]; + _text[secondIdx] = _text[firstIdx]; + _text[firstIdx] = secondChar; + + var left = IncrementIf(AlmostEndOfLine, _console2.CursorLeft); + var cursorPosition = IncrementIf(AlmostEndOfLine, _cursorPos); + + WriteNewString(_text.ToString()); + + _console2.SetCursorPosition(left, _console2.CursorTop); + _cursorPos = cursorPosition; + + MoveCursorRight(); + } + + + private void StartAutoComplete() + { + Backspace(_cursorPos - _completionStart); + + _completionsIndex = 0; + + WriteString(_completions[_completionsIndex]); + } + + + private void NextAutoComplete() + { + Backspace(_cursorPos - _completionStart); + + _completionsIndex++; + + if (_completionsIndex == _completions.Length) + _completionsIndex = 0; + + WriteString(_completions[_completionsIndex]); + } + + + private void PreviousAutoComplete() + { + Backspace(_cursorPos - _completionStart); + + _completionsIndex--; + + if (_completionsIndex == -1) + _completionsIndex = _completions.Length - 1; + + WriteString(_completions[_completionsIndex]); + } + + + private void PrevHistory() + { + if (_historyIndex > 0) + { + _historyIndex--; + WriteNewString(_history[_historyIndex]); + } + } + + + private void NextHistory() + { + if (_historyIndex < _history.Count) + { + _historyIndex++; + if (_historyIndex == _history.Count) + ClearLine(); + else + WriteNewString(_history[_historyIndex]); + } + } + + + private void ResetAutoComplete() + { + _completions = null; + _completionsIndex = 0; + } + + + public void Handle(ConsoleKeyInfo keyInfo) + { + _keyInfo = keyInfo; + + // If in auto complete mode and Tab wasn't pressed + if (IsInAutoCompleteMode() && _keyInfo.Key != ConsoleKey.Tab) + ResetAutoComplete(); + + _keyActions.TryGetValue(BuildKeyInput(), out var action); + action = action ?? WriteChar; + action.Invoke(); + } + } } \ No newline at end of file diff --git a/src/ReadLine/ReadLine.cs b/ReadLine/ReadLine.cs old mode 100755 new mode 100644 similarity index 61% rename from src/ReadLine/ReadLine.cs rename to ReadLine/ReadLine.cs index 0bb765e..434744a --- a/src/ReadLine/ReadLine.cs +++ b/ReadLine/ReadLine.cs @@ -5,27 +5,29 @@ namespace ReadLine { - public static class ReadLine + public class ReadLine : IReadLine { - private static List _history; + private List _history; + private ReadLine() { + _history = new List(); + } - static ReadLine() => _history = new List(); - + public static ReadLine Instance = new ReadLine(); // Singleton implementation - public static IAutoCompleteHandler AutoCompletionHandler { private get; set; } + public IAutoCompleteHandler AutoCompletionHandler { get; set; } - public static void AddHistory(params string[] text) => _history.AddRange(text); + public void AddHistory(params string[] text) => _history.AddRange(text); - public static List GetHistory() => _history; + public List GetHistory() => _history; - public static void ClearHistory() => _history = new List(); + public void ClearHistory() => _history = new List(); - public static string Read(string prompt = "", string @default = "") + public string Read(string prompt = "", string @default = "") { Console.Write(prompt); var keyHandler = new KeyHandler(new Console2(), _history, AutoCompletionHandler); @@ -40,7 +42,7 @@ public static string Read(string prompt = "", string @default = "") } - public static string ReadPassword(string prompt = "") + public string ReadPassword(string prompt = "") { Console.Write(prompt); var keyHandler = new KeyHandler(new Console2 @@ -53,6 +55,8 @@ public static string ReadPassword(string prompt = "") private static string GetText(KeyHandler keyHandler) { + Console.TreatControlCAsInput = true; + var keyInfo = Console.ReadKey(true); while (keyInfo.Key != ConsoleKey.Enter) { diff --git a/src/ReadLine/ReadLine.csproj b/ReadLine/ReadLine.csproj old mode 100755 new mode 100644 similarity index 98% rename from src/ReadLine/ReadLine.csproj rename to ReadLine/ReadLine.csproj index 88d7801..6694755 --- a/src/ReadLine/ReadLine.csproj +++ b/ReadLine/ReadLine.csproj @@ -13,7 +13,7 @@ snKey.snk true Updated to support .NET Standard v2.0 / Core 2.2 & 3.0 / Framework v4.5 - v4.8 - 2.0.3 + 2.0.4 A GNU-Readline like library for .NET artifacts MIT diff --git a/src/ReadLine/snKey.snk b/ReadLine/snKey.snk similarity index 100% rename from src/ReadLine/snKey.snk rename to ReadLine/snKey.snk diff --git a/artifacts/ReadLine.2.0.3.nupkg b/artifacts/ReadLine.2.0.3.nupkg deleted file mode 100644 index 2538e1bf5992b42b40741fc7ecc23bab9d3eb5fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41824 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 k$K - - - netcoreapp2.1 - portable - ReadLine.Tests - ReadLine.Tests - true - - - - - - - - - - - diff --git a/test/ReadLine.Tests/ReadLineTests.cs b/test/ReadLine.Tests/ReadLineTests.cs deleted file mode 100755 index 2b8cfdc..0000000 --- a/test/ReadLine.Tests/ReadLineTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Linq; -using Xunit; -using static ReadLine.ReadLine; - - -namespace ReadLine.Tests -{ - public class ReadLineTests : IDisposable - { - public ReadLineTests() - { - string[] history = { "ls -a", "dotnet run", "git init" }; - AddHistory(history); - } - - [Fact] - public void TestNoInitialHistory() - { - Assert.Equal(3, GetHistory().Count); - } - - [Fact] - public void TestUpdatesHistory() - { - AddHistory("mkdir"); - Assert.Equal(4, GetHistory().Count); - Assert.Equal("mkdir", GetHistory().Last()); - } - - [Fact] - public void TestGetCorrectHistory() - { - Assert.Equal("ls -a", GetHistory()[0]); - Assert.Equal("dotnet run", GetHistory()[1]); - Assert.Equal("git init", GetHistory()[2]); - } - - public void Dispose() - { - // If all above tests pass - // clear history works - ClearHistory(); - } - } -} From f53119532ce7db8ed2ff1110800bb1428e27bab7 Mon Sep 17 00:00:00 2001 From: Latency McLaughlin Date: Tue, 17 Mar 2020 19:38:31 -0700 Subject: [PATCH 2/2] Create dotnetcore.yml --- .github/workflows/dotnetcore.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/dotnetcore.yml diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 0000000..d243b1f --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,21 @@ +name: .NET Core + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.101 + - name: Build with dotnet + run: dotnet build --configuration Release