Test for added animal; minor fixes

This commit is contained in:
Zev Spitz
2022-01-22 22:27:27 +02:00
parent 9a8959154a
commit 41fdd87047
7 changed files with 88 additions and 35 deletions

View File

@@ -0,0 +1,7 @@
''' <summary>
''' <para>Indicates that there are no more inputs in the MockConsole.</para>
''' We need this while testing, because otherwise the game loop will continue forever, waiting for a nonexistent input.
''' </summary>
Public Class EndOfInputsException
Inherits Exception
End Class

View File

@@ -37,26 +37,21 @@ Public Class MockConsole
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)
Public Overrides Sub WriteCenteredLines(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.")
If currentLast.Length > 0 Then Lines.Add(("", False))
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")
If inputs.Count = 0 Then Throw New EndOfInputsException
Dim nextInput = inputs.Dequeue.Trim
WriteLine(nextInput)

View File

@@ -36,7 +36,7 @@ Public Class TestContainer
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.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
Assert.Equal(
{
"ANIMALS I ALREADY KNOW ARE:",
@@ -52,7 +52,7 @@ Public Class TestContainer
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.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
Assert.Equal(
{
$"ARE YOU THINKING OF AN ANIMAL? {yesVariant}",
@@ -68,7 +68,7 @@ Public Class TestContainer
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.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
Assert.Equal(
{
$"DOES IT SWIM? {noVariant}",
@@ -77,4 +77,42 @@ Public Class TestContainer
console.Lines.Slice(-2, 0).Select(Function(x) x.line)
)
End Sub
''' <summary>Test adding a new animal and using the new animal in the game</summary>
<Fact>
Sub TestAddedAnimal()
Dim console As New MockConsole({
"y",
"y",
"n",
"whale",
"is it a mammal?",
"y",
"y",
"y",
"y",
"y"
})
Dim game As New Game(console)
Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
Assert.Equal(
{
"ARE YOU THINKING OF AN ANIMAL? y",
"DOES IT SWIM? y",
"IS IT A FISH? n",
"THE ANIMAL YOU WERE THINKING OF WAS A ? whale",
"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A",
"WHALE FROM A FISH",
"is it a mammal?",
"FOR A WHALE THE ANSWER WOULD BE? y",
"ARE YOU THINKING OF AN ANIMAL? y",
"DOES IT SWIM? y",
"IS IT A MAMMAL? y",
"IS IT A WHALE? y",
"WHY NOT TRY ANOTHER ANIMAL?",
"ARE YOU THINKING OF AN ANIMAL? "
},
console.Lines.Slice(9, 100).Select(Function(x) x.line)
)
End Sub
End Class

View File

@@ -46,8 +46,11 @@ Public Class Game
Sub BeginLoop()
' Print the program heading
console.WriteCenteredLine("ANIMAL")
console.WriteCenteredLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
console.WriteCenteredLines(
"ANIMAL
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
' Print the program description
console.Write(
"
@@ -64,9 +67,10 @@ THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.
Dim response = console.ReadLine
If response = "list" Then
' List all the stored animals
console.WriteLine(
console.Write(
"
ANIMALS I ALREADY KNOW ARE:")
ANIMALS I ALREADY KNOW ARE:
")
' We're using a ForEach extension method instead of the regular For Each loop to provide the index alongside the text
root.DescendantTexts.ForEach(Sub(text, index)
@@ -76,8 +80,9 @@ ANIMALS I ALREADY KNOW ARE:")
If index > 0 AndAlso index Mod 4 = 0 Then console.WriteLine()
console.Write($"{text.MaxLength(15),-15}")
End Sub)
console.WriteLine(
console.Write(
"
")
Continue Do
End If
@@ -105,25 +110,26 @@ ANIMALS I ALREADY KNOW ARE:")
' Now we're at an end branch
console.Write($"IS IT A {currentBranch.Text}? ")
ynResponse = GetYesNo()
If ynResponse Then ' Only if ynResponse = True will we go into this If Then
If ynResponse Then ' Only if ynResponse = True will we go into this If Then block
' The computer guessed the animal; we can go back to the beginning of the game
console.WriteLine("WHY NOT TRY ANOTHER ANIMAL?")
Continue Do
End If
' Get the new animal
' Get the new animal from the user
console.Write("THE ANIMAL YOU WERE THINKING OF WAS A ? ")
Dim newAnimal = console.ReadLine
Dim newAnimal = console.ReadLine.ToUpperInvariant
' Get the question used to distinguish the new animal from the current end branch
console.WriteLine(
console.Write(
$"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A
{newAnimal} FROM A {currentBranch.Text}")
Dim newQuestion = console.ReadLine
{newAnimal} FROM A {currentBranch.Text}
")
Dim newQuestion = console.ReadLine.ToUpperInvariant
' Get the answer to that question, for the new animal
' for the old animal, the answer would be the opposite
console.Write(
$"FOR A {newAnimal} THE ANSWER WOULD BE ? ")
' for the old animal, the answer will be the opposite
console.Write($"FOR A {newAnimal} THE ANSWER WOULD BE? ")
Do
ynResponse = GetYesNo()
Loop While ynResponse Is Nothing

View File

@@ -5,18 +5,15 @@
Console.Write(value)
End Sub
Public Overrides Sub WriteLine(value As Object)
Console.WriteLine(value)
End Sub
Public Overrides Sub WriteLine()
Console.WriteLine()
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.")
Public Overrides Sub WriteCenteredLines(value As Object)
If Console.CursorLeft <> 0 Then WriteLine()
Dim toWrite = If(value?.ToString, "")
Console.WriteLine($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}")
Write($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}")
WriteLine()
End Sub
Public Overrides Function ReadLine() As String

View File

@@ -1,9 +1,13 @@
Public MustInherit Class ConsoleAdapterBase
Public MustOverride Sub Write(value As Object)
Public MustOverride Sub WriteLine(value As Object)
Public MustOverride Sub WriteLine()
Public MustOverride Sub WriteCenteredLine(value As Object)
Public MustOverride Sub WriteCenteredLines(value As Object)
''' <summary>Implementations should always return a String without leading or trailing whitespace, never Nothng</summary>
Public MustOverride Function ReadLine() As String
Public Sub WriteLine(value As Object)
Write(value)
WriteLine()
End Sub
End Class

View File

@@ -1,3 +1,9 @@
Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
This takes some inspiration from the [C# port of Animal](https://github.com/zspitz/basic-computer-games/tree/main/03_Animal/csharp).
The `Game` class takes a console abstraction (`ConsoleAdapterBase`), which could also be used for different UIs, such as WinForms or a web page.
This solution also has an xUnit tests project.
Responses can be entered in any capitalization, but animals and the distinguishing question will be converted to uppercase.