From e8d753ada84b01229398742925be45e52ac31f77 Mon Sep 17 00:00:00 2001 From: Zev Spitz Date: Fri, 21 Jan 2022 04:31:55 +0200 Subject: [PATCH] Added tests project --- .../vbnet/Animal.Tests/Animal.Tests.vbproj | 8 +- 03_Animal/vbnet/Animal.Tests/MockConsole.vb | 65 +++++++++++++++ 03_Animal/vbnet/Animal.Tests/TestContainer.vb | 80 +++++++++++++++++++ 03_Animal/vbnet/Animal.Tests/UnitTest1.vb | 12 --- .../vbnet/Animal/Shared/ConsoleAdapter.vb | 1 + 03_Animal/vbnet/Animal/Shared/Extensions.vb | 29 +++++++ 6 files changed, 181 insertions(+), 14 deletions(-) create mode 100644 03_Animal/vbnet/Animal.Tests/MockConsole.vb create mode 100644 03_Animal/vbnet/Animal.Tests/TestContainer.vb delete mode 100644 03_Animal/vbnet/Animal.Tests/UnitTest1.vb diff --git a/03_Animal/vbnet/Animal.Tests/Animal.Tests.vbproj b/03_Animal/vbnet/Animal.Tests/Animal.Tests.vbproj index 05d00314..62a341e9 100644 --- a/03_Animal/vbnet/Animal.Tests/Animal.Tests.vbproj +++ b/03_Animal/vbnet/Animal.Tests/Animal.Tests.vbproj @@ -3,12 +3,12 @@ Animal.Tests net6.0 - false + On - + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -20,4 +20,8 @@ + + + + diff --git a/03_Animal/vbnet/Animal.Tests/MockConsole.vb b/03_Animal/vbnet/Animal.Tests/MockConsole.vb new file mode 100644 index 00000000..a78dc50f --- /dev/null +++ b/03_Animal/vbnet/Animal.Tests/MockConsole.vb @@ -0,0 +1,65 @@ +Imports System.IO + +Public Class MockConsole + Inherits ConsoleAdapterBase + + Private inputs As Queue(Of String) + Public ReadOnly Lines As New List(Of (line As String, centered As Boolean)) From { + ("", False) + } + + ' TODO it's possible to clear all the lines, and we'd have to check once again in WriteString and WriteCenteredLine if there are any lines + + Sub New(Inputs As IEnumerable(Of String)) + Me.inputs = New Queue(Of String)(Inputs) + End Sub + + Private Sub CheckLinesInitialized() + If Lines.Count = 0 Then Lines.Add(("", False)) + End Sub + + Private Sub WriteString(s As String, Optional centered As Boolean = False) + If s Is Nothing Then Return + CheckLinesInitialized() + s.Split(Environment.NewLine).ForEach(Sub(line, index) + If index = 0 Then + Dim currentLast = Lines(Lines.Count - 1) + ' centered should never come from the current last line + ' if WriteCenteredLine is called, it immediately creates a new line + Lines(Lines.Count - 1) = (currentLast.line + line, centered) + Else + Lines.Add((line, centered)) + End If + End Sub) + End Sub + + Public Overrides Sub Write(value As Object) + WriteString(value?.ToString) + End Sub + + Public Overrides Sub WriteLine(value As Object) + WriteString(value?.ToString) + WriteLine() + End Sub + + Public Overrides Sub WriteLine() + Lines.Add(("", False)) + End Sub + + Public Overrides Sub WriteCenteredLine(value As Object) + If Lines.Count = 0 Then Lines.Add(("", False)) + Dim currentLast = Lines(Lines.Count - 1).line + If currentLast.Length > 0 Then Throw New InvalidOperationException("Can only write centered line if cursor is at start of line.") + WriteString(value?.ToString, True) + WriteLine() + End Sub + + Public Overrides Function ReadLine() As String + ' Indicates the end of a test run, for programs which loop endlessly + If inputs.Count = 0 Then Throw New EndOfStreamException("End of inputs") + + Dim nextInput = inputs.Dequeue.Trim + WriteLine(nextInput) + Return nextInput + End Function +End Class diff --git a/03_Animal/vbnet/Animal.Tests/TestContainer.vb b/03_Animal/vbnet/Animal.Tests/TestContainer.vb new file mode 100644 index 00000000..3aed862a --- /dev/null +++ b/03_Animal/vbnet/Animal.Tests/TestContainer.vb @@ -0,0 +1,80 @@ +Imports Xunit +Imports Animal +Imports System.IO + +Public Class TestContainer + Private Shared Function ResponseVariantExpander(src As IEnumerable(Of String)) As TheoryData(Of String) + Dim theoryData = New TheoryData(Of String) + src. + SelectMany(Function(x) {x, x.Substring(0, 1)}). + SelectMany(Function(x) { + x, + x.ToUpperInvariant, + x.ToLowerInvariant, + x.ToTitleCase, + x.ToReverseCase + }). + Distinct. + ForEach(Sub(x) theoryData.Add(x)) + Return theoryData + End Function + Private Shared YesVariantsThepryData As TheoryData(Of String) = ResponseVariantExpander({"yes", "true", "1"}) + Private Shared Function YesVariants() As TheoryData(Of String) + Return YesVariantsThepryData + End Function + Private Shared NoVariantsThepryData As TheoryData(Of String) = ResponseVariantExpander({"no", "false", "0"}) + Private Shared Function NoVariants() As TheoryData(Of String) + Return NoVariantsThepryData + End Function + + ''' Test LIST variants + + + + + + Sub List(listResponse As String) + Dim console As New MockConsole({listResponse}) + Dim game As New Game(console) + Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop()) + Assert.Equal( + { + "ANIMALS I ALREADY KNOW ARE:", + "FISH BIRD " + }, + console.Lines.Slice(-4, -2).Select(Function(x) x.line) + ) + End Sub + + '' Test YES variants + + + Sub YesVariant(yesVariant As String) + Dim console As New MockConsole({yesVariant}) + Dim game As New Game(console) + Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop()) + Assert.Equal( + { + $"ARE YOU THINKING OF AN ANIMAL? {yesVariant}", + "DOES IT SWIM? " + }, + console.Lines.Slice(-2, 0).Select(Function(x) x.line) + ) + End Sub + + '' Test NO variants + + + Sub NoVariant(noVariant As String) + Dim console As New MockConsole({"y", noVariant}) + Dim game As New Game(console) + Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop()) + Assert.Equal( + { + $"DOES IT SWIM? {noVariant}", + "IS IT A BIRD? " + }, + console.Lines.Slice(-2, 0).Select(Function(x) x.line) + ) + End Sub +End Class diff --git a/03_Animal/vbnet/Animal.Tests/UnitTest1.vb b/03_Animal/vbnet/Animal.Tests/UnitTest1.vb deleted file mode 100644 index fe32490e..00000000 --- a/03_Animal/vbnet/Animal.Tests/UnitTest1.vb +++ /dev/null @@ -1,12 +0,0 @@ -Imports System -Imports Xunit - -Namespace Animal.Tests - Public Class UnitTest1 - - Sub TestSub() - - End Sub - End Class -End Namespace - diff --git a/03_Animal/vbnet/Animal/Shared/ConsoleAdapter.vb b/03_Animal/vbnet/Animal/Shared/ConsoleAdapter.vb index 132f1968..f49394e0 100644 --- a/03_Animal/vbnet/Animal/Shared/ConsoleAdapter.vb +++ b/03_Animal/vbnet/Animal/Shared/ConsoleAdapter.vb @@ -14,6 +14,7 @@ End Sub Public Overrides Sub WriteCenteredLine(value As Object) + If Console.CursorLeft <> 0 Then Throw New InvalidOperationException("Can only write centered line if cursor is at start of line.") Dim toWrite = If(value?.ToString, "") Console.WriteLine($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}") End Sub diff --git a/03_Animal/vbnet/Animal/Shared/Extensions.vb b/03_Animal/vbnet/Animal/Shared/Extensions.vb index 83d1914b..e10df441 100644 --- a/03_Animal/vbnet/Animal/Shared/Extensions.vb +++ b/03_Animal/vbnet/Animal/Shared/Extensions.vb @@ -1,6 +1,11 @@ Imports System.Runtime.CompilerServices Public Module Extensions + Public Sub ForEach(Of T)(src As IEnumerable(Of T), action As Action(Of T)) + For Each x In src + action(x) + Next + End Sub Public Sub ForEach(Of T)(src As IEnumerable(Of T), action As Action(Of T, Integer)) Dim index As Integer For Each x In src @@ -18,4 +23,28 @@ Public Module Extensions If Not s.EndsWith(toAppend, StringComparison.OrdinalIgnoreCase) Then s += toAppend Return s End Function + + Public Function ToTitleCase(s As String) As String + If s Is Nothing Then Return Nothing + Return Char.ToUpperInvariant(s(0)) + s.Substring(1).ToUpperInvariant + End Function + + ' https://stackoverflow.com/a/3681580/111794 + Public Function ToReverseCase(s As String) As String + If s Is Nothing Then Return Nothing + Return New String(s.Select(Function(c) If( + Not Char.IsLetter(c), + c, + If( + Char.IsUpper(c), Char.ToLowerInvariant(c), Char.ToUpperInvariant(c) + ) + )).ToArray) + End Function + + ' https://stackoverflow.com/a/58132204/111794 + Public Function Slice(Of T)(lst As IList(Of T), start As Integer, [end] As Integer) As T() + start = If(start >= 0, start, lst.Count + start) + [end] = If([end] > 0, [end], lst.Count + [end]) + Return lst.Skip(start).Take([end] - start).ToArray + End Function End Module