Skip to content

Instantly share code, notes, and snippets.

@michaelbannister
Created January 28, 2016 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelbannister/2f752cbd28c3124ff18e to your computer and use it in GitHub Desktop.
Save michaelbannister/2f752cbd28c3124ff18e to your computer and use it in GitHub Desktop.
String calculator TDD kata first attempt
import java.util.regex.Pattern
class StringCalculator {
def add(String expression) {
if (expression.isEmpty()) {
return 0
}
def delimiter = findCustomDelimiterPattern(expression)
expression = stripDelimiterSpecification(expression)
rejectNegatives(expression)
def sum = 0
for (String string : expression.split(delimiter)) {
int number = Integer.parseInt(string)
if (number <= 1000) {
sum += number
}
}
sum
}
private void rejectNegatives(String expression) {
if (expression.contains('-')) {
def negatives = expression.findAll(/-\d+/)
throw new NegativesNotAllowedException(negatives.join(','))
}
}
private String stripDelimiterSpecification(String expression) {
if (hasCustomDelimiter(expression)) {
expression.split('\n', 2).last()
} else {
expression
}
}
private String findCustomDelimiterPattern(String expression) {
if (!expression.startsWith('//')) {
return '[,\n]'
}
def firstLine = expression.split('\n')[0]
def delimiterSpec = firstLine.substring(2)
if (delimiterSpec.length() == 1) {
return delimiterSpec
}
def delimiterPatterns = delimiterSpec.findAll(/\[(.+?)\]/) { match, textInsideSquareBrackets ->
Pattern.quote(textInsideSquareBrackets)
}
delimiterPatterns.join('|')
}
private boolean hasCustomDelimiter(String expression) {
expression.startsWith('//')
}
}
import spock.lang.Specification
class StringCalculatorSpec extends Specification {
def "add of empty string is 0"() {
expect:
add('') == 0
}
def "add of number is itself"() {
expect:
add('2') == 2
}
def "add of two numbers is their sum"() {
expect:
add('1,2') == 3
}
def "add can sum several numbers"() {
expect:
add('3,5,7,9') == 24
}
def "add numbers separated by newlines"() {
expect:
add('1\n2') == 3
}
def "can specify a custom delimiter"() {
expect:
add('//;\n1;2') == 3
}
def "negative number throws exception"() {
when:
add('-3')
then:
thrown(NegativesNotAllowedException)
}
def "negative number anywhere in the input throws exception"() {
when:
add('1,-3')
then:
thrown(NegativesNotAllowedException)
}
def "first negative number is included in the exception message"() {
when:
add('-3')
then:
def e = thrown(NegativesNotAllowedException)
e.message == '-3'
}
def "all negative numbers are included in the exception message"() {
when:
add('1,-2,3,-4')
then:
def e = thrown(NegativesNotAllowedException)
e.message == '-2,-4'
}
def "numbers larger than 1000 should be ignored"() {
expect:
add('2,1001,1004,2') == 4
}
def "delimiter can be longer than one character"() {
expect:
add('//[***]\n1***2***3') == 6
}
def "custom delimiter may be multiple characters"() {
expect:
add('//[*][%]\n1*2%3') == 6
}
def add(expression) {
new StringCalculator().add(expression)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment