Skip to content

Instantly share code, notes, and snippets.

@iamkevinlowe
Created July 5, 2016 01:07
Show Gist options
  • Save iamkevinlowe/72b2f39e53915003ba94e275afac7551 to your computer and use it in GitHub Desktop.
Save iamkevinlowe/72b2f39e53915003ba94e275afac7551 to your computer and use it in GitHub Desktop.
# http://osherove.com/tdd-kata-1/
class StringCalculator
def add(string)
# Default delimiters to split string
delims = %w(, \n)
# If string begins with "//[delimiter]\n" include delimiter to array of delimiters
if string.match(/^\/\/.+/)
match, string = string.split('\n', 2)
delims.concat(match.to_s[3..-2].split(']['))
end
# Gets accepted numbers from string
numbers = string.split(Regexp.union(delims)).map(&:to_i).reject { |n| n > 1000 }
# Gets any negative numbers
negatives = numbers.select { |n| n < 0 }
# Raises an ArgumentError if negative numbers are found
raise ArgumentError.new "negatives not allowed: #{negatives.join(', ')}" unless negatives.none?
# Returns sum of numbers
numbers.inject(0) { |sum, num| sum += num }
end
end
# class Test
# attr_reader :pass_count, :fail_count
# def initialize(calc)
# @pass_count = @fail_count = 0
# @calc = calc
# end
# def this(desc, method, string, expected)
# puts "Test: #{desc}"
# begin
# actual = @calc.send(method, string)
# rescue ArgumentError => e
# actual = e.message
# end
# if actual == expected
# puts "\tPassed!\n\n"
# @pass_count += 1
# else
# puts "\tFailed! Expected #{actual} to equal #{expected}\n\n"
# @fail_count += 1
# end
# end
# end
# test = Test.new(StringCalculator.new)
# test.this("expect empty string to equal 0", 'add', '', 0)
# test.this("expect '1' to equal 1", 'add', '1', 1)
# test.this("expect '1,2' to equal 3", 'add', '1,2', 3)
# test.this("expect '1,2,3' to equal 6", 'add', '1,2,3', 6)
# rand_array = (1..rand(10) + 1).map { |n| n * rand(10) }
# test.this("expect an unknown amount of numbers to pass", 'add', rand_array.join(','), rand_array.inject(&:+))
# test.this("expect '1\\n2,3' to equal 6", 'add', '1\n2,3', 6)
# test.this("expect '//[;]\\n1;2' to equal 3", 'add', '//[;]\n1;2', 3)
# test.this("expect negative numbers to throw an exception", 'add', '-1', 'negatives not allowed: -1')
# test.this("expect numbers bigger than 1000 to be ignored", 'add', '2,1001', 2)
# test.this("expect '//[***]\\n1***2***3' to equal 6", 'add', '//[***]\n1***2***3', 6)
# test.this("expect '//[*][%]\\n1*2%3' to equal 6", 'add', '//[*][%]\n1*2%3', 6)
# test.this("expect multiple delimiters with lengths longer than one character to pass", 'add', '//[@@@][*][^^]\n1@@@2*3^^4', 10)
# puts "#{test.pass_count} tests passed. #{test.fail_count} tests failed."
require 'minitest/autorun'
describe StringCalculator do
let(:calc) { StringCalculator.new }
describe "when given an empty string" do
it "returns zero" do
calc.add('').must_equal 0
calc.add(' ').must_equal 0
calc.add(' ').must_equal 0
end
end
describe "when given a single number string" do
it "returns the number" do
calc.add('1').must_equal 1
calc.add('2').must_equal 2
calc.add('345').must_equal 345
end
end
describe "when given a two number string" do
it "returns the sum of the two numbers" do
calc.add('1,2').must_equal 3
calc.add('2,3').must_equal 5
calc.add('45,67').must_equal 112
end
end
describe "when given a three number string" do
it "returns the sum of the three numbers" do
calc.add('1,2,3').must_equal 6
calc.add('4,5,6').must_equal 15
calc.add('78,90,12').must_equal 180
end
end
describe "when given an unknown amount of numbers string" do
it "returns the sum of the numbers" do
3.times do
rand_array = 1.upto(rand(10) + 1).map { |n| n * rand(10) }
calc.add(rand_array.join(',')).must_equal rand_array.inject(&:+)
end
end
end
describe "when given a string of with '\\n'" do
it "returns the sum of the numbers delimited by '\\n' and ','" do
calc.add('1\n2,3').must_equal 6
calc.add('4\n5\n6').must_equal 15
calc.add('7,8\n9').must_equal 24
end
end
describe "when given a string that starts with '//[;]\\n'" do
it "returns the sum of the numbers delimited by ';', '\\n' and ','" do
calc.add('//[;]\n1;2').must_equal 3
calc.add('//[;]\n3,4;5\n6').must_equal 18
calc.add('//[;]\n7;8;9;0').must_equal 24
end
end
describe "when given a string with negative numbers" do
it "raises an ArgumentError error" do
3.times do
negatives = 1.upto(rand(10) + 1).map { |n| -(n * rand(10) + 1) }
err = assert_raises(ArgumentError) { calc.add(negatives.join(',')) }
err.message.must_equal "negatives not allowed: #{negatives.join(', ')}"
end
end
end
describe "when given a string with a number greater than 1000" do
it "ignores numbers greater than 1000 and returns the sum" do
calc.add('1,1001').must_equal 1
calc.add('2,1000').must_equal 1002
calc.add('1001,2002,3003').must_equal 0
end
end
describe "when given a string with a multi character custom delimiter" do
it "delimits the string with the multi character delimiter and returns the sum" do
calc.add('//[***]\n1***2').must_equal 3
calc.add('//[***]\n3,4***5').must_equal 12
calc.add('//[abc]\n6abc7\n8abc9').must_equal 30
end
end
describe "when given a string with multiple custom delimiters" do
it "delimits the string with custom delimiters and returns the sum" do
calc.add('//[*][%]\n1*2%3').must_equal 6
calc.add('//[*][%]\n4*5*6%7%8').must_equal 30
calc.add('//[!][@][#][$][%][^][&][*]\n1!2@3#4$5%6^7&8*9').must_equal 45
end
end
describe "when given a string with multiple custom delimiters of multiple characters each" do
it "delimits the string with custom delimiters and returns the sum" do
calc.add('//[@@@][*][^^]\n1@@@2*3^^4').must_equal 10
calc.add('//[!!!][;;][!@#]\n5!!!6;;7!@#8').must_equal 26
calc.add('//[***][**][*]\n1***2**3*4').must_equal 10
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment