diff --git a/eltoby/StringCalculator/StringCalculator.Logic/Calculator.cs b/eltoby/StringCalculator/StringCalculator.Logic/Calculator.cs new file mode 100644 index 0000000..396b1e3 --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Logic/Calculator.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StringCalculator.Logic +{ + public class Calculator + { + public int Sum(int[] numbers) + { + List negatives = new List(); + + int sum = 0; + foreach (int number in numbers) + if (number < 0) + negatives.Add(number); + else + if (number <= 1000) + sum += number; + + if (negatives.Count >0) + throw new NegativesNotAllowedException(negatives.ToArray(),"numbers"); + else + return sum; + } + + public int Sum(string input) + { + InputParser ip = new InputParser(); + return Sum(ip.Parse(input)); + } + + } +} diff --git a/eltoby/StringCalculator/StringCalculator.Logic/InputParser.cs b/eltoby/StringCalculator/StringCalculator.Logic/InputParser.cs new file mode 100644 index 0000000..2734cad --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Logic/InputParser.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StringCalculator.Logic +{ + internal class InputParser + { + public int[] Parse(string input) + { + List delimiters = new List(); + delimiters.AddRange(new string[] {",","\n"}); + if (hasSpecialDelimiter(input)) + { + delimiters.AddRange(getSpecialDelimiters(input)); + input = removeSpecialDelimiterLine(input); + } + + List numbers = new List(); + if (!String.IsNullOrEmpty(input.Trim())) + foreach (string part in input.Split(delimiters.ToArray(), StringSplitOptions.RemoveEmptyEntries)) + numbers.Add(int.Parse(part)); + + return numbers.ToArray(); + } + + bool hasSpecialDelimiter(string input) + { + return (input.StartsWith("//")); + } + + string[] getSpecialDelimiters(string input) + { + List delimiters = new List(); + string delimiterLine = input.Substring(2, input.IndexOf('\n') -2); + StringBuilder stbDelimiter = new StringBuilder(); + bool inDelimiter = false; + foreach (char c in delimiterLine) + { + switch (c) + { + case '[': + inDelimiter = true; + stbDelimiter = new StringBuilder(); + break; + case ']': + inDelimiter = false; + delimiters.Add(stbDelimiter.ToString()); + break; + default: + if (inDelimiter) + stbDelimiter.Append(c); + else + delimiters.Add(c.ToString()); + break; + } + } + return delimiters.ToArray(); + } + + string removeSpecialDelimiterLine(string input) + { + int startIndex = input.IndexOf('\n') + 1; + return input.Substring(startIndex); + } + } + +} diff --git a/eltoby/StringCalculator/StringCalculator.Logic/NegativesNotAllowedException.cs b/eltoby/StringCalculator/StringCalculator.Logic/NegativesNotAllowedException.cs new file mode 100644 index 0000000..3e8ec6a --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Logic/NegativesNotAllowedException.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StringCalculator.Logic +{ + public class NegativesNotAllowedException :ArgumentOutOfRangeException + { + int[] negatives; + public NegativesNotAllowedException(int[] negatives, string paramName) :base(paramName,negatives,"Negatives not allowed") + { + this.negatives = negatives; + } + + public string Negatives + { + get + { + return getString(negatives); + } + } + + string getString(int[] numbers) + { + StringBuilder stb = new StringBuilder(); + foreach (int number in numbers) + { + if (stb.Length > 0) + stb.Append(","); + stb.Append(number); + } + return stb.ToString(); + } + + } +} diff --git a/eltoby/StringCalculator/StringCalculator.Logic/Properties/AssemblyInfo.cs b/eltoby/StringCalculator/StringCalculator.Logic/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b984279 --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Logic/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("StringCalculator.Logic")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("StringCalculator.Logic")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8738bc32-b798-4010-9990-4a2eb8eeceac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/eltoby/StringCalculator/StringCalculator.Logic/StringCalculator.Logic.csproj b/eltoby/StringCalculator/StringCalculator.Logic/StringCalculator.Logic.csproj new file mode 100644 index 0000000..38f87b4 --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Logic/StringCalculator.Logic.csproj @@ -0,0 +1,49 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {626EF91B-F885-4FC3-8D57-F323B2F1FA22} + Library + Properties + StringCalculator.Logic + StringCalculator.Logic + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eltoby/StringCalculator/StringCalculator.Test/Program.cs b/eltoby/StringCalculator/StringCalculator.Test/Program.cs new file mode 100644 index 0000000..3d23761 --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Test/Program.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; +using StringCalculator.Logic; + +namespace StringCalculator.Test +{ + class Program + { + static void Main(string[] args) + { + string[] tests = {"","1","1,2","1,2,3","1,2,3,4","1\n2,3","//;\n1;2","-1,2,-5", "1001,2","//[***]\n1***2***3","//[*][%]\n1*2%3", "//[^^][*]\n1^^2*3"}; + + foreach (string test in tests) + { + Console.WriteLine(String.Format("Test: {0}", test)); + try + { + Console.WriteLine(string.Format("Result: {0}", new Calculator().Sum(test))); + } + catch (NegativesNotAllowedException ex) + { + Console.WriteLine("Controlled Exception:"); + Console.WriteLine(ex.Message); + Console.WriteLine(ex.Negatives); + } + Console.WriteLine("-------------"); + } + Console.WriteLine("Test Ended. Press Enter to continue."); + Console.Read(); + } + } +} diff --git a/eltoby/StringCalculator/StringCalculator.Test/Properties/AssemblyInfo.cs b/eltoby/StringCalculator/StringCalculator.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8febf5d --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("StringCalculator.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("StringCalculator.Test")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6de8f9c2-3a96-41c9-804b-dd62108f3007")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/eltoby/StringCalculator/StringCalculator.Test/StringCalculator.Test.csproj b/eltoby/StringCalculator/StringCalculator.Test/StringCalculator.Test.csproj new file mode 100644 index 0000000..984c715 --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.Test/StringCalculator.Test.csproj @@ -0,0 +1,53 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {40780F28-448C-4A2C-B0E5-85EF653FE5D4} + Exe + Properties + StringCalculator.Test + StringCalculator.Test + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + {626EF91B-F885-4FC3-8D57-F323B2F1FA22} + StringCalculator.Logic + + + + + \ No newline at end of file diff --git a/eltoby/StringCalculator/StringCalculator.sln b/eltoby/StringCalculator/StringCalculator.sln new file mode 100644 index 0000000..9404faa --- /dev/null +++ b/eltoby/StringCalculator/StringCalculator.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringCalculator.Logic", "StringCalculator.Logic\StringCalculator.Logic.csproj", "{626EF91B-F885-4FC3-8D57-F323B2F1FA22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StringCalculator.Test", "StringCalculator.Test\StringCalculator.Test.csproj", "{40780F28-448C-4A2C-B0E5-85EF653FE5D4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {626EF91B-F885-4FC3-8D57-F323B2F1FA22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {626EF91B-F885-4FC3-8D57-F323B2F1FA22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {626EF91B-F885-4FC3-8D57-F323B2F1FA22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {626EF91B-F885-4FC3-8D57-F323B2F1FA22}.Release|Any CPU.Build.0 = Release|Any CPU + {40780F28-448C-4A2C-B0E5-85EF653FE5D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40780F28-448C-4A2C-B0E5-85EF653FE5D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40780F28-448C-4A2C-B0E5-85EF653FE5D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40780F28-448C-4A2C-B0E5-85EF653FE5D4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal