AssertTest.php 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. <?php
  2. namespace Illuminate\Tests\Testing\Fluent;
  3. use Illuminate\Support\Collection;
  4. use Illuminate\Testing\Fluent\AssertableJson;
  5. use Illuminate\Tests\Testing\Stubs\ArrayableStubObject;
  6. use PHPUnit\Framework\AssertionFailedError;
  7. use PHPUnit\Framework\TestCase;
  8. use RuntimeException;
  9. use TypeError;
  10. class AssertTest extends TestCase
  11. {
  12. public function testAssertHas()
  13. {
  14. $assert = AssertableJson::fromArray([
  15. 'prop' => 'value',
  16. ]);
  17. $assert->has('prop');
  18. }
  19. public function testAssertHasFailsWhenPropMissing()
  20. {
  21. $assert = AssertableJson::fromArray([
  22. 'bar' => 'value',
  23. ]);
  24. $this->expectException(AssertionFailedError::class);
  25. $this->expectExceptionMessage('Property [prop] does not exist.');
  26. $assert->has('prop');
  27. }
  28. public function testAssertHasNestedProp()
  29. {
  30. $assert = AssertableJson::fromArray([
  31. 'example' => [
  32. 'nested' => 'nested-value',
  33. ],
  34. ]);
  35. $assert->has('example.nested');
  36. }
  37. public function testAssertHasFailsWhenNestedPropMissing()
  38. {
  39. $assert = AssertableJson::fromArray([
  40. 'example' => [
  41. 'nested' => 'nested-value',
  42. ],
  43. ]);
  44. $this->expectException(AssertionFailedError::class);
  45. $this->expectExceptionMessage('Property [example.another] does not exist.');
  46. $assert->has('example.another');
  47. }
  48. public function testAssertHasCountItemsInProp()
  49. {
  50. $assert = AssertableJson::fromArray([
  51. 'bar' => [
  52. 'baz' => 'example',
  53. 'prop' => 'value',
  54. ],
  55. ]);
  56. $assert->has('bar', 2);
  57. }
  58. public function testAssertHasCountFailsWhenAmountOfItemsDoesNotMatch()
  59. {
  60. $assert = AssertableJson::fromArray([
  61. 'bar' => [
  62. 'baz' => 'example',
  63. 'prop' => 'value',
  64. ],
  65. ]);
  66. $this->expectException(AssertionFailedError::class);
  67. $this->expectExceptionMessage('Property [bar] does not have the expected size.');
  68. $assert->has('bar', 1);
  69. }
  70. public function testAssertHasCountFailsWhenPropMissing()
  71. {
  72. $assert = AssertableJson::fromArray([
  73. 'bar' => [
  74. 'baz' => 'example',
  75. 'prop' => 'value',
  76. ],
  77. ]);
  78. $this->expectException(AssertionFailedError::class);
  79. $this->expectExceptionMessage('Property [baz] does not exist.');
  80. $assert->has('baz', 1);
  81. }
  82. public function testAssertHasFailsWhenSecondArgumentUnsupportedType()
  83. {
  84. $assert = AssertableJson::fromArray([
  85. 'bar' => 'baz',
  86. ]);
  87. $this->expectException(TypeError::class);
  88. $assert->has('bar', 'invalid');
  89. }
  90. public function testAssertHasOnlyCounts()
  91. {
  92. $assert = AssertableJson::fromArray([
  93. 'foo',
  94. 'bar',
  95. 'baz',
  96. ]);
  97. $assert->has(3);
  98. }
  99. public function testAssertHasOnlyCountFails()
  100. {
  101. $assert = AssertableJson::fromArray([
  102. 'foo',
  103. 'bar',
  104. 'baz',
  105. ]);
  106. $this->expectException(AssertionFailedError::class);
  107. $this->expectExceptionMessage('Root level does not have the expected size.');
  108. $assert->has(2);
  109. }
  110. public function testAssertHasOnlyCountFailsScoped()
  111. {
  112. $assert = AssertableJson::fromArray([
  113. 'bar' => [
  114. 'baz' => 'example',
  115. 'prop' => 'value',
  116. ],
  117. ]);
  118. $this->expectException(AssertionFailedError::class);
  119. $this->expectExceptionMessage('Property [bar] does not have the expected size.');
  120. $assert->has('bar', function ($bar) {
  121. $bar->has(3);
  122. });
  123. }
  124. public function testAssertCount()
  125. {
  126. $assert = AssertableJson::fromArray([
  127. 'foo',
  128. 'bar',
  129. 'baz',
  130. ]);
  131. $assert->count(3);
  132. }
  133. public function testAssertCountFails()
  134. {
  135. $assert = AssertableJson::fromArray([
  136. 'foo',
  137. 'bar',
  138. 'baz',
  139. ]);
  140. $this->expectException(AssertionFailedError::class);
  141. $this->expectExceptionMessage('Root level does not have the expected size.');
  142. $assert->count(2);
  143. }
  144. public function testAssertCountFailsScoped()
  145. {
  146. $assert = AssertableJson::fromArray([
  147. 'bar' => [
  148. 'baz' => 'example',
  149. 'prop' => 'value',
  150. ],
  151. ]);
  152. $this->expectException(AssertionFailedError::class);
  153. $this->expectExceptionMessage('Property [bar] does not have the expected size.');
  154. $assert->has('bar', function ($bar) {
  155. $bar->count(3);
  156. });
  157. }
  158. public function testAssertMissing()
  159. {
  160. $assert = AssertableJson::fromArray([
  161. 'foo' => [
  162. 'bar' => true,
  163. ],
  164. ]);
  165. $assert->missing('foo.baz');
  166. }
  167. public function testAssertMissingFailsWhenPropExists()
  168. {
  169. $assert = AssertableJson::fromArray([
  170. 'prop' => 'value',
  171. 'foo' => [
  172. 'bar' => true,
  173. ],
  174. ]);
  175. $this->expectException(AssertionFailedError::class);
  176. $this->expectExceptionMessage('Property [foo.bar] was found while it was expected to be missing.');
  177. $assert->missing('foo.bar');
  178. }
  179. public function testAssertMissingAll()
  180. {
  181. $assert = AssertableJson::fromArray([
  182. 'baz' => 'foo',
  183. ]);
  184. $assert->missingAll([
  185. 'foo',
  186. 'bar',
  187. ]);
  188. }
  189. public function testAssertMissingAllFailsWhenAtLeastOnePropExists()
  190. {
  191. $assert = AssertableJson::fromArray([
  192. 'baz' => 'foo',
  193. ]);
  194. $this->expectException(AssertionFailedError::class);
  195. $this->expectExceptionMessage('Property [baz] was found while it was expected to be missing.');
  196. $assert->missingAll([
  197. 'bar',
  198. 'baz',
  199. ]);
  200. }
  201. public function testAssertMissingAllAcceptsMultipleArgumentsInsteadOfArray()
  202. {
  203. $assert = AssertableJson::fromArray([
  204. 'baz' => 'foo',
  205. ]);
  206. $assert->missingAll('foo', 'bar');
  207. $this->expectException(AssertionFailedError::class);
  208. $this->expectExceptionMessage('Property [baz] was found while it was expected to be missing.');
  209. $assert->missingAll('bar', 'baz');
  210. }
  211. public function testAssertWhereMatchesValue()
  212. {
  213. $assert = AssertableJson::fromArray([
  214. 'bar' => 'value',
  215. ]);
  216. $assert->where('bar', 'value');
  217. }
  218. public function testAssertWhereFailsWhenDoesNotMatchValue()
  219. {
  220. $assert = AssertableJson::fromArray([
  221. 'bar' => 'value',
  222. ]);
  223. $this->expectException(AssertionFailedError::class);
  224. $this->expectExceptionMessage('Property [bar] does not match the expected value.');
  225. $assert->where('bar', 'invalid');
  226. }
  227. public function testAssertWhereFailsWhenMissing()
  228. {
  229. $assert = AssertableJson::fromArray([
  230. 'bar' => 'value',
  231. ]);
  232. $this->expectException(AssertionFailedError::class);
  233. $this->expectExceptionMessage('Property [baz] does not exist.');
  234. $assert->where('baz', 'invalid');
  235. }
  236. public function testAssertWhereFailsWhenMachingLoosely()
  237. {
  238. $assert = AssertableJson::fromArray([
  239. 'bar' => 1,
  240. ]);
  241. $this->expectException(AssertionFailedError::class);
  242. $this->expectExceptionMessage('Property [bar] does not match the expected value.');
  243. $assert->where('bar', true);
  244. }
  245. public function testAssertWhereUsingClosure()
  246. {
  247. $assert = AssertableJson::fromArray([
  248. 'bar' => 'baz',
  249. ]);
  250. $assert->where('bar', function ($value) {
  251. return $value === 'baz';
  252. });
  253. }
  254. public function testAssertWhereFailsWhenDoesNotMatchValueUsingClosure()
  255. {
  256. $assert = AssertableJson::fromArray([
  257. 'bar' => 'baz',
  258. ]);
  259. $this->expectException(AssertionFailedError::class);
  260. $this->expectExceptionMessage('Property [bar] was marked as invalid using a closure.');
  261. $assert->where('bar', function ($value) {
  262. return $value === 'invalid';
  263. });
  264. }
  265. public function testAssertWhereClosureArrayValuesAreAutomaticallyCastedToCollections()
  266. {
  267. $assert = AssertableJson::fromArray([
  268. 'bar' => [
  269. 'baz' => 'foo',
  270. 'example' => 'value',
  271. ],
  272. ]);
  273. $assert->where('bar', function ($value) {
  274. $this->assertInstanceOf(Collection::class, $value);
  275. return $value->count() === 2;
  276. });
  277. }
  278. public function testAssertWhereMatchesValueUsingArrayable()
  279. {
  280. $stub = ArrayableStubObject::make(['foo' => 'bar']);
  281. $assert = AssertableJson::fromArray([
  282. 'bar' => $stub->toArray(),
  283. ]);
  284. $assert->where('bar', $stub);
  285. }
  286. public function testAssertWhereMatchesValueUsingArrayableWhenSortedDifferently()
  287. {
  288. $assert = AssertableJson::fromArray([
  289. 'data' => [
  290. 'status' => 200,
  291. 'user' => [
  292. 'id' => 1,
  293. 'name' => 'Taylor',
  294. ],
  295. ],
  296. ]);
  297. $assert->where('data', [
  298. 'user' => [
  299. 'name' => 'Taylor',
  300. 'id' => 1,
  301. ],
  302. 'status' => 200,
  303. ]);
  304. }
  305. public function testAssertWhereFailsWhenDoesNotMatchValueUsingArrayable()
  306. {
  307. $assert = AssertableJson::fromArray([
  308. 'bar' => ['id' => 1, 'name' => 'Example'],
  309. 'baz' => [
  310. 'id' => 1,
  311. 'name' => 'Taylor Otwell',
  312. 'email' => 'taylor@laravel.com',
  313. 'email_verified_at' => '2021-01-22T10:34:42.000000Z',
  314. 'created_at' => '2021-01-22T10:34:42.000000Z',
  315. 'updated_at' => '2021-01-22T10:34:42.000000Z',
  316. ],
  317. ]);
  318. $assert
  319. ->where('bar', ArrayableStubObject::make(['name' => 'Example', 'id' => 1]))
  320. ->where('baz', [
  321. 'name' => 'Taylor Otwell',
  322. 'email' => 'taylor@laravel.com',
  323. 'id' => 1,
  324. 'email_verified_at' => '2021-01-22T10:34:42.000000Z',
  325. 'updated_at' => '2021-01-22T10:34:42.000000Z',
  326. 'created_at' => '2021-01-22T10:34:42.000000Z',
  327. ]);
  328. }
  329. public function testAssertWhereContainsFailsWithEmptyValue()
  330. {
  331. $assert = AssertableJson::fromArray([]);
  332. $this->expectException(AssertionFailedError::class);
  333. $this->expectExceptionMessage('Property [foo] does not contain [1].');
  334. $assert->whereContains('foo', ['1']);
  335. }
  336. public function testAssertWhereContainsFailsWithMissingValue()
  337. {
  338. $assert = AssertableJson::fromArray([
  339. 'foo' => ['bar', 'baz'],
  340. ]);
  341. $this->expectException(AssertionFailedError::class);
  342. $this->expectExceptionMessage('Property [foo] does not contain [invalid].');
  343. $assert->whereContains('foo', ['bar', 'baz', 'invalid']);
  344. }
  345. public function testAssertWhereContainsFailsWithMissingNestedValue()
  346. {
  347. $assert = AssertableJson::fromArray([
  348. ['id' => 1],
  349. ['id' => 2],
  350. ['id' => 3],
  351. ['id' => 4],
  352. ]);
  353. $this->expectException(AssertionFailedError::class);
  354. $this->expectExceptionMessage('Property [id] does not contain [5].');
  355. $assert->whereContains('id', [1, 2, 3, 4, 5]);
  356. }
  357. public function testAssertWhereContainsFailsWhenDoesNotMatchType()
  358. {
  359. $assert = AssertableJson::fromArray([
  360. 'foo' => [1, 2, 3, 4],
  361. ]);
  362. $this->expectException(AssertionFailedError::class);
  363. $this->expectExceptionMessage('Property [foo] does not contain [1].');
  364. $assert->whereContains('foo', ['1']);
  365. }
  366. public function testAssertWhereContainsFailsWhenDoesNotSatisfyClosure()
  367. {
  368. $assert = AssertableJson::fromArray([
  369. 'foo' => [1, 2, 3, 4],
  370. ]);
  371. $this->expectException(AssertionFailedError::class);
  372. $this->expectExceptionMessage('Property [foo] does not contain a value that passes the truth test within the given closure.');
  373. $assert->whereContains('foo', [function ($actual) {
  374. return $actual === 5;
  375. }]);
  376. }
  377. public function testAssertWhereContainsFailsWhenHavingExpectedValueButDoesNotSatisfyClosure()
  378. {
  379. $assert = AssertableJson::fromArray([
  380. 'foo' => [1, 2, 3, 4],
  381. ]);
  382. $this->expectException(AssertionFailedError::class);
  383. $this->expectExceptionMessage('Property [foo] does not contain a value that passes the truth test within the given closure.');
  384. $assert->whereContains('foo', [1, function ($actual) {
  385. return $actual === 5;
  386. }]);
  387. }
  388. public function testAssertWhereContainsFailsWhenSatisfiesClosureButDoesNotHaveExpectedValue()
  389. {
  390. $assert = AssertableJson::fromArray([
  391. 'foo' => [1, 2, 3, 4],
  392. ]);
  393. $this->expectException(AssertionFailedError::class);
  394. $this->expectExceptionMessage('Property [foo] does not contain [5].');
  395. $assert->whereContains('foo', [5, function ($actual) {
  396. return $actual === 1;
  397. }]);
  398. }
  399. public function testAssertWhereContainsWithNestedValue()
  400. {
  401. $assert = AssertableJson::fromArray([
  402. ['id' => 1],
  403. ['id' => 2],
  404. ['id' => 3],
  405. ['id' => 4],
  406. ]);
  407. $assert->whereContains('id', 1);
  408. $assert->whereContains('id', [1, 2, 3, 4]);
  409. $assert->whereContains('id', [4, 3, 2, 1]);
  410. }
  411. public function testAssertWhereContainsWithMatchingType()
  412. {
  413. $assert = AssertableJson::fromArray([
  414. 'foo' => [1, 2, 3, 4],
  415. ]);
  416. $assert->whereContains('foo', 1);
  417. $assert->whereContains('foo', [1]);
  418. }
  419. public function testAssertWhereContainsWithNullValue()
  420. {
  421. $assert = AssertableJson::fromArray([
  422. 'foo' => null,
  423. ]);
  424. $assert->whereContains('foo', null);
  425. $assert->whereContains('foo', [null]);
  426. }
  427. public function testAssertWhereContainsWithOutOfOrderMatchingType()
  428. {
  429. $assert = AssertableJson::fromArray([
  430. 'foo' => [4, 1, 7, 3],
  431. ]);
  432. $assert->whereContains('foo', [1, 7, 4, 3]);
  433. }
  434. public function testAssertWhereContainsWithOutOfOrderNestedMatchingType()
  435. {
  436. $assert = AssertableJson::fromArray([
  437. ['bar' => 5],
  438. ['baz' => 4],
  439. ['zal' => 8],
  440. ]);
  441. $assert->whereContains('baz', 4);
  442. }
  443. public function testAssertWhereContainsWithClosure()
  444. {
  445. $assert = AssertableJson::fromArray([
  446. 'foo' => [1, 2, 3, 4],
  447. ]);
  448. $assert->whereContains('foo', function ($actual) {
  449. return $actual % 3 === 0;
  450. });
  451. }
  452. public function testAssertWhereContainsWithNestedClosure()
  453. {
  454. $assert = AssertableJson::fromArray([
  455. 'foo' => 1,
  456. 'bar' => 2,
  457. 'baz' => 3,
  458. ]);
  459. $assert->whereContains('baz', function ($actual) {
  460. return $actual % 3 === 0;
  461. });
  462. }
  463. public function testAssertWhereContainsWithMultipleClosure()
  464. {
  465. $assert = AssertableJson::fromArray([
  466. 'foo' => [1, 2, 3, 4],
  467. ]);
  468. $assert->whereContains('foo', [
  469. function ($actual) {
  470. return $actual % 3 === 0;
  471. },
  472. function ($actual) {
  473. return $actual % 2 === 0;
  474. },
  475. ]);
  476. }
  477. public function testAssertWhereContainsWithNullExpectation()
  478. {
  479. $assert = AssertableJson::fromArray([
  480. 'foo' => 1,
  481. ]);
  482. $assert->whereContains('foo', null);
  483. }
  484. public function testAssertNestedWhereMatchesValue()
  485. {
  486. $assert = AssertableJson::fromArray([
  487. 'example' => [
  488. 'nested' => 'nested-value',
  489. ],
  490. ]);
  491. $assert->where('example.nested', 'nested-value');
  492. }
  493. public function testAssertNestedWhereFailsWhenDoesNotMatchValue()
  494. {
  495. $assert = AssertableJson::fromArray([
  496. 'example' => [
  497. 'nested' => 'nested-value',
  498. ],
  499. ]);
  500. $this->expectException(AssertionFailedError::class);
  501. $this->expectExceptionMessage('Property [example.nested] does not match the expected value.');
  502. $assert->where('example.nested', 'another-value');
  503. }
  504. public function testScope()
  505. {
  506. $assert = AssertableJson::fromArray([
  507. 'bar' => [
  508. 'baz' => 'example',
  509. 'prop' => 'value',
  510. ],
  511. ]);
  512. $called = false;
  513. $assert->has('bar', function (AssertableJson $assert) use (&$called) {
  514. $called = true;
  515. $assert
  516. ->where('baz', 'example')
  517. ->where('prop', 'value');
  518. });
  519. $this->assertTrue($called, 'The scoped query was never actually called.');
  520. }
  521. public function testScopeFailsWhenPropMissing()
  522. {
  523. $assert = AssertableJson::fromArray([
  524. 'bar' => [
  525. 'baz' => 'example',
  526. 'prop' => 'value',
  527. ],
  528. ]);
  529. $this->expectException(AssertionFailedError::class);
  530. $this->expectExceptionMessage('Property [baz] does not exist.');
  531. $assert->has('baz', function (AssertableJson $item) {
  532. $item->where('baz', 'example');
  533. });
  534. }
  535. public function testScopeFailsWhenPropSingleValue()
  536. {
  537. $assert = AssertableJson::fromArray([
  538. 'bar' => 'value',
  539. ]);
  540. $this->expectException(AssertionFailedError::class);
  541. $this->expectExceptionMessage('Property [bar] is not scopeable.');
  542. $assert->has('bar', function (AssertableJson $item) {
  543. //
  544. });
  545. }
  546. public function testScopeShorthand()
  547. {
  548. $assert = AssertableJson::fromArray([
  549. 'bar' => [
  550. ['key' => 'first'],
  551. ['key' => 'second'],
  552. ],
  553. ]);
  554. $called = false;
  555. $assert->has('bar', 2, function (AssertableJson $item) use (&$called) {
  556. $item->where('key', 'first');
  557. $called = true;
  558. });
  559. $this->assertTrue($called, 'The scoped query was never actually called.');
  560. }
  561. public function testScopeShorthandWithoutCount()
  562. {
  563. $assert = AssertableJson::fromArray([
  564. 'bar' => [
  565. ['key' => 'first'],
  566. ['key' => 'second'],
  567. ],
  568. ]);
  569. $called = false;
  570. $assert->has('bar', null, function (AssertableJson $item) use (&$called) {
  571. $item->where('key', 'first');
  572. $called = true;
  573. });
  574. $this->assertTrue($called, 'The scoped query was never actually called.');
  575. }
  576. public function testScopeShorthandFailsWhenAssertingZeroItems()
  577. {
  578. $assert = AssertableJson::fromArray([
  579. 'bar' => [
  580. ['key' => 'first'],
  581. ['key' => 'second'],
  582. ],
  583. ]);
  584. $this->expectException(AssertionFailedError::class);
  585. $this->expectExceptionMessage('Property [bar] does not have the expected size.');
  586. $assert->has('bar', 0, function (AssertableJson $item) {
  587. $item->where('key', 'first');
  588. });
  589. }
  590. public function testScopeShorthandFailsWhenAmountOfItemsDoesNotMatch()
  591. {
  592. $assert = AssertableJson::fromArray([
  593. 'bar' => [
  594. ['key' => 'first'],
  595. ['key' => 'second'],
  596. ],
  597. ]);
  598. $this->expectException(AssertionFailedError::class);
  599. $this->expectExceptionMessage('Property [bar] does not have the expected size.');
  600. $assert->has('bar', 1, function (AssertableJson $item) {
  601. $item->where('key', 'first');
  602. });
  603. }
  604. public function testScopeShorthandFailsWhenAssertingEmptyArray()
  605. {
  606. $assert = AssertableJson::fromArray([
  607. 'bar' => [],
  608. ]);
  609. $this->expectException(AssertionFailedError::class);
  610. $this->expectExceptionMessage(
  611. 'Cannot scope directly onto the first element of property [bar] because it is empty.'
  612. );
  613. $assert->has('bar', 0, function (AssertableJson $item) {
  614. $item->where('key', 'first');
  615. });
  616. }
  617. public function testScopeShorthandFailsWhenAssertingEmptyArrayWithoutCount()
  618. {
  619. $assert = AssertableJson::fromArray([
  620. 'bar' => [],
  621. ]);
  622. $this->expectException(AssertionFailedError::class);
  623. $this->expectExceptionMessage(
  624. 'Cannot scope directly onto the first element of property [bar] because it is empty.'
  625. );
  626. $assert->has('bar', null, function (AssertableJson $item) {
  627. $item->where('key', 'first');
  628. });
  629. }
  630. public function testScopeShorthandFailsWhenSecondArgumentUnsupportedType()
  631. {
  632. $assert = AssertableJson::fromArray([
  633. 'bar' => [
  634. ['key' => 'first'],
  635. ['key' => 'second'],
  636. ],
  637. ]);
  638. $this->expectException(TypeError::class);
  639. $assert->has('bar', 'invalid', function (AssertableJson $item) {
  640. $item->where('key', 'first');
  641. });
  642. }
  643. public function testFirstScope()
  644. {
  645. $assert = AssertableJson::fromArray([
  646. 'foo' => [
  647. 'key' => 'first',
  648. ],
  649. 'bar' => [
  650. 'key' => 'second',
  651. ],
  652. ]);
  653. $assert->first(function (AssertableJson $item) {
  654. $item->where('key', 'first');
  655. });
  656. }
  657. public function testFirstScopeFailsWhenNoProps()
  658. {
  659. $assert = AssertableJson::fromArray([]);
  660. $this->expectException(AssertionFailedError::class);
  661. $this->expectExceptionMessage('Cannot scope directly onto the first element of the root level because it is empty.');
  662. $assert->first(function (AssertableJson $item) {
  663. //
  664. });
  665. }
  666. public function testFirstNestedScopeFailsWhenNoProps()
  667. {
  668. $assert = AssertableJson::fromArray([
  669. 'foo' => [],
  670. ]);
  671. $this->expectException(AssertionFailedError::class);
  672. $this->expectExceptionMessage('Cannot scope directly onto the first element of property [foo] because it is empty.');
  673. $assert->has('foo', function (AssertableJson $assert) {
  674. $assert->first(function (AssertableJson $item) {
  675. //
  676. });
  677. });
  678. }
  679. public function testFirstScopeFailsWhenPropSingleValue()
  680. {
  681. $assert = AssertableJson::fromArray([
  682. 'foo' => 'bar',
  683. ]);
  684. $this->expectException(AssertionFailedError::class);
  685. $this->expectExceptionMessage('Property [foo] is not scopeable.');
  686. $assert->first(function (AssertableJson $item) {
  687. //
  688. });
  689. }
  690. public function testEachScope()
  691. {
  692. $assert = AssertableJson::fromArray([
  693. 'foo' => [
  694. 'key' => 'first',
  695. ],
  696. 'bar' => [
  697. 'key' => 'second',
  698. ],
  699. ]);
  700. $assert->each(function (AssertableJson $item) {
  701. $item->whereType('key', 'string');
  702. });
  703. }
  704. public function testEachScopeFailsWhenNoProps()
  705. {
  706. $assert = AssertableJson::fromArray([]);
  707. $this->expectException(AssertionFailedError::class);
  708. $this->expectExceptionMessage('Cannot scope directly onto each element of the root level because it is empty.');
  709. $assert->each(function (AssertableJson $item) {
  710. //
  711. });
  712. }
  713. public function testEachNestedScopeFailsWhenNoProps()
  714. {
  715. $assert = AssertableJson::fromArray([
  716. 'foo' => [],
  717. ]);
  718. $this->expectException(AssertionFailedError::class);
  719. $this->expectExceptionMessage('Cannot scope directly onto each element of property [foo] because it is empty.');
  720. $assert->has('foo', function (AssertableJson $assert) {
  721. $assert->each(function (AssertableJson $item) {
  722. //
  723. });
  724. });
  725. }
  726. public function testEachScopeFailsWhenPropSingleValue()
  727. {
  728. $assert = AssertableJson::fromArray([
  729. 'foo' => 'bar',
  730. ]);
  731. $this->expectException(AssertionFailedError::class);
  732. $this->expectExceptionMessage('Property [foo] is not scopeable.');
  733. $assert->each(function (AssertableJson $item) {
  734. //
  735. });
  736. }
  737. public function testFailsWhenNotInteractingWithAllPropsInScope()
  738. {
  739. $assert = AssertableJson::fromArray([
  740. 'bar' => [
  741. 'baz' => 'example',
  742. 'prop' => 'value',
  743. ],
  744. ]);
  745. $this->expectException(AssertionFailedError::class);
  746. $this->expectExceptionMessage('Unexpected properties were found in scope [bar].');
  747. $assert->has('bar', function (AssertableJson $item) {
  748. $item->where('baz', 'example');
  749. });
  750. }
  751. public function testDisableInteractionCheckForCurrentScope()
  752. {
  753. $assert = AssertableJson::fromArray([
  754. 'bar' => [
  755. 'baz' => 'example',
  756. 'prop' => 'value',
  757. ],
  758. ]);
  759. $assert->has('bar', function (AssertableJson $item) {
  760. $item->etc();
  761. });
  762. }
  763. public function testCannotDisableInteractionCheckForDifferentScopes()
  764. {
  765. $assert = AssertableJson::fromArray([
  766. 'bar' => [
  767. 'baz' => [
  768. 'foo' => 'bar',
  769. 'example' => 'value',
  770. ],
  771. 'prop' => 'value',
  772. ],
  773. ]);
  774. $this->expectException(AssertionFailedError::class);
  775. $this->expectExceptionMessage('Unexpected properties were found in scope [bar.baz].');
  776. $assert->has('bar', function (AssertableJson $item) {
  777. $item
  778. ->etc()
  779. ->has('baz', function (AssertableJson $item) {
  780. //
  781. });
  782. });
  783. }
  784. public function testTopLevelPropInteractionDisabledByDefault()
  785. {
  786. $assert = AssertableJson::fromArray([
  787. 'foo' => 'bar',
  788. 'bar' => 'baz',
  789. ]);
  790. $assert->has('foo');
  791. }
  792. public function testTopLevelInteractionEnabledWhenInteractedFlagSet()
  793. {
  794. $assert = AssertableJson::fromArray([
  795. 'foo' => 'bar',
  796. 'bar' => 'baz',
  797. ]);
  798. $this->expectException(AssertionFailedError::class);
  799. $this->expectExceptionMessage('Unexpected properties were found on the root level.');
  800. $assert
  801. ->has('foo')
  802. ->interacted();
  803. }
  804. public function testAssertWhereAllMatchesValues()
  805. {
  806. $assert = AssertableJson::fromArray([
  807. 'foo' => [
  808. 'bar' => 'value',
  809. 'example' => ['hello' => 'world'],
  810. ],
  811. 'baz' => 'another',
  812. ]);
  813. $assert->whereAll([
  814. 'foo.bar' => 'value',
  815. 'foo.example' => ArrayableStubObject::make(['hello' => 'world']),
  816. 'baz' => function ($value) {
  817. return $value === 'another';
  818. },
  819. ]);
  820. }
  821. public function testAssertWhereAllFailsWhenAtLeastOnePropDoesNotMatchValue()
  822. {
  823. $assert = AssertableJson::fromArray([
  824. 'foo' => 'bar',
  825. 'baz' => 'example',
  826. ]);
  827. $this->expectException(AssertionFailedError::class);
  828. $this->expectExceptionMessage('Property [baz] was marked as invalid using a closure.');
  829. $assert->whereAll([
  830. 'foo' => 'bar',
  831. 'baz' => function ($value) {
  832. return $value === 'foo';
  833. },
  834. ]);
  835. }
  836. public function testAssertWhereTypeString()
  837. {
  838. $assert = AssertableJson::fromArray([
  839. 'foo' => 'bar',
  840. ]);
  841. $assert->whereType('foo', 'string');
  842. }
  843. public function testAssertWhereTypeInteger()
  844. {
  845. $assert = AssertableJson::fromArray([
  846. 'foo' => 123,
  847. ]);
  848. $assert->whereType('foo', 'integer');
  849. }
  850. public function testAssertWhereTypeBoolean()
  851. {
  852. $assert = AssertableJson::fromArray([
  853. 'foo' => true,
  854. ]);
  855. $assert->whereType('foo', 'boolean');
  856. }
  857. public function testAssertWhereTypeDouble()
  858. {
  859. $assert = AssertableJson::fromArray([
  860. 'foo' => 12.3,
  861. ]);
  862. $assert->whereType('foo', 'double');
  863. }
  864. public function testAssertWhereTypeArray()
  865. {
  866. $assert = AssertableJson::fromArray([
  867. 'foo' => ['bar', 'baz'],
  868. 'bar' => ['foo' => 'baz'],
  869. ]);
  870. $assert->whereType('foo', 'array');
  871. $assert->whereType('bar', 'array');
  872. }
  873. public function testAssertWhereTypeNull()
  874. {
  875. $assert = AssertableJson::fromArray([
  876. 'foo' => null,
  877. ]);
  878. $assert->whereType('foo', 'null');
  879. }
  880. public function testAssertWhereAllType()
  881. {
  882. $assert = AssertableJson::fromArray([
  883. 'one' => 'foo',
  884. 'two' => 123,
  885. 'three' => true,
  886. 'four' => 12.3,
  887. 'five' => ['foo', 'bar'],
  888. 'six' => ['foo' => 'bar'],
  889. 'seven' => null,
  890. ]);
  891. $assert->whereAllType([
  892. 'one' => 'string',
  893. 'two' => 'integer',
  894. 'three' => 'boolean',
  895. 'four' => 'double',
  896. 'five' => 'array',
  897. 'six' => 'array',
  898. 'seven' => 'null',
  899. ]);
  900. }
  901. public function testAssertWhereTypeWhenWrongTypeIsGiven()
  902. {
  903. $assert = AssertableJson::fromArray([
  904. 'foo' => 'bar',
  905. ]);
  906. $this->expectException(AssertionFailedError::class);
  907. $this->expectExceptionMessage('Property [foo] is not of expected type [integer].');
  908. $assert->whereType('foo', 'integer');
  909. }
  910. public function testAssertWhereTypeWithUnionTypes()
  911. {
  912. $firstAssert = AssertableJson::fromArray([
  913. 'foo' => 'bar',
  914. ]);
  915. $secondAssert = AssertableJson::fromArray([
  916. 'foo' => null,
  917. ]);
  918. $firstAssert->whereType('foo', ['string', 'null']);
  919. $secondAssert->whereType('foo', ['string', 'null']);
  920. }
  921. public function testAssertWhereTypeWhenWrongUnionTypeIsGiven()
  922. {
  923. $assert = AssertableJson::fromArray([
  924. 'foo' => 123,
  925. ]);
  926. $this->expectException(AssertionFailedError::class);
  927. $this->expectExceptionMessage('Property [foo] is not of expected type [string|null].');
  928. $assert->whereType('foo', ['string', 'null']);
  929. }
  930. public function testAssertWhereTypeWithPipeInUnionType()
  931. {
  932. $assert = AssertableJson::fromArray([
  933. 'foo' => 'bar',
  934. ]);
  935. $assert->whereType('foo', 'string|null');
  936. }
  937. public function testAssertWhereTypeWithPipeInWrongUnionType()
  938. {
  939. $assert = AssertableJson::fromArray([
  940. 'foo' => 'bar',
  941. ]);
  942. $this->expectException(AssertionFailedError::class);
  943. $this->expectExceptionMessage('Property [foo] is not of expected type [integer|null].');
  944. $assert->whereType('foo', 'integer|null');
  945. }
  946. public function testAssertHasAll()
  947. {
  948. $assert = AssertableJson::fromArray([
  949. 'foo' => [
  950. 'bar' => 'value',
  951. 'example' => ['hello' => 'world'],
  952. ],
  953. 'baz' => 'another',
  954. ]);
  955. $assert->hasAll([
  956. 'foo.bar',
  957. 'foo.example',
  958. 'baz',
  959. ]);
  960. }
  961. public function testAssertHasAllFailsWhenAtLeastOnePropMissing()
  962. {
  963. $assert = AssertableJson::fromArray([
  964. 'foo' => [
  965. 'bar' => 'value',
  966. 'example' => ['hello' => 'world'],
  967. ],
  968. 'baz' => 'another',
  969. ]);
  970. $this->expectException(AssertionFailedError::class);
  971. $this->expectExceptionMessage('Property [foo.baz] does not exist.');
  972. $assert->hasAll([
  973. 'foo.bar',
  974. 'foo.baz',
  975. 'baz',
  976. ]);
  977. }
  978. public function testAssertHasAllAcceptsMultipleArgumentsInsteadOfArray()
  979. {
  980. $assert = AssertableJson::fromArray([
  981. 'foo' => [
  982. 'bar' => 'value',
  983. 'example' => ['hello' => 'world'],
  984. ],
  985. 'baz' => 'another',
  986. ]);
  987. $assert->hasAll('foo.bar', 'foo.example', 'baz');
  988. $this->expectException(AssertionFailedError::class);
  989. $this->expectExceptionMessage('Property [foo.baz] does not exist.');
  990. $assert->hasAll('foo.bar', 'foo.baz', 'baz');
  991. }
  992. public function testAssertCountMultipleProps()
  993. {
  994. $assert = AssertableJson::fromArray([
  995. 'bar' => [
  996. 'key' => 'value',
  997. 'prop' => 'example',
  998. ],
  999. 'baz' => [
  1000. 'another' => 'value',
  1001. ],
  1002. ]);
  1003. $assert->hasAll([
  1004. 'bar' => 2,
  1005. 'baz' => 1,
  1006. ]);
  1007. }
  1008. public function testAssertCountMultiplePropsFailsWhenPropMissing()
  1009. {
  1010. $assert = AssertableJson::fromArray([
  1011. 'bar' => [
  1012. 'key' => 'value',
  1013. 'prop' => 'example',
  1014. ],
  1015. ]);
  1016. $this->expectException(AssertionFailedError::class);
  1017. $this->expectExceptionMessage('Property [baz] does not exist.');
  1018. $assert->hasAll([
  1019. 'bar' => 2,
  1020. 'baz' => 1,
  1021. ]);
  1022. }
  1023. public function testMacroable()
  1024. {
  1025. AssertableJson::macro('myCustomMacro', function () {
  1026. throw new RuntimeException('My Custom Macro was called!');
  1027. });
  1028. $this->expectException(RuntimeException::class);
  1029. $this->expectExceptionMessage('My Custom Macro was called!');
  1030. $assert = AssertableJson::fromArray(['foo' => 'bar']);
  1031. $assert->myCustomMacro();
  1032. }
  1033. public function testTappable()
  1034. {
  1035. $assert = AssertableJson::fromArray([
  1036. 'bar' => [
  1037. 'baz' => 'example',
  1038. 'prop' => 'value',
  1039. ],
  1040. ]);
  1041. $called = false;
  1042. $assert->has('bar', function (AssertableJson $assert) use (&$called) {
  1043. $assert->etc();
  1044. $assert->tap(function (AssertableJson $assert) use (&$called) {
  1045. $called = true;
  1046. });
  1047. });
  1048. $this->assertTrue($called, 'The scoped query was never actually called.');
  1049. }
  1050. }