Showing posts with label NUnit. Show all posts
Showing posts with label NUnit. Show all posts

2011-01-28

Conway's Game of Life Code Kata #2

After yesterday's code retreat, I've refined, refactored, and added some IEnumerable plumbing to the solution I implemented in preparation for the retreat.

It would be a really fun exercise to visualize the generations with WPF, Silverlight or something else. I'd also like to finish the attempts made at the retreat to implement this solution with JavaScript. As one of my pairing partners pointed out, visualization could be done by manipulating the DOM of an ordinary web page.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using SharpTestsEx;

namespace ConwaysGameOfLifeKatas.Generations.UnitTests {
    [Description("en.wikipedia.org/wiki/Conway's_Game_of_Life")]
    public class GenerationsUnitTests {
        [Test]
        public void new_generation_should_kill_alive_cell_with_fewer_than_two_live_neighbours() {
            var generations = new Generations(new Cell(1, 1), new Cell(0, 1));

            generations.First().Contains(new Cell(1, 1)).Should().Be.False();
        }

        [Test]
        public void new_generation_should_keep_alive_cell_with_two_live_neighbours_alive() {
            var generations = new Generations(new Cell(1, 1), new Cell(0, 1), new Cell(2, 1));

            generations.First().Contains(new Cell(1, 1)).Should().Be.True();
        }

        [Test]
        public void new_generation_should_keep_alive_cell_with_three_alive_neighbours_alive() {
            var generations = new Generations(new Cell(1, 1), new Cell(0, 1), new Cell(2, 1), new Cell(0, 0));

            generations.First().Contains(new Cell(1, 1)).Should().Be.True();
        }

        [Test]
        public void new_generation_should_kill_alive_cell_with_more_than_three_alive_neighbours() {
            var generations = new Generations(new Cell(0, 0), new Cell(1, 0), new Cell(2, 0),
                                              new Cell(0, 1), new Cell(1, 1));

            generations.First().Contains(new Cell(1, 1)).Should().Be.False();
        }

        [Test]
        public void new_generation_should_revive_dead_cell_with_three_alive_neighbours() {
            var generation = new Generations(new Cell(0, 0), new Cell(1, 0), new Cell(2, 0));

            generation.First().Contains(new Cell(1, 1)).Should().Be.True();
        }

        [TestCase(0,0,0,false)]
        [TestCase(1,0,0,true)]
        [TestCase(2,0,0,false)]
        [TestCase(0,1,0,false)]
        [TestCase(1,1,0,true)]
        [TestCase(2,1,0,false)]
        [TestCase(0,2,0,false)]
        [TestCase(1,2,0,true)]
        [TestCase(2,2,0,false)]
        [TestCase(0,0,1,false)]
        [TestCase(1,0,1,false)]
        [TestCase(2,0,1,false)]
        [TestCase(0,1,1,true)]
        [TestCase(1,1,1,true)]
        [TestCase(2,1,1,true)]
        [TestCase(0,2,1,false)]
        [TestCase(1,2,1,false)]
        [TestCase(2,2,1,false)]
        public void blinker_oscillator_should_oscillate_according_to_wikipedia(int x, int y, int generationIndex, bool isAlive) {
            var generations = new Generations(new Cell(0, 1), new Cell(1, 1), new Cell(2, 1));

            generations[generationIndex].Contains(new Cell(x, y)).Should().Be.EqualTo(isAlive);
        }
    }

    public class Generations : IEnumerable<Generation> {
        private readonly Generation _seedGeneration;

        public Generations(params Cell[] seed) {
            _seedGeneration= new Generation(seed);
        }

        public IEnumerator<Generation> GetEnumerator() {
            return new GenerationEnumerator(_seedGeneration);
        }

        public Generation this[int index] { 
            get {
                return this.ElementAt(index);
            }
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        public class GenerationEnumerator : IEnumerator<Generation> {
            public GenerationEnumerator(Generation generation) {
                Current = generation;
            }

            public void Dispose() {}

            public bool MoveNext() {
                Current = Current.Tick();

                return true;
            }

            public void Reset() {}

            public Generation Current { get; private set; }

            object IEnumerator.Current {
                get { return Current; }
            }
        }
    }

    public class Generation {
        private readonly ISet<Cell> _aliveCells;

        public Generation(params Cell[] aliveCellsSeed) {
            _aliveCells = new HashSet<Cell>(aliveCellsSeed);
        }

        private IEnumerable<Cell> KeepAlives {
            get {
                return _aliveCells
                    .Where(c => GetNumberOfAliveNeighboursOf(c) == 2
                                || GetNumberOfAliveNeighboursOf(c) == 3);
            }
        }

        private IEnumerable<Cell> Revives {
            get {
                return _aliveCells
                    .SelectMany(GetDeadNeighboursOf)
                    .Where(c => GetNumberOfAliveNeighboursOf(c) == 3);
            }
        }

        public Generation Tick() {
            return new Generation(KeepAlives.Union(Revives).ToArray());
        }

        private IEnumerable<Cell> GetDeadNeighboursOf(Cell cell) {
            return GetNeighboursOf(cell).Where(c => !Contains(c));
        }

        private static IEnumerable<Cell> GetNeighboursOf(Cell cell) {
            return Enumerable.Range(-1, 3)
                .SelectMany(x => Enumerable.Range(-1, 3)
                                     .Select(y => new Cell(cell.X + x, cell.Y + y)))
                .Except(cell);
        }

        private int GetNumberOfAliveNeighboursOf(Cell cell) {
            return GetNeighboursOf(cell).Count(Contains);
        }

        public bool Contains(Cell cell) {
            return _aliveCells.Contains(cell);
        }
    }

    public struct Cell : IEquatable<Cell> {
        private readonly int _x;
        private readonly int _y;

        public Cell(int x, int y) {
            _x = x;
            _y = y;
        }

        public int Y {
            get { return _y; }
        }

        public int X {
            get { return _x; }
        }

        public bool Equals(Cell other) {
            return other._x == _x && other._y == _y;
        }

        public override bool Equals(object obj) {
            if (ReferenceEquals(null, obj)) return false;
            if (obj.GetType() != typeof (Cell)) return false;
            return Equals((Cell) obj);
        }

        public override int GetHashCode() {
            unchecked {
                return (_x*397) ^ _y;
            }
        }
    }

    public static class Extensions {
        public static IEnumerable<T> Except<T>(this IEnumerable<T> @this, T element) {
            return @this.Except(new[] {element});
        }
    }
}

2009-09-24

Trying out Sharp Tests Ex with NUnit 2.5

/*before*/ Assert.That(logHandlersCount, Is.EqualTo(1));



/*after*/ logHandlersCount.Should().Be.EqualTo(1);




Even better readability :-)

More on Sharp Tests Ex here: http://sharptestex.codeplex.com/Wiki/View.aspx?title=SyntaxMainPage

2009-06-30

Alt.Net Oresund Meeting at ITU 25th of June

We weren't that many people, but in return Martin N Jensen held a great presentation showing the new features of NUnit and how they compare to MbUnit and xUnit.Net.

I definitely learned a few new tricks that I'm eager to put to practice.

These include
  • BDD style constraints (improved readability)
  • Theories (specifications that run several combinations of input)
  • Generic test fixtures (run the same test for chosen implementations of an interface)
I've worked with MbUnit for about a year now, and before that MSTest for several years.

From 2001 to sometime 2005, I however used NUnit, and with the new additions and a new employer, maybe we'll see each other again soon.

I haven't fully grasped the theory concept, but will look into it. This seems like a good place to start: Theories in Practice: Easy-to-Write Specifications that Catch Bugs

A new employer? After having three really good offers to consider, I finally made up my mind this weekend. I will start working with the very same Martin N Jensen, and the other guys at BankInvest this autumn. I'm very excited, and eager to produce great financial software with great people.