summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Scenes/Game.tscn6
-rw-r--r--Scripts/Command.cs22
-rw-r--r--Scripts/CommandParser.cs27
-rw-r--r--Scripts/Commands/LookCommand.cs57
-rw-r--r--Scripts/OutputRow.cs8
-rw-r--r--Tests/ComponentTests/ParserTests/CommandParserTestBase.gd29
-rw-r--r--Tests/ComponentTests/ParserTests/test_CommandParser.gd9
-rw-r--r--Tests/ComponentTests/ParserTests/test_LookCommand.gd55
-rw-r--r--Texty.csproj12
-rw-r--r--project.godot6
10 files changed, 209 insertions, 22 deletions
diff --git a/Scenes/Game.tscn b/Scenes/Game.tscn
index 5c24cf2..5988f7d 100644
--- a/Scenes/Game.tscn
+++ b/Scenes/Game.tscn
@@ -1,9 +1,10 @@
-[gd_scene load_steps=5 format=2]
+[gd_scene load_steps=6 format=2]
[ext_resource path="res://Scenes/InputContainer.tscn" type="PackedScene" id=1]
[ext_resource path="res://Scripts/Game.cs" type="Script" id=2]
[ext_resource path="res://Scenes/OutputContainer.tscn" type="PackedScene" id=3]
[ext_resource path="res://Scenes/OutputRow.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Scripts/CommandParser.cs" type="Script" id=5]
[node name="Game" type="MarginContainer"]
anchor_right = 1.0
@@ -18,6 +19,9 @@ __meta__ = {
}
OutputRowScene = ExtResource( 4 )
+[node name="CommandParser" type="Node" parent="."]
+script = ExtResource( 5 )
+
[node name="LayoutContainer" type="VBoxContainer" parent="."]
margin_right = 1008.0
margin_bottom = 584.0
diff --git a/Scripts/Command.cs b/Scripts/Command.cs
index 4a7ce58..e784576 100644
--- a/Scripts/Command.cs
+++ b/Scripts/Command.cs
@@ -1,7 +1,25 @@
+using Godot;
+
namespace Texty.Scripts
{
- public class Command
+ public enum CommandType
{
-
+ Look
+ }
+
+ public class Command : Object
+ {
+ public Command()
+ {
+ }
+
+ public Command(CommandType type, string[] arguments)
+ {
+ RawArguments = arguments;
+ Type = type;
+ }
+
+ public string[] RawArguments { get; }
+ public CommandType Type { get; }
}
} \ No newline at end of file
diff --git a/Scripts/CommandParser.cs b/Scripts/CommandParser.cs
index 1394a5e..97d8025 100644
--- a/Scripts/CommandParser.cs
+++ b/Scripts/CommandParser.cs
@@ -1,14 +1,23 @@
+using System.Linq;
using Godot;
+using Texty.Scripts.Commands;
namespace Texty.Scripts
{
- public class CommandParser : Node
- {
-
- public override void _Ready()
- {
- }
-
- }
-}
+ public class CommandParser : Node
+ {
+ public override void _Ready()
+ {
+ }
+ public Command TryParse(string text)
+ {
+ var components = text.Split(' ');
+ return components[0].ToLower() switch
+ {
+ "look" => new LookCommand(components.Skip(1).ToArray()),
+ _ => null
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/Scripts/Commands/LookCommand.cs b/Scripts/Commands/LookCommand.cs
new file mode 100644
index 0000000..08783a9
--- /dev/null
+++ b/Scripts/Commands/LookCommand.cs
@@ -0,0 +1,57 @@
+using System.Linq;
+
+namespace Texty.Scripts.Commands
+{
+ public enum LookModifier
+ {
+ At,
+ Around
+ }
+
+ public class LookCommand : Command
+ {
+ public LookCommand()
+ {
+ }
+
+ public LookCommand(string[] arguments) : base(CommandType.Look, arguments)
+ {
+ (Modifier, arguments) = TryParseModifier(arguments);
+ Target = string.Join(" ", arguments);
+ }
+
+ public string Target { get; }
+ public LookModifier? Modifier { get; }
+
+ /// <summary>
+ /// Access this <c>LookCommand</c>'s modifier as a string.
+ /// </summary>
+ /// <remarks>
+ /// This function is provided as a means for testing the modifier parsing from GDScript.
+ /// </remarks>
+ private string ModifierAsString => Modifier?.ToString();
+
+ public override string ToString()
+ {
+ return $"look {ModifierAsString?.ToLower()} {string.Join(" ", Target)}";
+ }
+
+ /// <summary>
+ /// Try to parse this <c>LookCommand</c>'s modifier from the given arguments.
+ /// </summary>
+ /// <param name="arguments">The arguments given to this look commands</param>
+ /// <returns>A pair consisting of the parse modifier and the remaining arguments</returns>
+ private static (LookModifier?, string[]) TryParseModifier(string[] arguments)
+ {
+ if (arguments.Length == 0)
+ return (null, arguments);
+
+ return arguments[0].ToLower() switch
+ {
+ "at" => (LookModifier.At, arguments.Skip(1).ToArray()),
+ "around" => (LookModifier.Around, new string[] { }),
+ _ => (null, arguments)
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/Scripts/OutputRow.cs b/Scripts/OutputRow.cs
index 15a6454..13d9293 100644
--- a/Scripts/OutputRow.cs
+++ b/Scripts/OutputRow.cs
@@ -11,12 +11,12 @@ namespace Texty.Scripts
[Signal]
public delegate void OutputTextChanged(string newText);
- public Label Input;
- public Label Output;
-
private string _inputText = "";
private string _outputText = "";
+ public Label Input;
+ public Label Output;
+
[Export]
public string InputText
{
@@ -69,4 +69,4 @@ namespace Texty.Scripts
Output
}
}
-} \ No newline at end of file
+} \ No newline at end of file
diff --git a/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd b/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd
new file mode 100644
index 0000000..6e452cb
--- /dev/null
+++ b/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd
@@ -0,0 +1,29 @@
+extends GutTest
+
+class_name CommandParserTestBase
+
+const CommandParser = preload("res://Scripts/CommandParser.cs")
+
+var _instance: CommandParser
+
+func _to_bits(number: int, bits: int) -> Array:
+ var result = []
+ for bit in bits:
+ result.append(number & 1)
+ number = number >> 1
+ return result
+
+func before_each():
+ _instance = autofree(CommandParser.new())
+
+func generate_capitalization_permutations(text: String) -> Array:
+ var result = []
+
+ for permutation in pow(2, text.length()):
+ var mask = _to_bits(permutation, text.length())
+ var copy = String(text)
+ for index in len(mask):
+ if mask[index] == 1:
+ copy[index] = copy[index].to_upper()
+ result.append(copy)
+ return result;
diff --git a/Tests/ComponentTests/ParserTests/test_CommandParser.gd b/Tests/ComponentTests/ParserTests/test_CommandParser.gd
new file mode 100644
index 0000000..bdb14a6
--- /dev/null
+++ b/Tests/ComponentTests/ParserTests/test_CommandParser.gd
@@ -0,0 +1,9 @@
+extends CommandParserTestBase
+
+const Command = preload("res://Scripts/Command.cs")
+
+func parse(input: String) -> Command:
+ return autofree(_instance.TryParse(input))
+
+func test_parsing_the_empty_string_returns_null():
+ assert_null(parse(''))
diff --git a/Tests/ComponentTests/ParserTests/test_LookCommand.gd b/Tests/ComponentTests/ParserTests/test_LookCommand.gd
new file mode 100644
index 0000000..32268b0
--- /dev/null
+++ b/Tests/ComponentTests/ParserTests/test_LookCommand.gd
@@ -0,0 +1,55 @@
+extends CommandParserTestBase
+
+const LookCommand = preload("res://Scripts/Commands/LookCommand.cs")
+
+var _around_permutations = generate_capitalization_permutations('around')
+var _at_permutations = generate_capitalization_permutations('at')
+var _look_permutations = generate_capitalization_permutations('look')
+
+func parse(input: String) -> LookCommand:
+ return autofree(_instance.TryParse(input))
+
+func test_parsing_look_command_without_an_argument_returns_non_null():
+ assert_not_null(parse('look'))
+
+func test_parsing_look_command_is_case_insensitive(permutation=use_parameters(_look_permutations)):
+ assert_not_null(parse(permutation))
+
+func test_parsing_look_command_without_an_argument_returns_look_command_with_an_emtpy_target():
+ assert_eq('', parse('look').Target)
+
+func test_parsing_look_at_command_is_case_insensitive(permutation=use_parameters(_at_permutations)):
+ assert_not_null(parse('look ' + permutation))
+
+func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_an_emtpy_target():
+ assert_eq('', parse('look at').Target)
+
+func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_non_null_modifier():
+ assert_not_null(parse('look at').Modifier)
+
+func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_at_modifier():
+ assert_eq('At', parse('look at').ModifierAsString)
+
+func test_parsing_look_at_command_with_more_arguments_returns_look_command_with_non_empty_target():
+ assert_ne('', parse('look at door on the left').Target)
+
+func test_parsing_look_at_command_with_an_additional_argument_returns_look_command_with_the_additional_argument_as_the_target():
+ assert_eq('window', parse('look at window').Target)
+
+func test_parsing_look_at_command_with_multiple_additional_arguments_returns_look_command_with_the_additional_arguments_as_the_target():
+ assert_eq('table near the door', parse('look at table near the door').Target)
+
+func test_parsing_look_around_command_is_case_insensitive(permutation=use_parameters(_around_permutations)):
+ assert_not_null(parse('look ' + permutation))
+
+func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_an_empty_target():
+ assert_eq('', parse('look around').Target)
+
+func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_non_null_modifier():
+ assert_not_null(parse('look around').Modifier)
+
+func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_around_modifier():
+ assert_eq('Around', parse('look around').ModifierAsString)
+
+func test_parsing_look_around_command_ignores_all_additional_arguments():
+ assert_eq('', parse('look around the room').Target)
diff --git a/Texty.csproj b/Texty.csproj
index 066bb51..fa11591 100644
--- a/Texty.csproj
+++ b/Texty.csproj
@@ -4,13 +4,13 @@
<LangVersion>8</LangVersion>
</PropertyGroup>
<ItemGroup>
- <Compile Remove="ScriptTemplates\**"/>
- <Compile Remove="Scenes\**"/>
- <Compile Remove="Tests\**"/>
+ <Compile Remove="ScriptTemplates\**" />
+ <Compile Remove="Scenes\**" />
+ <Compile Remove="Tests\**" />
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Remove="ScriptTemplates\**"/>
- <EmbeddedResource Remove="Scenes\**"/>
- <EmbeddedResource Remove="Tests\**"/>
+ <EmbeddedResource Remove="ScriptTemplates\**" />
+ <EmbeddedResource Remove="Scenes\**" />
+ <EmbeddedResource Remove="Tests\**" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/project.godot b/project.godot
index 789ed61..239d5ea 100644
--- a/project.godot
+++ b/project.godot
@@ -9,6 +9,11 @@
config_version=4
_global_script_classes=[ {
+"base": "GutTest",
+"class": "CommandParserTestBase",
+"language": "GDScript",
+"path": "res://Tests/ComponentTests/ParserTests/CommandParserTestBase.gd"
+}, {
"base": "Reference",
"class": "GutHookScript",
"language": "GDScript",
@@ -20,6 +25,7 @@ _global_script_classes=[ {
"path": "res://addons/gut/test.gd"
} ]
_global_script_class_icons={
+"CommandParserTestBase": "",
"GutHookScript": "",
"GutTest": ""
}