Advertisement
zinch

String Calculator Kata

Mar 13th, 2017
328
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.89 KB | None | 0 0
  1. package com.company;
  2.  
  3. import org.junit.Before;
  4. import org.junit.Rule;
  5. import org.junit.Test;
  6. import org.junit.rules.ExpectedException;
  7.  
  8. import static org.hamcrest.MatcherAssert.assertThat;
  9. import static org.hamcrest.core.IsEqual.equalTo;
  10.  
  11. /**
  12.  */
  13. public class StringCalculatorTest {
  14.  
  15.     @Rule
  16.     public ExpectedException exceptionCatcher = ExpectedException.none();
  17.  
  18.     private StringCalculator stringCalculator;
  19.  
  20.     @Before
  21.     public void setUp() throws Exception {
  22.         stringCalculator = new StringCalculator();
  23.     }
  24.  
  25.     @Test
  26.     public void whenEmptyString_thenZero() {
  27.         assertThat(stringCalculator.add(""), equalTo(0));
  28.     }
  29.  
  30.     @Test
  31.     public void whenOneNumber_thenReturnThatNumber() {
  32.         assertThat(stringCalculator.add(" 1 "), equalTo(1));
  33.     }
  34.  
  35.     @Test
  36.     public void whenTwoNumbers_thenReturnSum() {
  37.         assertThat(stringCalculator.add("1,\t2"), equalTo(3));
  38.     }
  39.  
  40.     @Test
  41.     public void whenInvalidDelimiter_thenException() {
  42.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  43.         stringCalculator.add("1 1");
  44.     }
  45.  
  46.     @Test
  47.     public void whenNoNumbers_thenException() {
  48.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  49.         stringCalculator.add("foo bar");
  50.     }
  51.  
  52.     @Test
  53.     public void whenThreeNumber_thenSum() {
  54.         assertThat(stringCalculator.add("1,2,3"), equalTo(6));
  55.     }
  56.  
  57.     @Test
  58.     public void whenNewLine_thenParsedCorrectly() {
  59.         assertThat(stringCalculator.add("1\n1,2"), equalTo(4));
  60.     }
  61.  
  62.     @Test
  63.     public void whenNewLineWithComma_thenException() {
  64.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  65.         stringCalculator.add("1,\n");
  66.     }
  67.  
  68.     @Test
  69.     public void whenTwoNumbersWithNewLineWithComma_thenException() {
  70.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  71.         stringCalculator.add("1,\n2");
  72.     }
  73.  
  74.     @Test
  75.     public void whenOtherDelimiter_thenSuportIt() {
  76.         assertThat(stringCalculator.add("//[;]\n2;3"), equalTo(5));
  77.     }
  78.  
  79.     @Test
  80.     public void whenDelimitersDontMatch_thenException() {
  81.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  82.         stringCalculator.add("//[!]\n1,2");
  83.     }
  84.  
  85.     @Test
  86.     public void whenOtherDelimitedWithNewLine_thenSum() {
  87.         assertThat(stringCalculator.add("//[!]\n100!500"), equalTo(600));
  88.     }
  89.  
  90.     @Test
  91.     public void whenNegativeNumbers_thenShowThemInException() {
  92.         exceptionCatcher.expect(StringCalculator.InvalidInput.class);
  93.         exceptionCatcher.expectMessage("-1,-5");
  94.         stringCalculator.add("//[qw]\n1qw2qw-1qw100qw-5");
  95.     }
  96.  
  97.     @Test
  98.     public void whenTwoNumbersGreaterThan1000_thenZero() {
  99.         assertThat(stringCalculator.add("//[-]\n1001-1002"), equalTo(0));
  100.     }
  101.  
  102.     @Test
  103.     public void whenTenAndThousandOne_thenTen() {
  104.         assertThat(stringCalculator.add("10,1001"), equalTo(10));
  105.     }
  106.  
  107.     @Test
  108.     public void whenThousandAndThousand_thenTwoThousand() {
  109.         assertThat(stringCalculator.add("1000\n1000"), equalTo(2000));
  110.     }
  111.  
  112.     @Test
  113.     public void whenTwoDelimiters_thenCorrectSum() {
  114.         assertThat(stringCalculator.add("//[*][%]\n1*2%3"), equalTo(6));
  115.     }
  116.  
  117.     @Test
  118.     public void whenTwoLongDelimiters_thenCorrectSum() {
  119.         assertThat(stringCalculator.add("//[*~][%-]\n1*~2%-3"), equalTo(6));
  120.     }
  121. }
  122.  
  123.  
  124. package com.company;
  125.  
  126. import java.util.ArrayList;
  127. import java.util.Collections;
  128. import java.util.List;
  129. import java.util.regex.Pattern;
  130.  
  131. import static java.lang.Integer.parseInt;
  132.  
  133. /**
  134.  */
  135. public class StringCalculator {
  136.  
  137.     private List<String> delimiters;
  138.     private String strNumbers;
  139.     private Pattern delimitersPattern;
  140.     private List<Integer> numbers;
  141.  
  142.     public StringCalculator() {
  143.         delimiters = Collections.singletonList(",");
  144.         delimitersPattern = Pattern.compile("//(\\[\\S+\\])+\\n.*");
  145.     }
  146.  
  147.     public int add(String numbers) {
  148.         this.strNumbers = numbers;
  149.         if (numbers.isEmpty())
  150.             return 0;
  151.  
  152.         checkPreconditions();
  153.  
  154.         if (hasDelimiter())
  155.             extractDelimiter();
  156.  
  157.         parse();
  158.         return sum();
  159.     }
  160.  
  161.     private void checkPreconditions() {
  162.         String[] invalidDelimiters = new String[]{"\n,", ",\n"};
  163.         for (String d : invalidDelimiters)
  164.             if (strNumbers.contains(d))
  165.                 throw new InvalidInput();
  166.     }
  167.  
  168.     private boolean hasDelimiter() {
  169.         return delimitersPattern.matcher(strNumbers).matches();
  170.     }
  171.  
  172.     private void extractDelimiter() {
  173.         int endIndex = strNumbers.indexOf("\n");
  174.  
  175.         delimiters = new ArrayList<>();
  176.         int openBraceIdx = 2;
  177.         while (openBraceIdx < endIndex - 1) {
  178.             int closeBraceIdx = strNumbers.indexOf(']', openBraceIdx);
  179.             delimiters.add(strNumbers.substring(openBraceIdx + 1, closeBraceIdx));
  180.             openBraceIdx = closeBraceIdx + 1;
  181.         }
  182.  
  183.         strNumbers = strNumbers.substring(endIndex + 1);
  184.     }
  185.  
  186.     private void parse() {
  187.         List<String> splittedNums = new ArrayList<>();
  188.  
  189.         for (String num : strNumbers.split(makeSplitString()))
  190.             splittedNums.add(num);
  191.  
  192.         tryParseIntoNumbers(splittedNums);
  193.     }
  194.  
  195.     private String makeSplitString() {
  196.         String splitString = "(";
  197.         for (String d : delimiters)
  198.             splitString += Pattern.quote(d) + "|";
  199.         splitString += "\\n)";
  200.         return splitString;
  201.     }
  202.  
  203.     private void tryParseIntoNumbers(List<String> splittedNums) {
  204.         numbers = new ArrayList<>();
  205.         List<Integer> negativeNumbers = new ArrayList<>();
  206.         for (String n : splittedNums) {
  207.             int i = tryParse(n);
  208.             numbers.add(i);
  209.             if (i < 0)
  210.                 negativeNumbers.add(i);
  211.         }
  212.  
  213.         if (!negativeNumbers.isEmpty())
  214.             throwExceptionForNegativeNumbers(negativeNumbers);
  215.     }
  216.  
  217.     private void throwExceptionForNegativeNumbers(List<Integer> negativeNumbers) {
  218.         String message = "";
  219.         for (Integer n : negativeNumbers)
  220.             message += message.isEmpty() ? n : "," + n;
  221.         throw new InvalidInput(message);
  222.     }
  223.  
  224.     private Integer tryParse(String number) {
  225.         try {
  226.             return parseInt(number.trim());
  227.         } catch (NumberFormatException e) {
  228.             throw new InvalidInput(e);
  229.         }
  230.     }
  231.  
  232.     private int sum() {
  233.         int result = 0;
  234.         for (Integer n : numbers) {
  235.             if (n <= 1000)
  236.                 result += n;
  237.         }
  238.         return result;
  239.     }
  240.  
  241.     public static class InvalidInput extends RuntimeException {
  242.         public InvalidInput() {
  243.         }
  244.  
  245.         public InvalidInput(String message) {
  246.             super(message);
  247.         }
  248.  
  249.         public InvalidInput(Throwable cause) {
  250.             super(cause);
  251.         }
  252.     }
  253.  
  254. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement