String Calculator Kata

Here's a sample solution for the String Calculator Kata that I'm using with cyber-dojo, in C# using NUnit as the test framework.

Code


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class NegativesNotAllowedException : Exception
{
}

/// <summary>
/// Calculators the sum of up to two numbers in a formatted string
/// </summary>
public class StringCalculator
{
	/// <summary>
	/// Examples: 
	///		Empty string returns 0.
	///		"1" returns 1
	///		"1,2" returns 3
	///		"1\n2,3" returns 6
	///		Negative numbers throw a NegativesNotAllowed exception
	/// </summary>
	/// <param name="numbers"></param>
	/// <returns></returns>
	public int Add(string numbers)
	{
		int sum = 0;

		if (!string.IsNullOrWhiteSpace(numbers))
		{
			var splits = numbers.Split(new char[] { ',', '\n' });

			foreach (string number in splits)
			{
				int newNumber = 0;

				try
				{
					newNumber = Convert.ToInt32(number);
				}
				catch (FormatException)
				{
					newNumber = 0;
				}

				if (newNumber < 0)
				{
					throw new NegativesNotAllowedException();
				}

				sum += newNumber;
			}
		}

		return sum;
	}
}

Tests

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

[TestFixture]
public class StringCalculatorSpecimenTests
{
	[Test]
	public void StringCalculator_Add_Empty_String_Returns_Zero()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(0, sc.Add(string.Empty));
	}

	[Test]
	public void StringCalculator_Add_Non_Numeric_Returns_Zero()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(0, sc.Add("a,b,c"));
	}

	[Test]
	public void StringCalculator_Add_OneNumber_One_ReturnsOne()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(1, sc.Add("1"));
	}

	[Test]
	public void StringCalculator_Add_OneNumber_Five_ReturnsFive()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(5, sc.Add("5"));
	}

	[Test]
	public void StringCalculator_Add_TwoNumbers_OneTwo_ReturnsThree()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(3, sc.Add("1,2"));
	}

	[Test]
	public void StringCalculator_Add_ThreeNumbers_OneTwoThree_ReturnsSix()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(6, sc.Add("1,2,3"));
	}

	[Test]
	public void StringCalculator_Add_Three_Numbers_NewLine_OneTwoThree_Returns_Six()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(6, sc.Add("1\n2,3"));
	}

	[Test]
	public void StringCalculator_Add_Three_Numbers_Whitespace_OneTwoThree_Returns_Six()
	{
		var sc = new StringCalculator();

		Assert.AreEqual(6, sc.Add("   1,		2,3  "));
	}

	[Test]
	[ExpectedException(typeof(NegativesNotAllowedException))]
	public void StringCalculator_Add_One_Negative_Number_Throws_Exception()
	{
		var sc = new StringCalculator();

		sc.Add("-1");

		Assert.Fail("Expecting Exception");
	}

	[Test]
	[ExpectedException(typeof(NegativesNotAllowedException))]
	public void StringCalculator_Add_Two_Numbers_Negative_First_Throws_Exception()
	{
		var sc = new StringCalculator();

		sc.Add("-1, 9");

		Assert.Fail("Expecting Exception");
	}

	[Test]
	[ExpectedException(typeof(NegativesNotAllowedException))]
	public void StringCalculator_Add_Two_Numbers_Negative_Second_Throws_Exception()
	{
		var sc = new StringCalculator();

		sc.Add("2,-7");

		Assert.Fail("Expecting Exception");
	}
}