ComplexOperationTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. namespace Complex;
  3. use Complex\Complex as Complex;
  4. class ComplexOperationTest extends \PHPUnit\Framework\TestCase
  5. {
  6. // Saved php.ini precision, so that we can adjust the setting
  7. private static $precision;
  8. // Number of significant digits used for assertEquals
  9. private $significantDigits = 14;
  10. /**
  11. * @beforeClass
  12. */
  13. public static function setPrecision()
  14. {
  15. self::$precision = ini_set('precision', 15);
  16. }
  17. /**
  18. * @afterClass
  19. */
  20. public static function resetPrecision()
  21. {
  22. ini_set('precision', self::$precision);
  23. }
  24. protected function getAssertionPrecision($value)
  25. {
  26. return \pow(10, floor(\log10($value)) - $this->significantDigits + 1);
  27. }
  28. public function complexNumberAssertions($expected, $result)
  29. {
  30. if (is_numeric($expected)) {
  31. $this->assertEqualsWithDelta(
  32. $expected,
  33. $result->getReal(),
  34. $this->getAssertionPrecision($expected),
  35. 'Numeric Assertion'
  36. );
  37. } else {
  38. $expected = new Complex($expected);
  39. $this->assertEqualsWithDelta(
  40. $expected->getReal(),
  41. $result->getReal(),
  42. $this->getAssertionPrecision($expected->getReal()),
  43. 'Real Component'
  44. );
  45. $this->assertEqualsWithDelta(
  46. $expected->getImaginary(),
  47. $result->getImaginary(),
  48. $this->getAssertionPrecision($expected->getImaginary()),
  49. 'Imaginary Component'
  50. );
  51. }
  52. }
  53. /**
  54. * @dataProvider providerAdd
  55. */
  56. public function testAdd()
  57. {
  58. $args = func_get_args();
  59. $complex = new Complex($args[0]);
  60. $result = $complex->add(
  61. new Complex($args[1])
  62. );
  63. $expected = new Complex($args[2]);
  64. $this->assertEqualsWithDelta($expected->getReal(), $result->getReal(), $this->getAssertionPrecision($expected->getReal()));
  65. $this->assertEqualsWithDelta($expected->getImaginary(), $result->getImaginary(), $this->getAssertionPrecision($expected->getImaginary()));
  66. // Verify that the original complex value remains unchanged
  67. $this->assertEquals(new Complex($args[0]), $complex);
  68. }
  69. public function testAddInvalid()
  70. {
  71. $this->expectException(Exception::class);
  72. $this->expectExceptionMessage('Suffix Mismatch');
  73. $complex = new Complex('12.34+56.78i');
  74. $result = $complex->add(
  75. new Complex(23),
  76. new Complex('34.56-78.90j')
  77. );
  78. }
  79. /**
  80. * @dataProvider providerSubtract
  81. */
  82. public function testSubtract()
  83. {
  84. $args = func_get_args();
  85. $complex = new Complex($args[0]);
  86. $result = $complex->subtract(
  87. new Complex($args[1])
  88. );
  89. $expected = new Complex($args[2]);
  90. $this->assertEqualsWithDelta($expected->getReal(), $result->getReal(), $this->getAssertionPrecision($expected->getReal()));
  91. $this->assertEqualsWithDelta($expected->getImaginary(), $result->getImaginary(), $this->getAssertionPrecision($expected->getImaginary()));
  92. // Verify that the original complex value remains unchanged
  93. $this->assertEquals(new Complex($args[0]), $complex);
  94. }
  95. public function testSubtractInvalid()
  96. {
  97. $this->expectException(Exception::class);
  98. $this->expectExceptionMessage('Suffix Mismatch');
  99. $complex = new Complex('12.34+56.78i');
  100. $result = $complex->subtract(
  101. new Complex(23),
  102. new Complex('34.56-78.90j')
  103. );
  104. }
  105. /**
  106. * @dataProvider providerMultiply
  107. */
  108. public function testMultiply()
  109. {
  110. $args = func_get_args();
  111. $complex = new Complex($args[0]);
  112. $result = $complex->multiply(
  113. new Complex($args[1])
  114. );
  115. $expected = new Complex($args[2]);
  116. $this->assertEqualsWithDelta($expected->getReal(), $result->getReal(), $this->getAssertionPrecision($expected->getReal()));
  117. $this->assertEqualsWithDelta($expected->getImaginary(), $result->getImaginary(), $this->getAssertionPrecision($expected->getImaginary()));
  118. // Verify that the original complex value remains unchanged
  119. $this->assertEquals(new Complex($args[0]), $complex);
  120. }
  121. public function testMultiplyInvalid()
  122. {
  123. $this->expectException(Exception::class);
  124. $this->expectExceptionMessage('Suffix Mismatch');
  125. $complex = new Complex('12.34+56.78i');
  126. $result = $complex->multiply(
  127. new Complex(23),
  128. new Complex('34.56-78.90j')
  129. );
  130. }
  131. /**
  132. * @dataProvider providerDivideBy
  133. */
  134. public function testDivideBy()
  135. {
  136. $args = func_get_args();
  137. $complex = new Complex($args[0]);
  138. $result = $complex->divideBy(
  139. new Complex($args[1])
  140. );
  141. $expected = new Complex($args[2]);
  142. $this->assertEqualsWithDelta($expected->getReal(), $result->getReal(), $this->getAssertionPrecision($expected->getReal()));
  143. $this->assertEqualsWithDelta($expected->getImaginary(), $result->getImaginary(), $this->getAssertionPrecision($expected->getImaginary()));
  144. // Verify that the original complex value remains unchanged
  145. $this->assertEquals(new Complex($args[0]), $complex);
  146. }
  147. public function testDivideByZero()
  148. {
  149. $this->expectException(\InvalidArgumentException::class);
  150. $complex = new Complex('2.5-i');
  151. $complex->divideBy(0.0);
  152. }
  153. public function testDivideByInvalid()
  154. {
  155. $this->expectException(Exception::class);
  156. $this->expectExceptionMessage('Suffix Mismatch');
  157. $complex = new Complex('12.34+56.78i');
  158. $result = $complex->divideBy(
  159. new Complex(23),
  160. new Complex('34.56-78.90j')
  161. );
  162. }
  163. /**
  164. * @dataProvider providerDivideInto
  165. */
  166. public function testDivideInto()
  167. {
  168. $args = func_get_args();
  169. $complex = new Complex($args[0]);
  170. $result = $complex->divideInto(
  171. new Complex($args[1])
  172. );
  173. $expected = new Complex($args[2]);
  174. $this->assertEqualsWithDelta($expected->getReal(), $result->getReal(), $this->getAssertionPrecision($expected->getReal()));
  175. $this->assertEqualsWithDelta($expected->getImaginary(), $result->getImaginary(), $this->getAssertionPrecision($expected->getImaginary()));
  176. // Verify that the original complex value remains unchanged
  177. $this->assertEquals(new Complex($args[0]), $complex);
  178. }
  179. public function testDivideIntoByZero()
  180. {
  181. $this->expectException(\InvalidArgumentException::class);
  182. $complex = new Complex(0.0);
  183. $complex->divideInto(
  184. new Complex('2.5-i')
  185. );
  186. }
  187. public function testDivideIntoInvalid()
  188. {
  189. $this->expectException(Exception::class);
  190. $this->expectExceptionMessage('Suffix Mismatch');
  191. $complex = new Complex('12.34+56.78i');
  192. $result = $complex->divideInto(
  193. new Complex(23),
  194. new Complex('34.56-78.90j')
  195. );
  196. }
  197. /**
  198. * @dataProvider providerNegative
  199. */
  200. public function testNegative()
  201. {
  202. $args = func_get_args();
  203. $complex = new Complex($args[0]);
  204. $result = $complex->negative();
  205. $this->complexNumberAssertions($args[1], $result);
  206. // Verify that the original complex value remains unchanged
  207. $this->assertEquals(new Complex($args[0]), $complex);
  208. }
  209. public function testValidateComplexArgument()
  210. {
  211. $this->expectException(Exception::class);
  212. $nonComplex = new \stdClass();
  213. Complex::validateComplexArgument($nonComplex);
  214. }
  215. public function testInvalidInvocation()
  216. {
  217. $this->expectException(Exception::class);
  218. $complex = new Complex('1.2+3.4i');
  219. $complex->someInvalidFunction();
  220. }
  221. private $oneComplexValueDataSets = [
  222. [12, null, null],
  223. [12.345, null, null],
  224. [0.12345, null, null],
  225. [12.345, 6.789, null],
  226. [12.345, -6.789, null],
  227. [0.12345, 6.789, null],
  228. [0.12345, -6.789, null],
  229. [0.12345, 0.6789, null],
  230. [0.12345, -0.6789, null],
  231. [-9.8765, null, null],
  232. [-0.98765, null, null],
  233. [-9.8765, +4.321, null],
  234. [-9.8765, -4.321, null],
  235. [-0.98765, 0.4321, null],
  236. [-0.98765, -0.4321, null],
  237. [0, M_PI, null],
  238. [0, -M_PI, null],
  239. [0, 1, null],
  240. [0, -1, null],
  241. [0, 0.123, null],
  242. [0, -0.123, null],
  243. ];
  244. private function formatOneArgumentTestResultArray($expectedResults)
  245. {
  246. $testValues = [];
  247. foreach ($this->oneComplexValueDataSets as $test => $dataSet) {
  248. $testValues[$test][] = $dataSet;
  249. $testValues[$test][] = $expectedResults[$test];
  250. }
  251. return $testValues;
  252. }
  253. private $twoComplexValueDataSets = [
  254. [123, null, null, 456, null, null],
  255. [123.456, null, null, 789.012, null, null],
  256. [123.456, 78.90, null, -987.654, -32.1, null],
  257. [123.456, 78.90, null, -987.654, null, null],
  258. [-987.654, -32.1, null, 0, 1, null],
  259. [-987.654, -32.1, null, 0, -1, null],
  260. ];
  261. private function formatTwoArgumentTestResultArray($expectedResults)
  262. {
  263. $testValues = [];
  264. foreach ($this->twoComplexValueDataSets as $test => $dataSet) {
  265. $testValues[$test][] = array_slice($dataSet, 0, 3);
  266. $testValues[$test][] = array_slice($dataSet, 3, 3);
  267. $testValues[$test][] = $expectedResults[$test];
  268. }
  269. return $testValues;
  270. }
  271. public function providerAdd()
  272. {
  273. $expectedResults = [
  274. 579,
  275. 912.468,
  276. '-864.198+46.8i',
  277. '-864.198+78.9i',
  278. '-987.654-31.1i',
  279. '-987.654-33.1i',
  280. ];
  281. return $this->formatTwoArgumentTestResultArray($expectedResults);
  282. }
  283. public function providerSubtract()
  284. {
  285. $expectedResults = [
  286. -333,
  287. -665.556,
  288. '1111.11+111i',
  289. '1111.11+78.9i',
  290. '-987.654-33.1i',
  291. '-987.654-31.1i',
  292. ];
  293. return $this->formatTwoArgumentTestResultArray($expectedResults);
  294. }
  295. public function providerMultiply()
  296. {
  297. $expectedResults = [
  298. 56088,
  299. 97408.265472,
  300. '-119399.122224-81888.8382i',
  301. '-121931.812224-77925.9006i',
  302. '32.1-987.654i',
  303. '-32.1+987.654i',
  304. ];
  305. return $this->formatTwoArgumentTestResultArray($expectedResults);
  306. }
  307. public function providerDivideBy()
  308. {
  309. $expectedResults = [
  310. 0.26973684210526,
  311. 0.15646910313151,
  312. '-0.127461004165656-0.07574363265504158i',
  313. '-0.1249992406247532-0.0798862759630397i',
  314. '-32.1+987.654i',
  315. '32.1-987.654i',
  316. ];
  317. return $this->formatTwoArgumentTestResultArray($expectedResults);
  318. }
  319. public function providerDivideInto()
  320. {
  321. $expectedResults = [
  322. 3.7073170731707,
  323. 6.3910381026439,
  324. '-5.798055462132258+3.44549131643853i',
  325. '-5.680072608981408+3.630100836319281i',
  326. '-3.287281241324573E-5-0.001011431921220928i',
  327. '3.287281241324573E-5+0.001011431921220928i',
  328. ];
  329. return $this->formatTwoArgumentTestResultArray($expectedResults);
  330. }
  331. /*
  332. */
  333. public function providerNegative()
  334. {
  335. $expectedResults = [
  336. -12,
  337. -12.345,
  338. -0.12345,
  339. '-12.345-6.789i',
  340. '-12.345+6.789i',
  341. '-0.12345-6.789i',
  342. '-0.12345+6.789i',
  343. '-0.12345-0.6789i',
  344. '-0.12345+0.6789i',
  345. 9.8765,
  346. 0.98765,
  347. '9.8765-4.321i',
  348. '9.8765+4.321i',
  349. '0.98765-0.4321i',
  350. '0.98765+0.4321i',
  351. '-3.14159265358979324i',
  352. '3.14159265358979324i',
  353. '-i',
  354. 'i',
  355. '-0.123i',
  356. '0.123i',
  357. ];
  358. return $this->formatOneArgumentTestResultArray($expectedResults);
  359. }
  360. }