Remove Tape.GetState method. Add Equals method. Fix unit tests
authorMichael Welch <michaelgwelch@gmail.com>
Tue, 21 Feb 2012 21:03:01 +0000 (15:03 -0600)
committerMichael Welch <michaelgwelch@gmail.com>
Tue, 21 Feb 2012 21:03:01 +0000 (15:03 -0600)
src.net/BrainmessCore/BrainmessCore.csproj
src.net/BrainmessCore/Collection.cs [new file with mode: 0644]
src.net/BrainmessCore/StringExtensions.cs
src.net/BrainmessCore/Tape.cs
src.net/BrainmessCoreTests/InstructionTests.cs
src.net/BrainmessCoreTests/InterpreterTests.cs
src.net/BrainmessCoreTests/TapeTests.cs

index e43e4af..5c94fef 100644 (file)
@@ -40,6 +40,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Collection.cs" />
     <Compile Include="Instruction.cs" />
     <Compile Include="Interpreter.cs" />
     <Compile Include="IProgram.cs" />
diff --git a/src.net/BrainmessCore/Collection.cs b/src.net/BrainmessCore/Collection.cs
new file mode 100644 (file)
index 0000000..3076f46
--- /dev/null
@@ -0,0 +1,37 @@
+\feffusing System.Collections;
+using System.Linq;
+
+namespace Welch.Brainmess
+{
+    public static class Collection
+    {
+        public static bool IsEqualTo(this ICollection col1, ICollection col2)
+        {
+            if (ReferenceEquals(col1, col2)) return true;
+            if (col1 == null || col2 == null) return false;
+
+            if (col1.Count != col2.Count) return false;
+
+            var iter1 = col1.GetEnumerator();
+            var iter2 = col2.GetEnumerator();
+
+            while(iter1.MoveNext() && iter2.MoveNext())
+            {
+                if (!Equals(iter1.Current, iter2.Current)) return false;
+            }
+
+            return true;
+        }
+
+        public static int HashCode(this IEnumerable items)
+        {
+            unchecked
+            {
+                if (items == null) return 0;
+
+                return items.Cast<object>().Aggregate(17, 
+                    (current, item) => current + ((19 * current) + (Equals(item, null) ? 0 : item.GetHashCode())));
+            }            
+        }
+    }
+}
index 55c656d..d9f1c96 100644 (file)
@@ -1,5 +1,4 @@
 using System;
-using System.Diagnostics;
 
 namespace Welch.Brainmess
 {
index c954c27..bb88e93 100644 (file)
@@ -1,7 +1,6 @@
 using System;
 using System.Diagnostics;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Linq;
 
 namespace Welch.Brainmess
@@ -25,7 +24,7 @@ namespace Welch.Brainmess
         /// </summary>
         public static Tape Default
         {
-            get { return LoadState(Enumerable.Range(0, 1)); }
+            get { return LoadState(Enumerable.Range(0, 1), 0); }
         }
 
         /// <summary>
@@ -36,7 +35,7 @@ namespace Welch.Brainmess
         /// <param name="cells">A sequence of integers to load onto the new tape.</param>
         /// <param name="position">An "index" into <paramref name="cells"/> that indicates which one should
         /// be considered the current cell for the initial state of the tape.</param>
-        public static Tape LoadState(IEnumerable<int> cells, int position = 0)
+        public static Tape LoadState(IEnumerable<int> cells, int position)
         {
             if (cells == null) throw new ArgumentNullException("cells");
             var array = cells.ToArray(); 
@@ -60,62 +59,6 @@ namespace Welch.Brainmess
             return new Tape(currentNode);
         }
 
-        /// <summary>
-        /// Clones the state of this instance and returns it as an 
-        /// instance of <see cref="State"/>.
-        /// </summary>
-        /// <returns></returns>
-        public State GetState()
-        {
-            return State.From(this);
-        }
-
-        /// <summary>
-        /// Represents the state of a Tape at a specific point in time.
-        /// All of the cells that have ever been visited are copied into an array
-        /// named Cells, and the current cell is indicated by an index into that
-        /// array named Position.
-        /// </summary>
-        public class State
-        {
-            /// <summary>
-            /// Indicate the cell that was current at the moment this instance
-            /// was created.
-            /// </summary>
-            public int Position { get; private set; }
-            
-            /// <summary>
-            /// The sequence of integers that were on the tape (in the order they were on the 
-            /// tape) at the moment this instance was created.
-            /// </summary>
-            public ReadOnlyCollection<int> Cells { get; private set; }
-
-            /// <summary>
-            /// Creates an instance of <see cref="State"/> by copying the state information
-            /// from <paramref name="tape"/>.
-            /// </summary>
-            /// <param name="tape"></param>
-            /// <returns></returns>
-            public static State From(Tape tape)
-            {
-                var list = tape._currentCell.List;
-                var node = list.First;
-                var position = 0;
-                while(node != tape._currentCell)
-                {
-                    Debug.Assert(node != null); // This quiets the Resharper warning. We no for sure this will never be null.
-                    node = node.Next;
-                    position++;
-                }
-
-                return new State
-                           {
-                               Cells = new ReadOnlyCollection<int>(tape._currentCell.List.ToArray()),
-                               Position = position
-                           };
-            }
-        }
-
         private Tape(LinkedListNode<int> startingCell)
         {
             // This is a private constructor so I assume that I'll always call it correctly.
@@ -173,6 +116,25 @@ namespace Welch.Brainmess
                 _currentCell.Value = value;
             }
         }
+
+        public override bool Equals(object obj)
+        {
+            if (obj == null) return false;
+            if (!(obj is Tape)) return false;
+
+            Tape other = (Tape)obj;
+            return _currentCell.List.IsEqualTo(other._currentCell.List) &&
+                   _currentCell.IndexOf() == other._currentCell.IndexOf();
+        }
+
+        /// <summary>
+        /// Does not provide a userful implementation. Always returns 0.
+        /// </summary>
+        /// <returns></returns>
+        public override int GetHashCode()
+        {
+            return 0;
+        }
     }
 }
 
index 888beb3..9cb2b66 100644 (file)
@@ -11,9 +11,9 @@ namespace Welch.Brainmess
         // is done in other classes, Tape, Program, etc. Most of the instructions are one line
         // and need only one test. The bulk of the testing is then done on Tape and Program
 
-        private static readonly Program _nullProgram  = null;
-        private static readonly TextReader _nullInput = null;
-        private static readonly TextWriter _nullOutput = null;
+        private static readonly Program NullProgram = Identity<Program>(null);
+        private static readonly TextReader NullInput = Identity<TextReader>(null);
+        private static readonly TextWriter NullOutput = Identity<TextWriter>(null);
 
         // ReSharper disable InconsistentNaming
         [TestMethod]
@@ -21,15 +21,14 @@ namespace Welch.Brainmess
         {
             // Arrange
             const int startingPosition = 1;
-            var tape = Tape.LoadState(new[] { 1, 3, 5 }, startingPosition);
+            var expectedTape = Tape.LoadState(new[] { 1, 3, 5 }, 2);
+            var actualTape = Tape.LoadState(new[] { 1, 3, 5 }, startingPosition);
 
             // Act
-            Instruction.MoveForward.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.MoveForward.Execute(NullProgram, actualTape, NullInput, NullOutput);
 
             // Assert
-            var actualEndingPosition = tape.GetState().Position;
-            const int expectedEndingPosition = 2;
-            Assert.AreEqual(expectedEndingPosition, actualEndingPosition);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [TestMethod]
@@ -37,56 +36,57 @@ namespace Welch.Brainmess
         {
             // Arrange
             const int startingPosition = 1;
-            var tape = Tape.LoadState(new[] { 1, 3, 5 }, startingPosition);
+            var expectedTape = Tape.LoadState(new[] { 1, 3, 5 }, 0);
+            var actualTape = Tape.LoadState(new[] { 1, 3, 5 }, startingPosition);
 
             // Act
-            Instruction.MoveBackward.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.MoveBackward.Execute(NullProgram, actualTape, NullInput, NullOutput);
 
             // Assert
-            var actualEndingPosition = tape.GetState().Position;
-            const int expectedEndingPosition = 0;
-
-            Assert.AreEqual(expectedEndingPosition, actualEndingPosition);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [TestMethod]
         public void IncrementExecution_ShouldIncrementCurrentCell()
         {
             // Arrange
-            var tape = Tape.LoadState(new[] { 5, 7, 9 }, 1);
+            var expectedTape = Tape.LoadState(new[] { 5, 8, 9 }, 1);
+            var actualTape = Tape.LoadState(new[] { 5, 7, 9 }, 1);
 
             // Act
-            Instruction.Increment.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.Increment.Execute(NullProgram, actualTape, NullInput, NullOutput);
 
             // Assert - Expect number at index 1 to have been incrmented
-            CollectionAssert.AreEqual(new[] { 5, 8, 9 }, tape.GetState().Cells);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [TestMethod]
         public void DecrementExecution_AtIndex1_ShouldDecrementTheValueAtIndex1()
         {
             // Arrange
-            var tape = Tape.LoadState(new[] { 5, 7, 9 }, 1);
+            var expectedTape = Tape.LoadState(new[] { 5, 6, 9 }, 1);
+            var actualTape = Tape.LoadState(new[] { 5, 7, 9 }, 1);
 
             // Act
-            Instruction.Decrement.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.Decrement.Execute(NullProgram, actualTape, NullInput, NullOutput);
 
             // Assert - Expect number at index 1 to have been incrmented
-            CollectionAssert.AreEqual(new[] { 5, 6, 9 }, tape.GetState().Cells);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [TestMethod]
         public void InputExecution_ShouldReadFromInputAtWriteToTape()
         {
             // Arrange
-            var tape = Tape.LoadState(new[] { 10, 11, 12 }, 1);
+            var expectedTape = Tape.LoadState(new[] { 10, 65, 12 }, 1);
+            var actualTape = Tape.LoadState(new[] { 10, 11, 12 }, 1);
             var input = CreateReaderWithNextCharacterEqualTo((char)65);
 
             // Act
-            Instruction.Input.Execute(_nullProgram, tape, input, _nullOutput);
+            Instruction.Input.Execute(NullProgram, actualTape, input, NullOutput);
 
             // Assert
-            CollectionAssert.AreEqual(new[] { 10, 65, 12 }, tape.GetState().Cells);
+            Assert.AreEqual(expectedTape, actualTape);
 
         }
 
@@ -102,7 +102,7 @@ namespace Welch.Brainmess
                              };
 
             // Act
-            Instruction.Output.Execute(_nullProgram, tape, _nullInput, output);
+            Instruction.Output.Execute(NullProgram, tape, NullInput, output);
 
             // Assert
             var bytes = stream.ToArray();
@@ -111,22 +111,20 @@ namespace Welch.Brainmess
             Assert.AreEqual(57, reader.Read());
         }
 
+        
         [TestMethod]
         public void TestAndJumpFowardExecution_WithTapeNotEqualToZero_ShouldDoNothing()
         {
             // Arrange
-            var cells = new[] { 0, 24, 0 };
-            const int pos = 1;
-
-            var tape = Tape.LoadState(cells, pos);
+            var mock = new Mock<IProgram>(MockBehavior.Strict); // any call to program should cause failure.
+            var actualTape = Tape.LoadState(new[] { 1 }, 0);
+            var expectedTape = Tape.LoadState(new[] { 1 }, 0);
 
             // Act
-            Instruction.TestAndJumpForward.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.TestAndJumpForward.Execute(mock.Object, actualTape, NullInput, NullOutput);
 
             // Assert
-            var state = tape.GetState();
-            Assert.AreEqual(pos, state.Position);
-            CollectionAssert.AreEqual(cells, state.Cells);
+            Assert.AreEqual(expectedTape, actualTape); // No change to tape
         }
 
         [TestMethod]
@@ -138,7 +136,7 @@ namespace Welch.Brainmess
             mock.Setup(program => program.JumpForward());
 
             // Act
-            Instruction.TestAndJumpForward.Execute(mock.Object, tape, _nullInput, _nullOutput);
+            Instruction.TestAndJumpForward.Execute(mock.Object, tape, NullInput, NullOutput);
 
             // Assert
             mock.VerifyAll();
@@ -149,18 +147,15 @@ namespace Welch.Brainmess
         public void TestAndJumpBackwardExecution_WithTapeEqualToZero_ShouldDoNothing()
         {
             // Arrange
-            var cells = new[] { 0, 0, 0 };
-            const int pos = 1;
-
-            var tape = Tape.LoadState(cells, pos);
+            var mock = new Mock<IProgram>(MockBehavior.Strict);
+            var expectedTape = Tape.LoadState(new[] { 0, 0, 0 }, 1);
+            var actualTape = Tape.LoadState(new[] { 0, 0, 0 }, 1);
 
             // Act
-            Instruction.TestAndJumpBackward.Execute(_nullProgram, tape, _nullInput, _nullOutput);
+            Instruction.TestAndJumpBackward.Execute(mock.Object, actualTape, NullInput, NullOutput);
 
             // Assert
-            var state = tape.GetState();
-            Assert.AreEqual(pos, state.Position);
-            CollectionAssert.AreEqual(cells, state.Cells);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [TestMethod]
@@ -172,7 +167,7 @@ namespace Welch.Brainmess
             mock.Setup(program => program.JumpBackward());
 
             // Act
-            Instruction.TestAndJumpBackward.Execute(mock.Object, tape, _nullInput, _nullOutput);
+            Instruction.TestAndJumpBackward.Execute(mock.Object, tape, NullInput, NullOutput);
 
             // Assert
             mock.VerifyAll();
@@ -185,7 +180,7 @@ namespace Welch.Brainmess
             // Arrange
 
             // Act
-            Instruction.NoOperation.Execute(_nullProgram, null, _nullInput, _nullOutput);
+            Instruction.NoOperation.Execute(NullProgram, null, NullInput, NullOutput);
 
             // Assert
             
@@ -271,6 +266,14 @@ namespace Welch.Brainmess
 
         }
 
+        /// <summary>
+        /// The Identity function. Returns the specified value.
+        /// Useful for quieting Resharper warnings about null.
+        /// </summary>
+        public static T Identity<T>(T value)
+        {
+            return value;
+        }
 
         // ReSharper restore InconsistentNaming
     }
index 64b2dd2..f1e3ad5 100644 (file)
@@ -38,16 +38,16 @@ namespace Welch.Brainmess
             var mock = new Mock<IProgram>(MockBehavior.Strict);
             mock.Setup(prog => prog.EndOfProgram).ReturnsInOrder(false, true);
             mock.Setup(prog => prog.Fetch()).Returns(Instruction.Increment);
-            var tape = Tape.Default;
+            var expectedTape = Tape.LoadState(new[] { 1 }, 0);
+            var actualTape = Tape.Default;
             var program = mock.Object;
-            var interpreter = new Interpreter(program, tape);
+            var interpreter = new Interpreter(program, actualTape);
 
             // Act
             interpreter.Run();
 
             // Assert
-            var state = tape.GetState();
-            Assert.AreEqual(1, state.Cells[state.Position]);
+            Assert.AreEqual(expectedTape, actualTape);
 
 
         }
@@ -98,9 +98,7 @@ namespace Welch.Brainmess
 
             // Assert
             Assert.AreEqual(0, program.ProgramCounter);
-            var state = tape.GetState();
-            Assert.AreEqual(0, state.Position);
-            CollectionAssert.AreEqual(new[] {0}, state.Cells);
+            Assert.AreEqual(tape, Tape.Default);
         }
 
         [TestMethod]
@@ -117,7 +115,9 @@ namespace Welch.Brainmess
         public override int Read()
         {
             Assert.Fail("Did not expect a Read");
+// ReSharper disable HeuristicUnreachableCode
             return 0;
+// ReSharper restore HeuristicUnreachableCode
         }
     }
 
index 2603640..61020d5 100644 (file)
@@ -27,13 +27,13 @@ namespace Welch.Brainmess
         [Test]
         public void Current_ConstructPrePopulatedTape_ExpectCurrentToMatch()
         {
-            // Assemble
+            // Arrange
             const int expectedValue = 55;
             var list = new LinkedList<int>();
             list.AddFirst(expectedValue);
 
             // Act
-            var tape = Tape.LoadState(list);
+            var tape = Tape.LoadState(list, 0);
 
             // Assert - The first value in the list should equal the value of the current cell on the tape.
             Assert.AreEqual(expectedValue, tape.Current);
@@ -43,108 +43,103 @@ namespace Welch.Brainmess
         public void SetCurrent_StateShouldChange()
         {
             // Arrange
-            var tape = Tape.LoadState(new[] { 1, 2, 1 }, 1);
+            var expectedTape = Tape.LoadState(new[] { 1, 23, 1 }, 1);
+            var actualTape = Tape.LoadState(new[] { 1, 2, 1 }, 1);
 
             // Act
-            tape.Current = 23;
+            actualTape.Current = 23;
 
             // Assert
-            CollectionAssert.AreEqual(new[] { 1, 23, 1 }, tape.GetState().Cells);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [Test]
         public void Increment_ConstructFromValues_ExpectIncrementToIncrementTheCell()
         {
-            // Assemble
-            var list = new LinkedList<int>(new [] {22});
-            var tape = Tape.LoadState(list);
+            // Arrange
+            var expectedTape = Tape.LoadState(new[] { 23 }, 0);
+            var actualTape = Tape.LoadState(new[] { 22 }, 0);
 
             // Act
-            tape.Increment();
+            actualTape.Increment();
 
             // Assert
-            Tape.State state = tape.GetState();
-            Assert.AreEqual(23, state.Cells[state.Position]);
+            Assert.AreEqual(expectedTape, actualTape);
 
         }
 
         [Test]
         public void Decrement_ConstructFromValues_ExpectDecrementToDecrementTheCell()
         {
-            // Assemble
-            var list = new LinkedList<int>(new[] {45});
-            var tape = Tape.LoadState(list);
+            // Arrange
+            var expectedTape = Tape.LoadState(new[] { 44 }, 0);
+            var actualTape = Tape.LoadState(new[] {45}, 0);
 
             // Act
-            tape.Decrement();
+            actualTape.Decrement();
 
             // Assert
-            Tape.State state = tape.GetState();
-            Assert.AreEqual(44, state.Cells[state.Position]);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [Test]
         public void MoveForward_ConstructDefaultAndMoveFoward_ExpectPositionToEqualOne()
         {
-            // Assemble
-            var tape = Tape.Default;
+            // Arrange
+            var expectedTape = Tape.LoadState(new[] { 0, 0 }, 1);
+            var actualTape = Tape.Default;
 
             // Act
-            tape.MoveForward(); // Method being tested.
+            actualTape.MoveForward(); // Method being tested.
 
             // Assert
-            Tape.State state = tape.GetState();
-            Assert.AreEqual(1, state.Position);
-
+            Assert.AreEqual(expectedTape, actualTape);
 
         }
 
         [Test]
         public void MoveForward_ConstructFromMultiCellListMoveForwardAndMutate_ExpectSecondCellMatchesValue()
         {
-            // Assemble
-            var initialList = new [] { 1, 3, 5, 7, 11, 13, 17, 19 };
-            const int position = 4;
-            var tape = Tape.LoadState(initialList, position);
+            // Arrange
+            var cells = new [] { 1, 3, 5, 7, 11, 13, 17, 19 };
+            var expectedTape = Tape.LoadState(cells, 5);
+            var actualTape = Tape.LoadState(cells, 4);
 
             // Act
-            tape.MoveForward();
+            actualTape.MoveForward();
 
             // Assert
-            var state = tape.GetState();
-            Assert.AreEqual(5, state.Position);
+            Assert.AreEqual(expectedTape, actualTape);
 
         }
 
         [Test]
         public void MoveBackward_ConstructFromMutiCellListMoveBackwardAndMutate_ExpectSecondFromLastCellMatchesValue()
         {
-            // Assemble - construct a tape from a list and set current cell to last value in list.
-            var initialList = new [] { 19, 17, 13, 11, 7, 5, 3, 1 };
-            const int startPosition = 7;
-            var tape = Tape.LoadState(initialList, startPosition);
+            // Arrange - construct a tape from a list and set current cell to last value in list.
+            var values = new [] { 19, 17, 13, 11, 7, 5, 3, 1 };
+            var expectedTape = Tape.LoadState(values, 6);
+            var actualTape = Tape.LoadState(values, 7);
 
             // Act
-            tape.MoveBackward();
+            actualTape.MoveBackward();
 
             // Assert
-            var state = tape.GetState();
-            const int endingPosition = 6;
-            Assert.AreEqual(endingPosition, state.Position);
+            Assert.AreEqual(expectedTape, actualTape);
         }
 
         [Test]
         public void MoveBackward_ConstructFromSingleCellListMoveBackwardAndMutate_ExpectFirstCellToMatch()
         {
-            // Assemble
-            var tape = Tape.Default;
+            // Arrange
+            var expectedTape = Tape.LoadState(new[] { 0, 0 }, 0);
+            var actualTape = Tape.Default;
 
             // Act
-            tape.MoveBackward();
+            actualTape.MoveBackward();
 
             // Assert
-            var state = tape.GetState();
-            Assert.AreEqual(0, state.Position);
+            Assert.AreEqual(expectedTape, actualTape);
 
         }
 
@@ -153,7 +148,7 @@ namespace Welch.Brainmess
         {
             try
             {
-                Tape.LoadState(null);
+                Tape.LoadState(null, 0);
                 Assert.Fail("Expect ArgumentNullException");
             }
             catch (ArgumentNullException)