Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
String Calculator Kata
<?php
namespace App;
use Exception;
class StringCalculator
{
/**
* The maximum number allowed.
*/
const MAX_NUMBER_ALLOWED = 1000;
/**
* The delimiter for the numbers.
*
* @var string
*/
protected string $delimiter = ",|\n";
/**
* Add the provided set of numbers.
*
* @param string $numbers
* @return int
*
* @throws \Exception
*/
public function add(string $numbers)
{
$this->disallowNegatives($numbers = $this->parseString($numbers));
return array_sum(
$this->ignoreGreaterThan1000($numbers)
);
}
/**
* Parse the numbers string.
*
* @param string $numbers
* @return array
*/
protected function parseString(string $numbers): array
{
$customDelimiter = '\/\/(.)\n';
if (preg_match("/{$customDelimiter}/", $numbers, $matches)) {
$this->delimiter = $matches[1];
$numbers = str_replace($matches[0], '', $numbers);
}
return preg_split("/{$this->delimiter}/", $numbers);
}
/**
* Do not allow any negative numbers.
*
* @param array $numbers
* @throws Exception
*/
protected function disallowNegatives(array $numbers): void
{
foreach ($numbers as $number) {
if ($number < 0) {
throw new Exception('Negative numbers are disallowed.');
}
}
}
/**
* Forget any number that is greater than 1,000.
*
* @param array $numbers
* @return array
*/
protected function ignoreGreaterThan1000(array $numbers): array
{
return array_filter(
$numbers, fn($number) => $number <= self::MAX_NUMBER_ALLOWED
);
}
}
<?php
use App\StringCalculator;
use PHPUnit\Framework\TestCase;
class StringCalculatorTest extends TestCase
{
/** @test */
function it_evaluates_an_empty_string_as_0()
{
$calculator = new StringCalculator();
$this->assertSame(0, $calculator->add(''));
}
/** @test */
function it_finds_the_sum_of_a_single_number()
{
$calculator = new StringCalculator();
$this->assertSame(5, $calculator->add('5'));
}
/** @test */
function it_finds_the_sum_of_two_numbers()
{
$calculator = new StringCalculator();
$this->assertSame(10, $calculator->add('5,5'));
}
/** @test */
function it_finds_the_sum_of_any_amount_of_numbers()
{
$calculator = new StringCalculator();
$this->assertSame(19, $calculator->add('5,5,5,4'));
}
/** @test */
function it_accepts_a_new_line_character_as_a_delimiter_too()
{
$calculator = new StringCalculator();
$this->assertSame(10, $calculator->add("5\n5"));
}
/** @test */
function negative_numbers_are_not_allowed()
{
$calculator = new StringCalculator();
$this->expectException(\Exception::class);
$calculator->add('5,-4');
}
/** @test */
function numbers_greater_than_1000_are_ignored()
{
$calculator = new StringCalculator();
$this->assertEquals(5, $calculator->add('5,1001'));
}
/** @test */
function it_supports_custom_delimiters()
{
$calculator = new StringCalculator();
$this->assertEquals(20, $calculator->add("//:\n5:4:11"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.