Ratio { static Ratio valueOf(final String value) { final Matcher matcher = PATTERN.matcher(value); if (!matcher.matches()) { throw new IllegalArgumentException("'" + value + "' is not a valid ratio"); } final int amount = Integer.parseInt(matcher.group(1)); final int total = Optional.ofNullable(matcher.group(2)).map(Integer::parseInt).orElse(amount); return new Ratio(amount, total); } @SuppressWarnings("unused")  Ratio(final Integer value); @SuppressWarnings("unused")  Ratio(final String value); private  Ratio(final Ratio ratio);   }
@Test void shouldParseAmount() { final Ratio ratio = Ratio.valueOf("17"); assertThat(ratio.getAmount(), is(17)); assertThat(ratio.getTotal(), is(17)); }
@Test void shouldParseAmountOutOfTotal() { final Ratio ratio = Ratio.valueOf("3 out of 5"); assertThat(ratio.getAmount(), is(3)); assertThat(ratio.getTotal(), is(5)); }
@Test void shouldParseAmountOfTotal() { final Ratio ratio = Ratio.valueOf("3 of 5"); assertThat(ratio.getAmount(), is(3)); assertThat(ratio.getTotal(), is(5)); }
@Test void shouldParseAmountDividedTotal() { final Ratio ratio = Ratio.valueOf("3 / 5"); assertThat(ratio.getAmount(), is(3)); assertThat(ratio.getTotal(), is(5)); }
@Test void shouldParseAmountDividedTotalWithoutSpaces() { final Ratio ratio = Ratio.valueOf("3/5"); assertThat(ratio.getAmount(), is(3)); assertThat(ratio.getTotal(), is(5)); }
@Test void shouldFailOnUnsupportedRatioFormat() { assertThrows(IllegalArgumentException.class, () -> Ratio.valueOf("a lot out of many")); }