assertInstanceOf(ObjectArithmetic::class, $c); } public function testZeroValue() { // Given $c = Quaternion::createZeroValue(); // Then $this->assertEquals(0, $c->r); $this->assertEquals(0, $c->i); $this->assertEquals(0, $c->j); $this->assertEquals(0, $c->k); } /** * @test __toString returns the proper string representation of a quaternion * @dataProvider dataProviderForToString * @param number $r * @param number $i * @param number $j * @param number $k * @param string $expected */ public function testToString($r, $i, $j, $k, string $expected) { // Given $c = new Quaternion($r, $i, $j, $k); // When $string = $c->__toString(); // Then $this->assertEquals($expected, $string); $this->assertEquals($expected, (string) $c); } public function dataProviderForToString(): array { return [ [0, 0, 0, 0, '0'], [1, 0, 0, 0, '1'], [-1, 0, 0, 0, '-1'], [0, 1, 0, 0, '1i'], [0, -1, 0, 0, '-1i'], [1, 0, 1, 0, '1 + 1j'], [1, 0, 0, 2, '1 + 2k'], [2, 0, -1, 0, '2 - 1j'], [2, 0, 0, -2, '2 - 2k'], [1, 0, -1, -1, '1 - 1j - 1k'], [1, 1, -2, 4, '1 + 1i - 2j + 4k'], ]; } /** * @test __get returns r, i, j, and k */ public function testGet() { // Given $r = 1; $i = 2; $j = 3; $k = 4; $c = new Quaternion($r, $i, $j, $k); // Then $this->assertEquals($r, $c->r); $this->assertEquals($i, $c->i); $this->assertEquals($j, $c->j); $this->assertEquals($k, $c->k); } /** * @test __get throws an Exception\BadParameterException if a property other than r or i is attempted */ public function testGetException() { // Given $r = 1; $i = 2; $j = 3; $k = 4; $c = new Quaternion($r, $i, $j, $k); // Then $this->expectException(Exception\BadParameterException::class); // When $z = $c->z; } /** * @test complexConjugate returns the expected Quaternion * @dataProvider dataProviderForComplexConjugate * @param number $r * @param number $i * @param number $j * @param number $k */ public function testComplexConjugate($r, $i, $j, $k) { // Given $c = new Quaternion($r, $i, $j, $k); // When $cc = $c->complexConjugate(); // Then $this->assertEquals($c->r, $cc->r); $this->assertEquals($c->i, -1 * $cc->i); $this->assertEquals($c->j, -1 * $cc->j); $this->assertEquals($c->k, -1 * $cc->k); } public function dataProviderForComplexConjugate(): array { return [ [0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 1], [1, 1, -1, -1], [1, 2, 3, 4], [3, 7, 11, -13], ]; } /** * @test abs returns the expected value * @dataProvider dataProviderForAbs * @param number $r * @param number $i * @param number $j * @param number $k * @param number $expected */ public function testAbs($r, $i, $j, $k, $expected) { // Given $c = new Quaternion($r, $i, $j, $k); // When $abs = $c->abs(); // Then $this->assertEquals($expected, $abs); } public function dataProviderForAbs(): array { return [ [0, 0, 0, 0, 0], [1, 0, 0, 0, 1], [0, 1, 0, 0, 1], [0, 0, 1, 0, 1], [0, 0, 0, 1, 1], [1, 2, 3, 4, \sqrt(30)], [-1, 0, 0, 0, 1], [0, -1, 0, 0, 1], [-1, 2, -3, 4, \sqrt(30)], ]; } /** * @test negate returns the expected quaternion with signs negated * @dataProvider dataProviderForNegate * @param number $r₁ * @param number $i₁ * @param number $r₂ * @param number $i₂ */ public function testNegate($r₁, $i₁, $j₁, $k₁, $r₂, $i₂, $j₂, $k₂) { // Given $c = new Quaternion($r₁, $i₁, $j₁, $k₁); $expected = new Quaternion($r₂, $i₂, $j₂, $k₂); // When $negated = $c->negate(); // Then $this->assertTrue($negated->equals($expected)); $this->assertEquals($expected->r, $negated->r); $this->assertEquals($expected->i, $negated->i); $this->assertEquals($expected->j, $negated->j); $this->assertEquals($expected->k, $negated->k); } public function dataProviderForNegate(): array { return [ [0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, -1, 0, 0, 0], [0, 1, 1, 1, 0, -1, -1, -1], [1, 2, -1, -2, -1, -2, 1, 2], [3, 4, 3, 4, -3, -4, -3, -4], ]; } /** * @test Constructor throws an exception when given non-numeric * @dataProvider dataProviderForConstructorException * @throws \Exception */ public function testConstructorException($r, $i, $j, $k) { // Then $this->expectException(Exception\BadDataException::class); // When $c = new Quaternion($r, $i, $j, $k); } public function dataProviderForConstructorException(): array { return [ ['a', 1, 1, 1], [1, true, 1, 1], [1, 1, new \stdClass(), 1], [1, 1, 1, [1]], ]; } /** * @testCase inverse returns the expected quaternion * @dataProvider dataProviderForInverse * @param number $r * @param number $i * @param number $j * @param number $k * @param number $expected_r * @param number $expected_i * @param number $expected_j * @param number $expected_k */ public function testInverse($r, $i, $j, $k, $expected_r, $expected_i, $expected_j, $expected_k) { $q = new Quaternion($r, $i, $j, $k); $inverse = $q->inverse(); $this->assertEquals($expected_r, $inverse->r); $this->assertEquals($expected_i, $inverse->i); $this->assertEquals($expected_j, $inverse->j); $this->assertEquals($expected_k, $inverse->k); } public function dataProviderForInverse(): array { return [ [1, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, -1, 0, 0], [0, 0, 1, 0, 0, 0, -1, 0], [0, 0, 0, 1, 0, 0, 0, -1], [1, -1, -1, -1, .25, .25, .25, .25], ]; } /** * @testCase inverse throws an Exception\BadDataException when value is 0 + 0i + 0j + 0k */ public function testInverseException() { $q = new Quaternion(0, 0, 0, 0); $this->expectException(Exception\BadDataException::class); $q->inverse(); } /** * @test add of two complex numbers returns the expected complex number * @dataProvider dataProviderForAdd * @param array $complex1 * @param array $complex2 * @param array $expected */ public function testAdd(array $complex1, array $complex2, array $expected) { // Given $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']); $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']); // When $result = $q1->add($q2); // Then $this->assertEquals($expected['r'], $result->r); $this->assertEquals($expected['i'], $result->i); $this->assertEquals($expected['j'], $result->j); $this->assertEquals($expected['k'], $result->k); } public function dataProviderForAdd(): array { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], ['r' => 4, 'i' => -3, 'j' => -2, 'k' => -5], ['r' => 7, 'i' => -1, 'j' => -1, 'k' => -6], ], ]; } /** * @test subtract of two quaternions returns the expected quaternion * @dataProvider dataProviderForSubtract * @param array $complex1 * @param array $complex2 * @param array $expected */ public function testSubtract(array $complex1, array $complex2, array $expected) { // Given $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']); $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']); // When $result = $q1->subtract($q2); // Then $this->assertEquals($expected['r'], $result->r); $this->assertEquals($expected['i'], $result->i); $this->assertEquals($expected['j'], $result->j); $this->assertEquals($expected['k'], $result->k); } public function dataProviderForSubtract(): array { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], ['r' => -4, 'i' => 3, 'j' => 2, 'k' => 5], ['r' => 7, 'i' => -1, 'j' => -1, 'k' => -6], ], ]; } /** * @test add of real numbers returns the expected quaternion * @dataProvider dataProviderForAddReal */ public function testAddReal($complex, $real, $expected) { // Given $q = new Quaternion($complex['r'], $complex['i'], $complex['j'], $complex['k']); // When $result = $q->add($real); // Then $this->assertEquals($expected['r'], $result->r); $this->assertEquals($expected['i'], $result->i); $this->assertEquals($expected['j'], $result->j); $this->assertEquals($expected['k'], $result->k); } public function dataProviderForAddReal() { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], 5, ['r' => 8, 'i' => 2, 'j' => 1, 'k' => -1], ], [ ['r' => 0, 'i' => 0, 'j' => 0, 'k' => 0], 5, ['r' => 5, 'i' => 0, 'j' => 0, 'k' => 0], ], [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], -2, ['r' => 1, 'i' => 2, 'j' => 1, 'k' => -1], ], ]; } /** * @test subtract of real numbers returns the expected quaternion * @dataProvider dataProviderForSubtractReal */ public function testSubtractReal($complex, $real, $expected) { // Given $q = new Quaternion($complex['r'], $complex['i'], $complex['j'], $complex['k']); // When $result = $q->subtract($real); // Then $this->assertEquals($expected['r'], $result->r); $this->assertEquals($expected['i'], $result->i); $this->assertEquals($expected['j'], $result->j); $this->assertEquals($expected['k'], $result->k); } public function dataProviderForSubtractReal() { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], -5, ['r' => 8, 'i' => 2, 'j' => 1, 'k' => -1], ], [ ['r' => 0, 'i' => 0, 'j' => 0, 'k' => 0], -5, ['r' => 5, 'i' => 0, 'j' => 0, 'k' => 0], ], [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], 2, ['r' => 1, 'i' => 2, 'j' => 1, 'k' => -1], ], ]; } /** * @test multiply of two quaternions returns the expected quaternion * @dataProvider dataProviderForMultiply * @param array $complex1 * @param array $complex2 * @param array $expected */ public function testMultiply(array $complex1, array $complex2, array $expected) { // Given $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']); $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']); // When $result = $q1->multiply($q2); // Then $this->assertEquals($expected['r'], $result->r); $this->assertEquals($expected['i'], $result->i); $this->assertEquals($expected['j'], $result->j); $this->assertEquals($expected['k'], $result->k); } public function dataProviderForMultiply(): array { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], ['r' => 1, 'i' => 4, 'j' => 3, 'k' => 2], ['r' => -6, 'i' => 19, 'j' => 2, 'k' => 7], ], [ ['r' => 3, 'i' => 13, 'j' => 5, 'k' => 7], ['r' => 19, 'i' => 17, 'j' => -11, 'k' => 2], ['r' => -123, 'i' => 385, 'j' => 155, 'k' => -89], ], [ ['r' => 2, 'i' => 3, 'j' => 4, 'k' => 5], ['r' => 6, 'i' => 7, 'j' => 8, 'k' => 9], ['r' => -86, 'i' => 28, 'j' => 48, 'k' => 44], ], ]; } /** * @test divide of two cquaternions returns the expected quaternion * @dataProvider dataProviderForDivide * @param array $complex1 * @param array $complex2 * @param array $expected */ public function testDivide(array $complex1, array $complex2, array $expected) { // Given $q1 = new Quaternion($complex1['r'], $complex1['i'], $complex1['j'], $complex1['k']); $q2 = new Quaternion($complex2['r'], $complex2['i'], $complex2['j'], $complex2['k']); // When $result = $q1->divide($q2); // Then $this->assertEqualsWithDelta($expected['r'], $result->r, 0.00001); $this->assertEqualsWithDelta($expected['i'], $result->i, 0.00001); $this->assertEqualsWithDelta($expected['j'], $result->j, 0.00001); $this->assertEqualsWithDelta($expected['k'], $result->k, 0.00001); } public function dataProviderForDivide(): array { return [ [ ['r' => 3, 'i' => 2, 'j' => 1, 'k' => -1], ['r' => 1, 'i' => 4, 'j' => 3, 'k' => 2], ['r' => 2 / 5, 'i' => -1 / 2, 'j' => 0, 'k' => -3 / 10], ], ]; } /** * @test add throws an Exception\IncorrectTypeException when the argument is not a number or quaternion */ public function testQuaternionAddException() { // Given $q = new Quaternion(1, 1, 1, 1); // Then $this->expectException(Exception\IncorrectTypeException::class); // When $q->add("string"); } /** * @test subtract throws an Exception\IncorrectTypeException when the argument is not a number or quaternion */ public function testQuaternionSubtractException() { // Given $q = new Quaternion(1, 1, 1, 1); // Then $this->expectException(Exception\IncorrectTypeException::class); // When $q->subtract("string"); } /** * @test multiply throws an Exception\IncorrectTypeException when the argument is not a number or quaternion */ public function tesQuaternionMultiplyException() { // Given $q = new Quaternion(1, 1, 1, 1); // Then $this->expectException(Exception\IncorrectTypeException::class); // When $q->multiply("string"); } /** * @test divide throws an Exception\IncorrectTypeException when the argument is not a number or quaternion */ public function testQuaternionDivideException() { // Given $q = new Quaternion(1, 1, 1, 1); // Then $this->expectException(Exception\IncorrectTypeException::class); // When $q->divide("string"); } }