Created
January 28, 2013 06:19
-
-
Save sviataslau/4653422 to your computer and use it in GitHub Desktop.
Sample String Calculator TDD Kata implementation.
http://osherove.com/tdd-kata-1/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
namespace StringCalculator | |
{ | |
public class Calculator | |
{ | |
private static readonly Regex _inputParsingRegex = new Regex(@"(?<definition>//(?<delimiter>.+)\n).*"); | |
private string _input; | |
public int Add(string input) | |
{ | |
if (input == null) | |
throw new ArgumentNullException("input"); | |
if (input == string.Empty) | |
return 0; | |
_input = input; | |
var numbers = Parse(); | |
EnsureNonNegatives(numbers); | |
return numbers.Sum(); | |
} | |
private int[] Parse() | |
{ | |
var delimiters = GetAllAllowedDelimiters(); | |
var numbersInput = GetNumberInput().Split(delimiters).Where(n => !string.IsNullOrEmpty(n)); | |
int[] numbers = Filter(numbersInput.Select(int.Parse).ToArray()); | |
return numbers; | |
} | |
private static int[] Filter(IEnumerable<int> numbers) | |
{ | |
return numbers.Where(n => n <= 1000).ToArray(); | |
} | |
private static void EnsureNonNegatives(IEnumerable<int> numbers) | |
{ | |
int[] negatives = numbers.Where(n => n < 0).ToArray(); | |
if (negatives.Any()) | |
{ | |
string exceptionMessage = string.Format("negative not allowed:{0}", string.Join(",", negatives)); | |
throw new ArgumentException(exceptionMessage); | |
} | |
} | |
private IEnumerable<string> GetUserDefinedDelimiters() | |
{ | |
var match = _inputParsingRegex.Match(_input); | |
string delimiter = match.Groups["delimiter"].Value; | |
if (string.IsNullOrEmpty(delimiter)) | |
return new string[0]; | |
return delimiter.Split(new[] {'[', ']'}); | |
} | |
private char[] GetAllAllowedDelimiters() | |
{ | |
var delimiter = GetUserDefinedDelimiters(); | |
return new[] { ',', '\n' }.Concat(delimiter.SelectMany(d => d.ToCharArray())).ToArray(); | |
} | |
private string GetDelimiterDefinitionPart() | |
{ | |
var match = _inputParsingRegex.Match(_input); | |
return match.Groups["definition"].Value; | |
} | |
private string GetNumberInput() | |
{ | |
string delimiterDefinitionPart = GetDelimiterDefinitionPart(); | |
return !string.IsNullOrEmpty(delimiterDefinitionPart) ? _input.Replace(delimiterDefinitionPart, string.Empty) : _input; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using FluentAssertions; | |
using NUnit.Framework; | |
namespace StringCalculator.Tests | |
{ | |
public class Tests | |
{ | |
[Test] | |
public void should_return_sum_for_empty() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add(""); | |
result.Should().Be(0); | |
} | |
[Test] | |
public void should_return_sum_for_one_number() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("10"); | |
result.Should().Be(10); | |
} | |
[Test] | |
public void should_return_sum_for_two_numbers() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("10,11"); | |
result.Should().Be(21); | |
} | |
[Test] | |
public void should_return_sum_for_three_numbers() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("10,11,12"); | |
result.Should().Be(33); | |
} | |
[Test] | |
public void should_return_sum_for_unknown_amount_of_numbers() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("1,2,3,4,5"); | |
result.Should().Be(15); | |
} | |
[Test] | |
public void should_return_sum_both_with_command_and_newline_separators() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("1\n2,3"); | |
result.Should().Be(6); | |
} | |
[Test] | |
public void should_return_sum_with_custom_delimiter() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("//;\n1;2"); | |
result.Should().Be(3); | |
} | |
[Test] | |
public void should_throw_exception_if_negative_numbers_are_passed() | |
{ | |
var calculator = new Calculator(); | |
Action call = () => calculator.Add("-1,10,-2"); | |
call.ShouldThrow<ArgumentException>("negative not allowed:-1,-2"); | |
} | |
[Test] | |
public void should_ignore_numbers_greater_than_1000() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("10,2,1001"); | |
result.Should().Be(12); | |
} | |
[Test] | |
public void should_return_sum_with_custom_delimiter_with_any_length() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("//***\n1***2***3"); | |
result.Should().Be(6); | |
} | |
[Test] | |
public void should_return_sum_with_more_than_one_custom_delimiter() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("//[*][%]\n1*2%3"); | |
result.Should().Be(6); | |
} | |
[Test] | |
public void should_return_sum_with_more_than_one_custom_delimiter_with_any_length() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("//[***][%]\n1***2%3"); | |
result.Should().Be(6); | |
} | |
[Test] | |
public void should_return_sum_wht_both_custom_and_standard_delimiters() | |
{ | |
var calculator = new Calculator(); | |
int result = calculator.Add("//[***][%]\n1***2,3%4\n5"); | |
result.Should().Be(15); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment