Skip to content

Instantly share code, notes, and snippets.

@druttka
Forked from anonymous/StringCalculatorTests.cs
Last active December 14, 2015 15:58
Show Gist options
  • Save druttka/5111493 to your computer and use it in GitHub Desktop.
Save druttka/5111493 to your computer and use it in GitHub Desktop.
// I described the thought processes (SOLID violations, which to fix, how and why)
// in my post at http://thedevstop.wordpress.com/2013/03/07/roy-osheroves-solid-katastring-calculator-redux/
// Note that I did this in LINQPad and so instead of NUnit tests, I dumped failures
// If I was to do this again, I'd either do it in VS with a test runner.
void Main()
{
var parser = new IntsFromCommaSeparatedString();
var none = parser.Parse("").ToArray();
AssertEqual(0, none.Length);
var one = parser.Parse("1").ToArray();
AssertEqual(1, one.Length);
AssertEqual(1, one[0]);
var two = parser.Parse("1,2").ToArray();
AssertEqual(2, two.Length);
AssertEqual(1, two[0]);
AssertEqual(2, two[1]);
var calc = new StringCalculator(parser, new SimpleDefault<int>());
AssertEqual(0, calc.Add(""));
AssertEqual(1, calc.Add("1"));
AssertEqual(3, calc.Add("1,2"));
}
public interface IParseInts
{
IEnumerable<int> Parse(string input);
}
public interface IDefault<T>
{
T GetDefault(string input);
}
public class SimpleDefault<T> : IDefault<T>
{
public T GetDefault(string input)
{
return default(T);
}
}
public class ExceptionDefault<TValue, TException> : IDefault<TValue>
where TException : Exception,new()
{
public TValue GetDefault(string input)
{
throw new TException();
}
}
public class IntsFromCommaSeparatedString : IParseInts
{
public IEnumerable<int> Parse(string input)
{
int x;
foreach(var part in input.Split(','))
{
if (int.TryParse(part, out x))
yield return x;
}
}
}
public class StringCalculator
{
private readonly IDefault<int> defaulter;
private readonly IParseInts parser;
public StringCalculator(IParseInts parser, IDefault<int> defaulter)
{
// you could guard against null if you want. Omitted for brevity
this.parser = parser;
this.defaulter = defaulter;
}
public int Add(string input)
{
var ints = this.parser.Parse(input);
if (!ints.Any())
return this.defaulter.GetDefault(input);
// Uh-oh. The way I’ve implemented this, I still pass the tests
// but I have eliminated the explicit check for empty=>0.
// It is only 0 by an implementation coincidence. This is however
// irrelevant to the SOLID part of this exercise, so I'll leave it
return ints.Sum();
}
}
// Only for use in the LINQPad query to simulate tests
private void AssertEqual(object expected, object actual)
{
if (!expected.Equals(actual))
throw new Exception(string.Format("Expected {0} to equal {1}", actual, expected));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment