PiecewiseTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. <?php
  2. namespace MathPHP\Tests\Expression;
  3. use MathPHP\Expression\Piecewise;
  4. use MathPHP\Expression\Polynomial;
  5. use MathPHP\Exception;
  6. class PiecewiseTest extends \PHPUnit\Framework\TestCase
  7. {
  8. /** @var Piecewise|Mock */
  9. private $piecewise;
  10. /**
  11. * Set up mock Piecewise
  12. */
  13. public function setUp(): void
  14. {
  15. $this->piecewise = $this->getMockBuilder(Piecewise::class)
  16. ->disableOriginalConstructor()
  17. ->getMock();
  18. }
  19. /**
  20. * @test Piecewise __invoke evaluates the expected function to get the expected result
  21. * @dataProvider dataProviderForEval
  22. * @param array $intervals
  23. * @param array $polynomial_args
  24. * @param array $inputs
  25. * @param array $expected
  26. */
  27. public function testEval(array $intervals, array $polynomial_args, array $inputs, array $expected)
  28. {
  29. // Precondition
  30. if (count($inputs) !== count($expected)) {
  31. $this->fail('Number of inputs and expected outputs must match');
  32. }
  33. // Given
  34. $functions = \array_map(
  35. function ($args) {
  36. return new Polynomial($args);
  37. },
  38. $polynomial_args
  39. );
  40. $piecewise = new Piecewise($intervals, $functions);
  41. $n = count($inputs);
  42. for ($i = 0; $i < $n; $i++) {
  43. // When
  44. $evaluated = $piecewise($inputs[$i]);
  45. // Then
  46. $this->assertEquals($expected[$i], $evaluated);
  47. }
  48. }
  49. public function dataProviderForEval(): array
  50. {
  51. return [
  52. // Test evaluation given a single interval, function
  53. [
  54. [
  55. [-100, 100], // f interval: [-100, 100]
  56. ],
  57. [
  58. [1, 0], // new Polynomial([1, 0]) // f(x) = x
  59. ],
  60. [
  61. -100, // p(-100) = f(-100) = -100
  62. 0, // p(0) = f(0) = 0
  63. 1, // p(1) = f(1) = 1
  64. 25, // p(25) = f(25) = 25
  65. 100, // p(100) = f(100) = 100
  66. ],
  67. [
  68. -100, // p(-100) = f(-100) = -100
  69. 0, // p(0) = f(0) = 0
  70. 1, // p(1) = f(1) = 1
  71. 25, // p(25) = f(25) = 25
  72. 100, // p(100) = f(100) = 100
  73. ],
  74. ],
  75. // Test evaluation in 3 intervals, functions
  76. [
  77. [
  78. [-100, -2, false, true], // f interval: [-100, -2)
  79. [-2, 2], // g interval: [-2, 2]
  80. [2, 100, true, false] // h interval: (2, 100]
  81. ],
  82. [
  83. [-1, 0], // new Polynomial([-1, 0]), // f(x) = -x
  84. [2], // new Polynomial([2]), // g(x) = 2
  85. [1, 0], // new Polynomial([1, 0]) // h(x) = x
  86. ],
  87. [
  88. -27, // p(-27) = f(-27) = -(-27) = 27
  89. -3, // p(-3) = f(-3) = -(-3) = 3
  90. -2, // p(-2) = g(-2) = 2
  91. -1, // p(-1) = g(-1) = 2
  92. 0, // p(0) = g(0) = 2
  93. 1, // p(1) = g(1) = 2
  94. 2, // p(2) = g(2) = 2
  95. 3, // p(3) = h(3) = 3
  96. 20, // p(20) = h(20) = 20
  97. 100, // p(100) = h(100) = 100
  98. ],
  99. [
  100. 27, // p(-27) = f(-27) = -(-27) = 27
  101. 3, // p(-3) = f(-3) = -(-3) = 3
  102. 2, // p(-2) = g(-2) = 2
  103. 2, // p(-1) = g(-1) = 2
  104. 2, // p(0) = g(0) = 2
  105. 2, // p(1) = g(1) = 2
  106. 2, // p(2) = g(2) = 2
  107. 3, // p(3) = h(3) = 3
  108. 20, // p(20) = h(20) = 20
  109. 100, // p(100) = h(100) = 100
  110. ]
  111. ],
  112. // Test evaluation of 3 intervals, and at discountinuous, intermediate point
  113. [
  114. [
  115. [-100, -2, false, true], // f interval: [-100, -2)
  116. [-2, 2], // g interval: [-2, 2]
  117. [2, 100, true, false] // h interval: (2, 100]
  118. ],
  119. [
  120. [-1, 0], // new Polynomial([-1, 0]), // f(x) = -x
  121. [100], // new Polynomial([2]), // g(x) = 100
  122. [1, 0], // new Polynomial([1, 0]) // h(x) = x
  123. ],
  124. [
  125. -27, // p(-27) = f(-27) = -(-27) = 27
  126. -3, // p(-3) = f(-3) = -(-3) = 3
  127. -2, // p(-2) = g(-2) = 100
  128. -1, // p(-1) = g(-1) = 100
  129. 0, // p(0) = g(0) = 100
  130. 1, // p(1) = g(1) = 100
  131. 2, // p(2) = g(2) = 100
  132. 3, // p(3) = h(3) = 3
  133. 20, // p(20) = h(20) = 20
  134. 100, // p(100) = h(100) = 100
  135. ],
  136. [
  137. 27, // p(-27) = f(-27) = -(-27) = 27
  138. 3, // p(-3) = f(-3) = -(-3) = 3
  139. 100, // p(-2) = g(-2) = 2
  140. 100, // p(-1) = g(-1) = 2
  141. 100, // p(0) = g(0) = 2
  142. 100, // p(1) = g(1) = 2
  143. 100, // p(2) = g(2) = 100
  144. 3, // p(3) = h(3) = 3
  145. 20, // p(20) = h(20) = 20
  146. 100, // p(100) = h(100) = 100
  147. ]
  148. ],
  149. // Test evaluation when intervals are given out of order
  150. [
  151. [
  152. [-2, 2], // g interval: [-2, 2]
  153. [-100, -2, false, true], // f interval: [-100, -2)
  154. [2, 100, true, false] // h interval: (2, 100]
  155. ],
  156. [
  157. [2], // new Polynomial([2]), // g(x) = 2
  158. [-1, 0], // new Polynomial([-1, 0]), // f(x) = -x
  159. [1, 0], // new Polynomial([1, 0]) // h(x) = x
  160. ],
  161. [
  162. -27, // p(-27) = f(-27) = -(-27) = 27
  163. -3, // p(-3) = f(-3) = -(-3) = 3
  164. -2, // p(-2) = g(-2) = 2
  165. -1, // p(-1) = g(-1) = 2
  166. 0, // p(0) = g(0) = 2
  167. 1, // p(1) = g(1) = 2
  168. 2, // p(2) = g(2) = 2
  169. 3, // p(3) = h(3) = 3
  170. 20, // p(20) = h(20) = 20
  171. 100, // p(100) = h(100) = 100
  172. ],
  173. [
  174. 27, // p(-27) = f(-27) = -(-27) = 27
  175. 3, // p(-3) = f(-3) = -(-3) = 3
  176. 2, // p(-2) = g(-2) = 2
  177. 2, // p(-1) = g(-1) = 2
  178. 2, // p(0) = g(0) = 2
  179. 2, // p(1) = g(1) = 2
  180. 2, // p(2) = g(2) = 2
  181. 3, // p(3) = h(3) = 3
  182. 20, // p(20) = h(20) = 20
  183. 100, // p(100) = h(100) = 100
  184. ]
  185. ],
  186. // Test evaluation at "jump" located at a single point
  187. [
  188. [
  189. [-100, -2], // f interval: [-100, -2]
  190. [-2, 2, true, true], // g interval: (-2, 2)
  191. [2, 2], // z interval: [2, 2] jump point
  192. [2, 100, true, false] // h interval: (2, 100]
  193. ],
  194. [
  195. [-1, 0], // new Polynomial([-1, 0]), // f(x) = -x
  196. [2], // new Polynomial([2]), // g(x) = 2
  197. [0], // new Polynomial([0]), // z(x) = 0
  198. [1, 0], // new Polynomial([1, 0]) // h(x) = x
  199. ],
  200. [
  201. -27, // p(-27) = f(-27) = -(-27) = 27
  202. -3, // p(-3) = f(-3) = -(-3) = 3
  203. -2, // p(-2) = g(-2) = 2
  204. -1, // p(-1) = g(-1) = 2
  205. 0, // p(0) = g(0) = 2
  206. 1, // p(1) = g(1) = 2
  207. 2, // p(2) = z(2) = 0 // jump point
  208. 3, // p(3) = h(3) = 3
  209. 20, // p(20) = h(20) = 20
  210. 100, // p(100) = h(100) = 100
  211. ],
  212. [
  213. 27, // p(-27) = f(-27) = -(-27) = 27
  214. 3, // p(-3) = f(-3) = -(-3) = 3
  215. 2, // p(-2) = g(-2) = 2
  216. 2, // p(-1) = g(-1) = 2
  217. 2, // p(0) = g(0) = 2
  218. 2, // p(1) = g(1) = 2
  219. 0, // p(2) = z(2) = 0 // jump point
  220. 3, // p(3) = h(3) = 3
  221. 20, // p(20) = h(20) = 20
  222. 100, // p(100) = h(100) = 100
  223. ]
  224. ],
  225. // Large intervals
  226. [
  227. [
  228. [1499173200, 1499176800, false, true], // f interval: [1499173200, 1499176800)
  229. [1499176800, 1499180400], // g interval: [1499176800, 1499180400]
  230. [1499180400, 1499184000, true, false] // h interval: (1499180400, 1499184000]
  231. ],
  232. [
  233. [-1, 0], // new Polynomial([-1, 0]), // f(x) = -x
  234. [2], // new Polynomial([2]), // g(x) = 2
  235. [1, 0], // new Polynomial([1, 0]) // h(x) = x
  236. ],
  237. [
  238. 1499173200, // p(1499173200) = f(1499173200) = -(1499173200) = -1499173200
  239. 1499173201, // p(1499173201) = f(1499173201) = -(1499173201) = -1499173201
  240. 1499176799, // p(1499176799) = f(1499176799) = -(1499176799) = -1499176799
  241. 1499176800, // p(1499176800) = g(1499176800) = 2
  242. 1499176801, // p(1499176801) = g(1499176801) = 2
  243. 1499180400, // p(1499180400) = g(1499180400) = 2
  244. 1499180401, // p(1499180401) = h(1499180401) = 1499180401
  245. 1499184000, // p(1499184000) = h(1499184000) = 1499184000
  246. ],
  247. [
  248. -1499173200, // p(1499173200) = f(1499173200) = -(1499173200) = -1499173200
  249. -1499173201, // p(1499173201) = f(1499173201) = -(1499173201) = -1499173201
  250. -1499176799, // p(1499176799) = f(1499176799) = -(1499176799) = -1499176799
  251. 2, // p(1499176800) = g(1499176800) = 2
  252. 2, // p(1499176801) = g(1499176801) = 2
  253. 2, // p(1499180400) = g(1499180400) = 2
  254. 1499180401, // p(1499180401) = h(1499180401) = 1499180401
  255. 1499184000, // p(1499184000) = h(1499184000) = 1499184000
  256. ]
  257. ],
  258. ];
  259. }
  260. public function testSubintervalsShareClosedPointException()
  261. {
  262. // Given
  263. $intervals = [
  264. [-100, -2], // f interval: [-100, -2]
  265. [-2, 2], // g interval: [-2, 2]
  266. [2, 100] // h interval: [2, 100]
  267. ];
  268. $functions = [
  269. new Polynomial([-1, 0]), // f(x) = -x
  270. new Polynomial([2]), // g(x) = 2
  271. new Polynomial([1, 0]) // h(x) = x
  272. ];
  273. // Then
  274. $this->expectException(Exception\BadDataException::class);
  275. // When
  276. $piecewise = new Piecewise($intervals, $functions);
  277. }
  278. public function testSubintervalsOverlapException()
  279. {
  280. // Given
  281. $intervals = [
  282. [-100, -2], // f interval: [-100, -2]
  283. [-5, 1], // g interval: [-2, 1]
  284. [2, 100] // h interval: [2, 100]
  285. ];
  286. $functions = [
  287. new Polynomial([-1, 0]), // f(x) = -x
  288. new Polynomial([2]), // g(x) = 2
  289. new Polynomial([1, 0]) // h(x) = x
  290. ];
  291. // Then
  292. $this->expectException(Exception\BadDataException::class);
  293. // When
  294. $piecewise = new Piecewise($intervals, $functions);
  295. }
  296. public function testSubintervalDecreasingException()
  297. {
  298. // Given
  299. $intervals = [
  300. [-100, -2], // f interval: [-100, -2]
  301. [2, -2, true, true], // g interval: (-2, 2)
  302. [2, 100] // h interval: [2, 100]
  303. ];
  304. $functions = [
  305. new Polynomial([-1, 0]), // f(x) = -x
  306. new Polynomial([2]), // g(x) = 2
  307. new Polynomial([1, 0]) // h(x) = x
  308. ];
  309. // Then
  310. $this->expectException(Exception\BadDataException::class);
  311. // When
  312. $piecewise = new Piecewise($intervals, $functions);
  313. }
  314. public function testSubintervalContainsMoreThanTwoPoints()
  315. {
  316. // Given
  317. $intervals = [
  318. [-100, -2, false, true], // f interval: [-100, -2)
  319. [0, 2, 3], // g interval: [0, 3]
  320. [3, 100, true, false] // h interval: (3, 100]
  321. ];
  322. $functions = [
  323. new Polynomial([-1, 0]), // f(x) = -x
  324. new Polynomial([2]), // g(x) = 2
  325. new Polynomial([1, 0]) // h(x) = x
  326. ];
  327. // Then
  328. $this->expectException(Exception\BadDataException::class);
  329. // When
  330. $piecewise = new Piecewise($intervals, $functions);
  331. }
  332. public function testSubintervalContainsOnePoints()
  333. {
  334. // Given
  335. $intervals = [
  336. [-100, -2, false, true], // f interval: [-100, -2)
  337. [-2], // g interval: [-2, -2]
  338. [3, 100, true, false] // h interval: (3, 100]
  339. ];
  340. $functions = [
  341. new Polynomial([-1, 0]), // f(x) = -x
  342. new Polynomial([2]), // g(x) = 2
  343. new Polynomial([1, 0]) // h(x) = x
  344. ];
  345. // Then
  346. $this->expectException(Exception\BadDataException::class);
  347. // When
  348. $piecewise = new Piecewise($intervals, $functions);
  349. }
  350. public function testSubintervalContainsOpenPoint()
  351. {
  352. // Given
  353. $intervals = [
  354. [-100, -2, false, true], // f interval: [-100, -2)
  355. [-2, -2, true, true], // g interval: (-2, 2)
  356. [3, 100, true, false] // h interval: (3, 100]
  357. ];
  358. $functions = [
  359. new Polynomial([-1, 0]), // f(x) = -x
  360. new Polynomial([2]), // g(x) = 2
  361. new Polynomial([1, 0]) // h(x) = x
  362. ];
  363. // Then
  364. $this->expectException(Exception\BadDataException::class);
  365. // When
  366. $piecewise = new Piecewise($intervals, $functions);
  367. }
  368. public function testInputFunctionsAreNotCallableException()
  369. {
  370. // Given
  371. $intervals = [
  372. [-100, -2, false, true], // f interval: [-100, -2)
  373. [-2, 2], // g interval: [-2, 2]
  374. [2, 100, true, false] // h interval: (2, 100]
  375. ];
  376. $functions = [
  377. new Polynomial([-1, 0]), // f(x) = -x
  378. 2, // g(x) = 2
  379. new Polynomial([1, 0]) // h(x) = x
  380. ];
  381. // Then
  382. $this->expectException(Exception\BadDataException::class);
  383. // When
  384. $piecewise = new Piecewise($intervals, $functions);
  385. }
  386. public function testNumberOfIntervalsAndFunctionsUnequalException()
  387. {
  388. // Given
  389. $intervals = [
  390. [-100, -2, false, true], // f interval: [-100, -2)
  391. [0, 2], // g interval: [0, 2]
  392. [2, 100, true, false] // h interval: (2, 100]
  393. ];
  394. $functions = [
  395. new Polynomial([-1, 0]), // f(x) = -x
  396. new Polynomial([2]), // g(x) = 2
  397. ];
  398. // Then
  399. $this->expectException(Exception\BadDataException::class);
  400. // When
  401. $piecewise = new Piecewise($intervals, $functions);
  402. }
  403. public function testEvaluationNotInDomainException()
  404. {
  405. // Given
  406. $intervals = [
  407. [-100, -2, false, true], // f interval: [-100, -2)
  408. [0, 2], // g interval: [0, 2]
  409. [2, 100, true, false] // h interval: (2, 100]
  410. ];
  411. $functions = [
  412. new Polynomial([-1, 0]), // f(x) = -x
  413. new Polynomial([2]), // g(x) = 2
  414. new Polynomial([1, 0]) // h(x) = x
  415. ];
  416. $piecewise = new Piecewise($intervals, $functions);
  417. // Then
  418. $this->expectException(Exception\BadDataException::class);
  419. // When
  420. $evaluation = $piecewise(-1);
  421. }
  422. public function testEvaluatedAtOpenPointException()
  423. {
  424. // Given
  425. $intervals = [
  426. [-100, -2, true, true], // f interval: (-100, -2)
  427. [-2, 2, true, true], // g interval: (0, 2)
  428. [2, 100, true, true] // h interval: (2, 100)
  429. ];
  430. $functions = [
  431. new Polynomial([-1, 0]), // f(x) = -x
  432. new Polynomial([2]), // g(x) = 2
  433. new Polynomial([1, 0]) // h(x) = x
  434. ];
  435. $piecewise = new Piecewise($intervals, $functions);
  436. // Then
  437. $this->expectException(Exception\BadDataException::class);
  438. // When
  439. $evaluation = $piecewise(2);
  440. }
  441. public function testDuplicatedIntervalException()
  442. {
  443. // Given
  444. $intervals = [
  445. [-100, -2, true, true], // f interval: (-100, -2)
  446. [-100, -2, true, true], // g interval: [-100, -2)
  447. [2, 100] // h interval: [2, 100]
  448. ];
  449. $functions = [
  450. new Polynomial([-1, 0]), // f(x) = -x
  451. new Polynomial([2]), // g(x) = 2
  452. new Polynomial([1, 0]) // h(x) = x
  453. ];
  454. // Then
  455. $this->expectException(Exception\BadDataException::class);
  456. // When
  457. $piecewise = new Piecewise($intervals, $functions);
  458. }
  459. /**
  460. * @test preconditionExceptions throws an Exception\BadDataException if intervals and functions do not have the same number of elements
  461. */
  462. public function testConstructorPreconditionCountException()
  463. {
  464. // Given
  465. $intervals = [
  466. [1, 2],
  467. [2, 3],
  468. ];
  469. $functions = [
  470. new Polynomial([2])
  471. ];
  472. // And
  473. $preconditions = new \ReflectionMethod(Piecewise::class, 'constructorPreconditions');
  474. $preconditions->setAccessible(true);
  475. // Then
  476. $this->expectException(Exception\BadDataException::class);
  477. // When
  478. $preconditions->invokeArgs($this->piecewise, [$intervals, $functions]);
  479. }
  480. /**
  481. * @test preconditionExceptions throws an Exception\BadDataException if the functions are not callable
  482. */
  483. public function testConstructorPreconditionCallableException()
  484. {
  485. // Given
  486. $intervals = [
  487. [1, 2],
  488. [2, 3],
  489. ];
  490. $functions = [
  491. 'not a function',
  492. 'certainly not callable',
  493. ];
  494. // And
  495. $preconditions = new \ReflectionMethod(Piecewise::class, 'constructorPreconditions');
  496. $preconditions->setAccessible(true);
  497. // Then
  498. $this->expectException(Exception\BadDataException::class);
  499. // When
  500. $preconditions->invokeArgs($this->piecewise, [$intervals, $functions]);
  501. }
  502. /**
  503. * @test checkAsAndBs throws an Exception\BadDataException if a point is not closed
  504. */
  505. public function testCheckAsAndBsExceptionPointNotClosed()
  506. {
  507. // Given
  508. [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen] = [1, 1, null, null, null, true, true];
  509. // And
  510. $checkAsAndBs = new \ReflectionMethod(Piecewise::class, 'checkAsAndBs');
  511. $checkAsAndBs->setAccessible(true);
  512. // Then
  513. $this->expectException(Exception\BadDataException::class);
  514. // When
  515. $checkAsAndBs->invokeArgs($this->piecewise, [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen]);
  516. }
  517. /**
  518. * @test checkAsAndBs throws an Exception\BadDataException if interval not increasing
  519. */
  520. public function testCheckAsAndBsExceptionIntervalNotIncreasing()
  521. {
  522. // Given
  523. [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen] = [2, 1, null, null, null, true, true];
  524. // And
  525. $checkAsAndBs = new \ReflectionMethod(Piecewise::class, 'checkAsAndBs');
  526. $checkAsAndBs->setAccessible(true);
  527. // Then
  528. $this->expectException(Exception\BadDataException::class);
  529. // When
  530. $checkAsAndBs->invokeArgs($this->piecewise, [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen]);
  531. }
  532. /**
  533. * @test checkAsAndBs throws an Exception\BadDataException if two intervals share a point that is closed at both ends
  534. */
  535. public function testCheckAsAndBsExceptionTwoIntervalsSharePointNotClosedAtBothEnds()
  536. {
  537. // Given
  538. [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen] = [1, 2, null, 1, false, false, true];
  539. // And
  540. $checkAsAndBs = new \ReflectionMethod(Piecewise::class, 'checkAsAndBs');
  541. $checkAsAndBs->setAccessible(true);
  542. // Then
  543. $this->expectException(Exception\BadDataException::class);
  544. // When
  545. $checkAsAndBs->invokeArgs($this->piecewise, [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen]);
  546. }
  547. /**
  548. * @test checkAsAndBs throws an Exception\BadDataException if one interval starts or ends inside another interval
  549. */
  550. public function testCheckAsAndBsExceptionOverlappingIntervals()
  551. {
  552. // Given
  553. [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen] = [3, 4, 2, 4, true, true, true];
  554. // And
  555. $checkAsAndBs = new \ReflectionMethod(Piecewise::class, 'checkAsAndBs');
  556. $checkAsAndBs->setAccessible(true);
  557. // Then
  558. $this->expectException(Exception\BadDataException::class);
  559. // When
  560. $checkAsAndBs->invokeArgs($this->piecewise, [$a, $b, $lastA, $lastB, $lastBOpen, $aOpen, $bOpen]);
  561. }
  562. /**
  563. * @test openOpen interval
  564. * @dataProvider dataProviderForOpenOpen
  565. * @param bool $aOpen
  566. * @param bool $bOpen
  567. * @param bool $expected
  568. */
  569. public function testOpenOpen(bool $aOpen, bool $bOpen, bool $expected)
  570. {
  571. // Given
  572. $openOpen = new \ReflectionMethod(Piecewise::class, 'openOpen');
  573. $openOpen->setAccessible(true);
  574. // When
  575. $result = $openOpen->invokeArgs($this->piecewise, [$aOpen, $bOpen]);
  576. // Then
  577. $this->assertSame($expected, $result);
  578. }
  579. public function dataProviderForOpenOpen(): array
  580. {
  581. return [
  582. [true, true, true],
  583. [true, false, false],
  584. [false, true, false],
  585. [false, false, false],
  586. ];
  587. }
  588. /**
  589. * @test openClosed interval
  590. * @dataProvider dataProviderForOpenClosed
  591. * @param bool $aOpen
  592. * @param bool $bOpen
  593. * @param bool $expected
  594. */
  595. public function testOpenClosed(bool $aOpen, bool $bOpen, bool $expected)
  596. {
  597. // Given
  598. $openOpen = new \ReflectionMethod(Piecewise::class, 'openClosed');
  599. $openOpen->setAccessible(true);
  600. // When
  601. $result = $openOpen->invokeArgs($this->piecewise, [$aOpen, $bOpen]);
  602. // Then
  603. $this->assertSame($expected, $result);
  604. }
  605. public function dataProviderForOpenClosed(): array
  606. {
  607. return [
  608. [true, true, false],
  609. [true, false, true],
  610. [false, true, false],
  611. [false, false, false],
  612. ];
  613. }
  614. /**
  615. * @test closedOpen interval
  616. * @dataProvider dataProviderForClosedOpen
  617. * @param bool $aOpen
  618. * @param bool $bOpen
  619. * @param bool $expected
  620. */
  621. public function testClosedOpen(bool $aOpen, bool $bOpen, bool $expected)
  622. {
  623. // Given
  624. $openOpen = new \ReflectionMethod(Piecewise::class, 'closedOpen');
  625. $openOpen->setAccessible(true);
  626. $result = $openOpen->invokeArgs($this->piecewise, [$aOpen, $bOpen]);
  627. // Then
  628. $this->assertSame($expected, $result);
  629. }
  630. public function dataProviderForClosedOpen(): array
  631. {
  632. return [
  633. [true, true, false],
  634. [true, false, false],
  635. [false, true, true],
  636. [false, false, false],
  637. ];
  638. }
  639. /**
  640. * @test closedClosed interval
  641. * @dataProvider dataProviderForClosedClosed
  642. * @param bool $aOpen
  643. * @param bool $bOpen
  644. * @param bool $expected
  645. */
  646. public function testClosedClosed(bool $aOpen, bool $bOpen, bool $expected)
  647. {
  648. // Given
  649. $openOpen = new \ReflectionMethod(Piecewise::class, 'closedClosed');
  650. $openOpen->setAccessible(true);
  651. // When
  652. $result = $openOpen->invokeArgs($this->piecewise, [$aOpen, $bOpen]);
  653. // Then
  654. $this->assertSame($expected, $result);
  655. }
  656. public function dataProviderForClosedClosed(): array
  657. {
  658. return [
  659. [true, true, false],
  660. [true, false, false],
  661. [false, true, false],
  662. [false, false, true],
  663. ];
  664. }
  665. }