api de gestion de ticket, basé sur php-crud-api. Le but est de décorrélé les outils de gestion des données, afin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Tests.php 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. <?php
  2. namespace Mevdschee\PhpCrudApi\Tests;
  3. abstract class Tests extends TestBase
  4. {
  5. public function testListPosts()
  6. {
  7. $test = new Api($this);
  8. $test->get('/posts');
  9. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[1,1,1,"blog started"],[2,1,2,"It works!"]]}}');
  10. }
  11. public function testListPostColumns()
  12. {
  13. $test = new Api($this);
  14. $test->get('/posts?columns=id,content');
  15. $test->expect('{"posts":{"columns":["id","content"],"records":[[1,"blog started"],[2,"It works!"]]}}');
  16. }
  17. public function testListPostsWithTransform()
  18. {
  19. $test = new Api($this);
  20. $test->get('/posts?transform=1');
  21. $test->expect('{"posts":[{"id":1,"user_id":1,"category_id":1,"content":"blog started"},{"id":2,"user_id":1,"category_id":2,"content":"It works!"}]}');
  22. }
  23. public function testReadPost()
  24. {
  25. $test = new Api($this);
  26. $test->get('/posts/2');
  27. $test->expect('{"id":2,"user_id":1,"category_id":2,"content":"It works!"}');
  28. }
  29. public function testReadPosts()
  30. {
  31. $test = new Api($this);
  32. $test->get('/posts/1,2');
  33. $test->expect('[{"id":1,"user_id":1,"category_id":1,"content":"blog started"},{"id":2,"user_id":1,"category_id":2,"content":"It works!"}]');
  34. }
  35. public function testReadPostColumns()
  36. {
  37. $test = new Api($this);
  38. $test->get('/posts/2?columns=id,content');
  39. $test->expect('{"id":2,"content":"It works!"}');
  40. }
  41. public function testAddPost()
  42. {
  43. $test = new Api($this);
  44. $test->post('/posts', '{"user_id":1,"category_id":1,"content":"test"}');
  45. $test->expect('3');
  46. }
  47. public function testEditPost()
  48. {
  49. $test = new Api($this);
  50. $test->put('/posts/3', '{"user_id":1,"category_id":1,"content":"test (edited)"}');
  51. $test->expect('1');
  52. $test->get('/posts/3');
  53. $test->expect('{"id":3,"user_id":1,"category_id":1,"content":"test (edited)"}');
  54. }
  55. public function testEditPostColumnsMissingField()
  56. {
  57. $test = new Api($this);
  58. $test->put('/posts/3?columns=id,content', '{"content":"test (edited 2)"}');
  59. $test->expect('1');
  60. $test->get('/posts/3');
  61. $test->expect('{"id":3,"user_id":1,"category_id":1,"content":"test (edited 2)"}');
  62. }
  63. public function testEditPostColumnsExtraField()
  64. {
  65. $test = new Api($this);
  66. $test->put('/posts/3?columns=id,content', '{"user_id":2,"content":"test (edited 3)"}');
  67. $test->expect('1');
  68. $test->get('/posts/3');
  69. $test->expect('{"id":3,"user_id":1,"category_id":1,"content":"test (edited 3)"}');
  70. }
  71. public function testEditPostWithUtf8Content()
  72. {
  73. $utf8 = json_encode('Hello world, Καλημέρα κόσμε, コンニチハ');
  74. $test = new Api($this);
  75. $test->put('/posts/2', '{"content":' . $utf8 . '}');
  76. $test->expect('1');
  77. $test->get('/posts/2');
  78. $test->expect('{"id":2,"user_id":1,"category_id":2,"content":' . $utf8 . '}');
  79. }
  80. public function testEditPostWithUtf8ContentWithPost()
  81. {
  82. $utf8 = '€ Hello world, Καλημέρα κόσμε, コンニチハ';
  83. $url_encoded = urlencode($utf8);
  84. $json_encoded = json_encode($utf8);
  85. $test = new Api($this);
  86. $test->put('/posts/2', 'content=' . $url_encoded);
  87. $test->expect('1');
  88. $test->get('/posts/2');
  89. $test->expect('{"id":2,"user_id":1,"category_id":2,"content":' . $json_encoded . '}');
  90. }
  91. public function testDeletePost()
  92. {
  93. $test = new Api($this);
  94. $test->delete('/posts/3');
  95. $test->expect('1');
  96. $test->get('/posts/3');
  97. $test->expect(false, 'Not found (object)');
  98. }
  99. public function testAddPostWithPost()
  100. {
  101. $test = new Api($this);
  102. $test->post('/posts', 'user_id=1&category_id=1&content=test');
  103. $test->expect('4');
  104. }
  105. public function testEditPostWithPost()
  106. {
  107. $test = new Api($this);
  108. $test->put('/posts/4', 'user_id=1&category_id=1&content=test+(edited)');
  109. $test->expect('1');
  110. $test->get('/posts/4');
  111. $test->expect('{"id":4,"user_id":1,"category_id":1,"content":"test (edited)"}');
  112. }
  113. public function testDeletePostWithPost()
  114. {
  115. $test = new Api($this);
  116. $test->delete('/posts/4');
  117. $test->expect('1');
  118. $test->get('/posts/4');
  119. $test->expect(false, 'Not found (object)');
  120. }
  121. public function testListWithPaginate()
  122. {
  123. $test = new Api($this);
  124. for ($i = 1; $i <= 10; $i++) {
  125. $test->post('/posts', '{"user_id":1,"category_id":1,"content":"#' . $i . '"}');
  126. $test->expect(4 + $i);
  127. }
  128. $test->get('/posts?page=2,2&order=id');
  129. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[5,1,1,"#1"],[6,1,1,"#2"]],"results":11}}');
  130. }
  131. public function testListWithPaginateInMultipleOrder()
  132. {
  133. $test = new Api($this);
  134. $test->get('/posts?page=1,2&order[]=category_id,asc&order[]=id,desc');
  135. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[14,1,1,"#10"],[12,1,1,"#8"]],"results":11}}');
  136. }
  137. public function testListWithPaginateInDescendingOrder()
  138. {
  139. $test = new Api($this);
  140. $test->get('/posts?page=2,2&order=id,desc');
  141. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[11,1,1,"#7"],[10,1,1,"#6"]],"results":11}}');
  142. }
  143. public function testListWithPaginateLastPage()
  144. {
  145. $test = new Api($this);
  146. $test->get('/posts?page=3,5&order=id');
  147. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[14,1,1,"#10"]],"results":11}}');
  148. }
  149. public function testListExampleFromReadmeFullRecord()
  150. {
  151. $test = new Api($this);
  152. $test->get('/posts?filter=id,eq,1');
  153. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[1,1,1,"blog started"]]}}');
  154. }
  155. public function testListExampleFromReadmeWithExclude()
  156. {
  157. $test = new Api($this);
  158. $test->get('/posts?exclude=id&filter=id,eq,1');
  159. $test->expect('{"posts":{"columns":["user_id","category_id","content"],"records":[[1,1,"blog started"]]}}');
  160. }
  161. public function testListExampleFromReadme()
  162. {
  163. $test = new Api($this);
  164. $test->get('/posts?include=categories,tags,comments&filter=id,eq,1');
  165. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[[1,1,1,"blog started"]]},"post_tags":{"relations":{"post_id":"posts.id"},"columns":["id","post_id","tag_id"],"records":[[1,1,1],[2,1,2]]},"categories":{"relations":{"id":"posts.category_id"},"columns":["id","name","icon"],"records":[[1,"announcement",null]]},"tags":{"relations":{"id":"post_tags.tag_id"},"columns":["id","name"],"records":[[1,"funny"],[2,"important"]]},"comments":{"relations":{"post_id":"posts.id"},"columns":["id","post_id","message"],"records":[[1,1,"great"],[2,1,"fantastic"]]}}');
  166. }
  167. public function testListExampleFromReadmeWithTransform()
  168. {
  169. $test = new Api($this);
  170. $test->get('/posts?include=categories,tags,comments&filter=id,eq,1&transform=1');
  171. $test->expect('{"posts":[{"id":1,"post_tags":[{"id":1,"post_id":1,"tag_id":1,"tags":[{"id":1,"name":"funny"}]},{"id":2,"post_id":1,"tag_id":2,"tags":[{"id":2,"name":"important"}]}],"comments":[{"id":1,"post_id":1,"message":"great"},{"id":2,"post_id":1,"message":"fantastic"}],"user_id":1,"category_id":1,"categories":[{"id":1,"name":"announcement","icon":null}],"content":"blog started"}]}');
  172. }
  173. public function testListExampleFromReadmeWithTransformWithExclude()
  174. {
  175. $test = new Api($this);
  176. $test->get('/posts?include=categories,tags,comments&exclude=comments.message&filter=id,eq,1&transform=1');
  177. $test->expect('{"posts":[{"id":1,"post_tags":[{"id":1,"post_id":1,"tag_id":1,"tags":[{"id":1,"name":"funny"}]},{"id":2,"post_id":1,"tag_id":2,"tags":[{"id":2,"name":"important"}]}],"comments":[{"id":1,"post_id":1},{"id":2,"post_id":1}],"user_id":1,"category_id":1,"categories":[{"id":1,"name":"announcement","icon":null}],"content":"blog started"}]}');
  178. }
  179. public function testEditCategoryWithBinaryContent()
  180. {
  181. $binary = base64_encode("\0abc\0\n\r\b\0");
  182. $base64url = rtrim(strtr($binary, '+/', '-_'), '=');
  183. $test = new Api($this);
  184. $test->put('/categories/2', '{"icon":"' . $base64url . '"}');
  185. $test->expect('1');
  186. $test->get('/categories/2');
  187. $test->expect('{"id":2,"name":"article","icon":"' . $binary . '"}');
  188. }
  189. public function testEditCategoryWithNull()
  190. {
  191. $test = new Api($this);
  192. $test->put('/categories/2', '{"icon":null}');
  193. $test->expect('1');
  194. $test->get('/categories/2');
  195. $test->expect('{"id":2,"name":"article","icon":null}');
  196. }
  197. public function testEditCategoryWithBinaryContentWithPost()
  198. {
  199. $binary = base64_encode("€ \0abc\0\n\r\b\0");
  200. $base64url = rtrim(strtr($binary, '+/', '-_'), '=');
  201. $test = new Api($this);
  202. $test->put('/categories/2', 'icon=' . $base64url);
  203. $test->expect('1');
  204. $test->get('/categories/2');
  205. $test->expect('{"id":2,"name":"article","icon":"' . $binary . '"}');
  206. }
  207. public function testListCategoriesWithBinaryContent()
  208. {
  209. $test = new Api($this);
  210. $test->get('/categories');
  211. $test->expect('{"categories":{"columns":["id","name","icon"],"records":[[1,"announcement",null],[2,"article","4oKsIABhYmMACg1cYgA="]]}}');
  212. }
  213. public function testEditCategoryWithNullWithPost()
  214. {
  215. $test = new Api($this);
  216. $test->put('/categories/2', 'icon__is_null');
  217. $test->expect('1');
  218. $test->get('/categories/2');
  219. $test->expect('{"id":2,"name":"article","icon":null}');
  220. }
  221. public function testAddPostFailure()
  222. {
  223. $test = new Api($this);
  224. $test->post('/posts', '{"user_id":"a","category_id":1,"content":"tests"}');
  225. $test->expect('null');
  226. }
  227. public function testOptionsRequest()
  228. {
  229. $test = new Api($this);
  230. $test->options('/posts/2');
  231. $test->expect('["Access-Control-Allow-Headers: Content-Type, X-XSRF-TOKEN","Access-Control-Allow-Methods: OPTIONS, GET, PUT, POST, DELETE, PATCH","Access-Control-Allow-Credentials: true","Access-Control-Max-Age: 1728000"]', false);
  232. }
  233. public function testHidingPasswordColumn()
  234. {
  235. $test = new Api($this);
  236. $test->get('/users?filter=id,eq,1&transform=1');
  237. $test->expect('{"users":[{"id":1,"username":"user1","location":null}]}');
  238. }
  239. public function testValidatorErrorMessage()
  240. {
  241. $test = new Api($this);
  242. $test->put('/posts/1', '{"category_id":"a"}');
  243. $test->expect(false, '{"category_id":"must be numeric"}');
  244. }
  245. public function testSanitizerToStripTags()
  246. {
  247. $test = new Api($this);
  248. $test->put('/categories/2', '{"name":"<script>alert();</script>"}');
  249. $test->expect('1');
  250. $test->get('/categories/2');
  251. $test->expect('{"id":2,"name":"alert();","icon":null}');
  252. }
  253. public function testErrorOnInvalidJson()
  254. {
  255. $test = new Api($this);
  256. $test->post('/posts', '{"}');
  257. $test->expectPattern(false, '/^Bad request.*$/');
  258. }
  259. public function testErrorOnDuplicatePrimaryKey()
  260. {
  261. $test = new Api($this);
  262. $test->post('/posts', '{"id":1,"user_id":1,"category_id":1,"content":"blog started (duplicate)"}');
  263. $test->expect('null');
  264. }
  265. public function testErrorOnFailingForeignKeyConstraint()
  266. {
  267. $test = new Api($this);
  268. $test->post('/posts', '{"user_id":3,"category_id":1,"content":"fk constraint"}');
  269. $test->expect('null');
  270. }
  271. public function testMissingIntermediateTable()
  272. {
  273. $test = new Api($this);
  274. $test->get('/users?include=posts,tags');
  275. $test->expect('{"users":{"columns":["id","username","location"],"records":[[1,"user1",null]]},"posts":{"relations":{"user_id":"users.id"},"columns":["id","user_id","category_id","content"],"records":[[1,1,1,"blog started"],[2,1,2,"\u20ac Hello world, \u039a\u03b1\u03bb\u03b7\u03bc\u1f73\u03c1\u03b1 \u03ba\u1f79\u03c3\u03bc\u03b5, \u30b3\u30f3\u30cb\u30c1\u30cf"],[5,1,1,"#1"],[6,1,1,"#2"],[7,1,1,"#3"],[8,1,1,"#4"],[9,1,1,"#5"],[10,1,1,"#6"],[11,1,1,"#7"],[12,1,1,"#8"],[14,1,1,"#10"]]},"post_tags":{"relations":{"post_id":"posts.id"},"columns":["id","post_id","tag_id"],"records":[[1,1,1],[2,1,2],[3,2,1],[4,2,2]]},"tags":{"relations":{"id":"post_tags.tag_id"},"columns":["id","name"],"records":[[1,"funny"],[2,"important"]]}}');
  276. }
  277. public function testEditUserPassword()
  278. {
  279. $test = new Api($this);
  280. $test->put('/users/1', '{"password":"testtest"}');
  281. $test->expect('1');
  282. }
  283. public function testEditUserLocation()
  284. {
  285. $test = new Api($this);
  286. $test->put('/users/1', '{"location":"POINT(30 20)"}');
  287. $test->expect('1');
  288. $test->get('/users/1?columns=id,location');
  289. if ($this->getEngineName() == 'SQLServer') {
  290. $test->expect('{"id":1,"location":"POINT (30 20)"}');
  291. } else {
  292. $test->expect('{"id":1,"location":"POINT(30 20)"}');
  293. }
  294. }
  295. public function testListUserLocations()
  296. {
  297. $test = new Api($this);
  298. $test->get('/users?columns=id,location');
  299. if ($this->getEngineName() == 'SQLServer') {
  300. $test->expect('{"users":{"columns":["id","location"],"records":[[1,"POINT (30 20)"]]}}');
  301. } else {
  302. $test->expect('{"users":{"columns":["id","location"],"records":[[1,"POINT(30 20)"]]}}');
  303. }
  304. }
  305. public function testEditUserWithId()
  306. {
  307. if ($this->getEngineName() != 'SQLServer') {
  308. $test = new Api($this);
  309. $test->put('/users/1', '{"id":2,"password":"testtest2"}');
  310. $test->expect('1');
  311. $test->get('/users/1?columns=id,username,password');
  312. $test->expect('{"id":1,"username":"user1","password":"testtest2"}');
  313. }
  314. }
  315. public function testReadOtherUser()
  316. {
  317. $test = new Api($this);
  318. $test->get('/users/2');
  319. $test->expect(false, 'Not found (object)');
  320. }
  321. public function testEditOtherUser()
  322. {
  323. $test = new Api($this);
  324. $test->put('/users/2', '{"password":"testtest"}');
  325. $test->expect('0');
  326. }
  327. public function testFilterCategoryOnNullIcon()
  328. {
  329. $test = new Api($this);
  330. $test->get('/categories?filter[]=icon,is,null&transform=1');
  331. $test->expect('{"categories":[{"id":1,"name":"announcement","icon":null},{"id":2,"name":"alert();","icon":null}]}');
  332. }
  333. public function testFilterCategoryOnNotNullIcon()
  334. {
  335. $test = new Api($this);
  336. $test->get('/categories?filter[]=icon,nis,null&transform=1');
  337. $test->expect('{"categories":[]}');
  338. }
  339. public function testFilterPostsNotIn()
  340. {
  341. $test = new Api($this);
  342. $test->get('/posts?filter[]=id,nin,1,2,3,4,7,8,9,10,11,12,13,14&transform=1');
  343. $test->expect('{"posts":[{"id":5,"user_id":1,"category_id":1,"content":"#1"},{"id":6,"user_id":1,"category_id":1,"content":"#2"}]}');
  344. }
  345. public function testFilterCommentsStringIn()
  346. {
  347. $test = new Api($this);
  348. $test->get('/comments?filter=message,in,fantastic,thank you&transform=1');
  349. $test->expect('{"comments":[{"id":2,"post_id":1,"message":"fantastic"},{"id":3,"post_id":2,"message":"thank you"}]}');
  350. }
  351. public function testFilterPostsBetween()
  352. {
  353. $test = new Api($this);
  354. $test->get('/posts?filter[]=id,bt,5,6&transform=1');
  355. $test->expect('{"posts":[{"id":5,"user_id":1,"category_id":1,"content":"#1"},{"id":6,"user_id":1,"category_id":1,"content":"#2"}]}');
  356. }
  357. public function testFilterPostsNotBetween()
  358. {
  359. $test = new Api($this);
  360. $test->get('/posts?filter[]=id,nbt,2,13&transform=1');
  361. $test->expect('{"posts":[{"id":1,"user_id":1,"category_id":1,"content":"blog started"},{"id":14,"user_id":1,"category_id":1,"content":"#10"}]}');
  362. }
  363. public function testColumnsWithTable()
  364. {
  365. $test = new Api($this);
  366. $test->get('/posts?columns=posts.content&filter=id,eq,1&transform=1');
  367. $test->expect('{"posts":[{"content":"blog started"}]}');
  368. }
  369. public function testColumnsWithTableWildcard()
  370. {
  371. $test = new Api($this);
  372. $test->get('/posts?columns=posts.*&filter=id,eq,1&transform=1');
  373. $test->expect('{"posts":[{"id":1,"user_id":1,"category_id":1,"content":"blog started"}]}');
  374. }
  375. public function testColumnsOnInclude()
  376. {
  377. $test = new Api($this);
  378. $test->get('/posts?include=categories&columns=categories.name&filter=id,eq,1&transform=1');
  379. $test->expect('{"posts":[{"category_id":1,"categories":[{"id":1,"name":"announcement"}]}]}');
  380. }
  381. public function testFilterOnRelationAnd()
  382. {
  383. $test = new Api($this);
  384. $test->get('/categories?include=posts&filter[]=id,ge,1&filter[]=id,le,1&filter[]=id,le,2&filter[]=posts.id,lt,8&filter[]=posts.id,gt,4');
  385. $test->expect('{"categories":{"columns":["id","name","icon"],"records":[[1,"announcement",null]]},"posts":{"relations":{"category_id":"categories.id"},"columns":["id","user_id","category_id","content"],"records":[[5,1,1,"#1"],[6,1,1,"#2"],[7,1,1,"#3"]]}}');
  386. }
  387. public function testFilterOnRelationOr()
  388. {
  389. $test = new Api($this);
  390. $test->get('/categories?include=posts&filter[]=id,ge,1&filter[]=id,le,1&filter[]=posts.id,eq,5&filter[]=posts.id,eq,6&filter[]=posts.id,eq,7&satisfy=all,posts.any');
  391. $test->expect('{"categories":{"columns":["id","name","icon"],"records":[[1,"announcement",null]]},"posts":{"relations":{"category_id":"categories.id"},"columns":["id","user_id","category_id","content"],"records":[[5,1,1,"#1"],[6,1,1,"#2"],[7,1,1,"#3"]]}}');
  392. }
  393. public function testColumnsOnWrongInclude()
  394. {
  395. $test = new Api($this);
  396. $test->get('/posts?include=categories&columns=categories&filter=id,eq,1&transform=1');
  397. $test->expect('{"posts":[{"category_id":1,"categories":[{"id":1}]}]}');
  398. }
  399. public function testColumnsOnImplicitJoin()
  400. {
  401. $test = new Api($this);
  402. $test->get('/posts?include=tags&columns=posts.id,tags.name&filter=id,eq,1&transform=1');
  403. $test->expect('{"posts":[{"id":1,"post_tags":[{"post_id":1,"tag_id":1,"tags":[{"id":1,"name":"funny"}]},{"post_id":1,"tag_id":2,"tags":[{"id":2,"name":"important"}]}]}]}');
  404. }
  405. public function testSpatialFilterWithin()
  406. {
  407. if (static::$capabilities & self::GIS) {
  408. $test = new Api($this);
  409. $test->get('/users?columns=id,username&filter=location,swi,POINT(30 20)');
  410. $test->expect('{"users":{"columns":["id","username"],"records":[[1,"user1"]]}}');
  411. }
  412. }
  413. public function testAddPostsWithNonExistingCategory()
  414. {
  415. $test = new Api($this);
  416. $test->post('/posts', '[{"user_id":1,"category_id":1,"content":"tests"},{"user_id":1,"category_id":15,"content":"tests"}]');
  417. $test->expect('null');
  418. $test->get('/posts?columns=content&filter=content,eq,tests');
  419. $test->expect('{"posts":{"columns":["content"],"records":[]}}');
  420. }
  421. public function testAddPosts()
  422. {
  423. $test = new Api($this);
  424. $test->post('/posts', '[{"user_id":1,"category_id":1,"content":"tests"},{"user_id":1,"category_id":1,"content":"tests"}]');
  425. $test->expectAny();
  426. $test->get('/posts?columns=content&filter=content,eq,tests');
  427. $test->expect('{"posts":{"columns":["content"],"records":[["tests"],["tests"]]}}');
  428. }
  429. public function testListEvents()
  430. {
  431. $test = new Api($this);
  432. $test->get('/events?columns=datetime');
  433. $test->expect('{"events":{"columns":["datetime"],"records":[["2016-01-01 13:01:01"]]}}');
  434. }
  435. public function testIncrementEventVisitors()
  436. {
  437. $test = new Api($this);
  438. $test->patch('/events/1', '{"visitors":11}');
  439. $test->expect('1');
  440. $test->get('/events/1');
  441. $test->expect('{"id":1,"name":"Launch","datetime":"2016-01-01 13:01:01","visitors":11}');
  442. }
  443. public function testIncrementEventVisitorsWithZero()
  444. {
  445. $test = new Api($this);
  446. $test->patch('/events/1', '{"visitors":0}');
  447. $test->expect('1');
  448. $test->get('/events/1');
  449. $test->expect('{"id":1,"name":"Launch","datetime":"2016-01-01 13:01:01","visitors":11}');
  450. }
  451. public function testDecrementEventVisitors()
  452. {
  453. $test = new Api($this);
  454. $test->patch('/events/1', '{"visitors":-5}');
  455. $test->expect('1');
  456. $test->get('/events/1');
  457. $test->expect('{"id":1,"name":"Launch","datetime":"2016-01-01 13:01:01","visitors":6}');
  458. }
  459. public function testListTagUsage()
  460. {
  461. $test = new Api($this);
  462. $test->get('/tag_usage');
  463. $test->expect('{"tag_usage":{"columns":["name","count"],"records":[["funny",2],["important",2]]}}');
  464. }
  465. public function testUpdateMultipleTags()
  466. {
  467. $test = new Api($this);
  468. $test->get('/tags?transform=1');
  469. $test->expect('{"tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}');
  470. $test->put('/tags/1,2', '[{"name":"funny"},{"name":"important"}]');
  471. $test->expect('[1,1]');
  472. }
  473. public function testUpdateMultipleTagsTooManyIds()
  474. {
  475. $test = new Api($this);
  476. $test->put('/tags/1,2,3', '[{"name":"funny!!!"},{"name":"important"}]');
  477. $test->expect(false, 'Not found (subject)');
  478. $test->get('/tags?transform=1');
  479. $test->expect('{"tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}');
  480. }
  481. public function testUpdateMultipleTagsWithoutFields()
  482. {
  483. $test = new Api($this);
  484. $test->put('/tags/1,2', '[{"name":"funny!!!"},{}]');
  485. $test->expect('null');
  486. $test->get('/tags?transform=1');
  487. $test->expect('{"tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}');
  488. }
  489. public function testDeleteMultipleTags()
  490. {
  491. $test = new Api($this);
  492. $test->post('/tags', '[{"name":"extra"},{"name":"more"}]');
  493. $test->expect('[3,4]');
  494. $test->delete('/tags/3,4');
  495. $test->expect('[1,1]');
  496. $test->get('/tags?transform=1');
  497. $test->expect('{"tags":[{"id":1,"name":"funny"},{"id":2,"name":"important"}]}');
  498. }
  499. public function testListProducts()
  500. {
  501. $test = new Api($this);
  502. $test->get('/products?columns=id,name,price&transform=1');
  503. $test->expect('{"products":[{"id":1,"name":"Calculator","price":"23.01"}]}');
  504. }
  505. public function testListProductsProperties()
  506. {
  507. $test = new Api($this);
  508. $test->get('/products?columns=id,properties&transform=1');
  509. if (static::$capabilities & self::JSON) {
  510. $test->expect('{"products":[{"id":1,"properties":{"depth":false,"model":"TRX-120","width":100,"height":null}}]}');
  511. } else {
  512. $test->expect('{"products":[{"id":1,"properties":"{\"depth\":false,\"model\":\"TRX-120\",\"width\":100,\"height\":null}"}]}');
  513. }
  514. }
  515. public function testReadProductProperties()
  516. {
  517. $test = new Api($this);
  518. $test->get('/products/1?columns=id,properties');
  519. if (static::$capabilities & self::JSON) {
  520. $test->expect('{"id":1,"properties":{"depth":false,"model":"TRX-120","width":100,"height":null}}');
  521. } else {
  522. $test->expect('{"id":1,"properties":"{\"depth\":false,\"model\":\"TRX-120\",\"width\":100,\"height\":null}"}');
  523. }
  524. }
  525. public function testWriteProductProperties()
  526. {
  527. $test = new Api($this);
  528. if (static::$capabilities & self::JSON) {
  529. $test->put('/products/1', '{"properties":{"depth":false,"model":"TRX-120","width":100,"height":123}}');
  530. } else {
  531. $test->put('/products/1', '{"properties":"{\"depth\":false,\"model\":\"TRX-120\",\"width\":100,\"height\":123}"}');
  532. }
  533. $test->expect('1');
  534. $test->get('/products/1?columns=id,properties');
  535. if (static::$capabilities & self::JSON) {
  536. $test->expect('{"id":1,"properties":{"depth":false,"model":"TRX-120","width":100,"height":123}}');
  537. } else {
  538. $test->expect('{"id":1,"properties":"{\"depth\":false,\"model\":\"TRX-120\",\"width\":100,\"height\":123}"}');
  539. }
  540. }
  541. public function testAddProducts()
  542. {
  543. $test = new Api($this);
  544. if (static::$capabilities & self::JSON) {
  545. $test->post('/products', '{"name":"Laptop","price":"1299.99","properties":{}}');
  546. } else {
  547. $test->post('/products', '{"name":"Laptop","price":"1299.99","properties":"{}"}');
  548. }
  549. $test->expect('2');
  550. $test->get('/products/2?columns=id,created_at,deleted_at');
  551. $test->expect('{"id":2,"created_at":"2013-12-11 10:09:08","deleted_at":null}');
  552. }
  553. public function testSoftDeleteProducts()
  554. {
  555. $test = new Api($this);
  556. $test->delete('/products/1,2');
  557. $test->expect('[1,1]');
  558. $test->get('/products?columns=id,deleted_at');
  559. $test->expect('{"products":{"columns":["id","deleted_at"],"records":[[1,"2013-12-11 11:10:09"],[2,"2013-12-11 11:10:09"]]}}');
  560. }
  561. public function testVarBinaryBarcodes()
  562. {
  563. $test = new Api($this);
  564. $test->get('/barcodes?transform=1');
  565. $test->expect('{"barcodes":[{"id":1,"product_id":1,"hex":"00ff01","bin":"AP8B"}]}');
  566. }
  567. public function testEditPostWithApostrophe()
  568. {
  569. $test = new Api($this);
  570. $test->put('/posts/1', '[{"id":1,"user_id":1,"category_id":1,"content":"blog start\'d"}]');
  571. $test->expect('1');
  572. $test->get('/posts/1');
  573. $test->expect('{"id":1,"user_id":1,"category_id":1,"content":"blog start\'d"}');
  574. }
  575. public function testAddPostWithLeadingWhitespaceInJSON()
  576. {
  577. $test = new Api($this);
  578. $test->post('/posts', '
  579. {"user_id":1,"category_id":1,"content":"test whitespace"} ');
  580. $test->expect('21');
  581. $test->get('/posts/21');
  582. $test->expect('{"id":21,"user_id":1,"category_id":1,"content":"test whitespace"}');
  583. }
  584. public function testListPostWithIncludeButNoRecords()
  585. {
  586. $test = new Api($this);
  587. $test->get('/posts?filter=id,eq,999&include=tags');
  588. $test->expect('{"posts":{"columns":["id","user_id","category_id","content"],"records":[]},"post_tags":{"relations":{"post_id":"posts.id"},"columns":["id","post_id","tag_id"],"records":[]},"tags":{"relations":{"id":"post_tags.tag_id"},"columns":["id","name"],"records":[]}}');
  589. }
  590. public function testTenancyCreateColumns()
  591. {
  592. // creation should fail, since due to tenancy function it will try to create with id=1, which is a PK and is already taken
  593. $test = new Api($this);
  594. $test->post('/users?columns=username,password,location', '{"username":"user3","password":"pass3","location":null}');
  595. $test->expect('null');
  596. }
  597. public function testTenancyCreateExclude()
  598. {
  599. // creation should fail, since due to tenancy function it will try to create with id=1, which is a PK and is already taken
  600. $test = new Api($this);
  601. $test->post('/users?exclude=id', '{"username":"user3","password":"pass3","location":null}');
  602. $test->expect('null');
  603. }
  604. public function testTenancyListColumns()
  605. {
  606. // should list only user with id=1 (exactly 1 record)
  607. $test = new Api($this);
  608. $test->get('/users?columns=username,location');
  609. if ($this->getEngineName() == 'SQLServer') {
  610. $test->expect('{"users":{"columns":["username","location"],"records":[["user1","POINT (30 20)"]]}}');
  611. } else {
  612. $test->expect('{"users":{"columns":["username","location"],"records":[["user1","POINT(30 20)"]]}}');
  613. }
  614. }
  615. public function testTenancyListExclude()
  616. {
  617. // should list only user with id=1 (exactly 1 record)
  618. $test = new Api($this);
  619. $test->get('/users?exclude=id');
  620. if ($this->getEngineName() == 'SQLServer') {
  621. $test->expect('{"users":{"columns":["username","location"],"records":[["user1","POINT (30 20)"]]}}');
  622. } else {
  623. $test->expect('{"users":{"columns":["username","location"],"records":[["user1","POINT(30 20)"]]}}');
  624. }
  625. }
  626. public function testTenancyReadColumns()
  627. {
  628. // should fail, since due to tenancy function user id=2 is unvailable to us
  629. $test = new Api($this);
  630. $test->get('/users/2?columns=username,location');
  631. $test->expect(false, 'Not found (object)');
  632. }
  633. public function testTenancyReadExclude()
  634. {
  635. // should fail, since due to tenancy function user id=2 is unvailable to us
  636. $test = new Api($this);
  637. $test->get('/users/2?exclude=id');
  638. $test->expect(false, 'Not found (object)');
  639. }
  640. public function testTenancyUpdateColumns()
  641. {
  642. // should fail, since due to tenancy function user id=2 is unvailable to us
  643. $test = new Api($this);
  644. $test->put('/users/2?columns=location', '{"location":"somelocation"}');
  645. $test->expect('0');
  646. }
  647. public function testTenancyUpdateExclude()
  648. {
  649. // should fail, since due to tenancy function user id=2 is unvailable to us
  650. $test = new Api($this);
  651. $test->put('/users/2?exclude=id', '{"location":"somelocation"}');
  652. $test->expect('0');
  653. }
  654. public function testTenancyDeleteColumns()
  655. {
  656. // should fail, since due to tenancy function user id=2 is unvailable to us
  657. $test = new Api($this);
  658. $test->delete('/users/2?columns=location');
  659. $test->expect('0');
  660. }
  661. public function testTenancyDeleteExclude()
  662. {
  663. // should fail, since due to tenancy function user id=2 is unvailable to us
  664. $test = new Api($this);
  665. $test->delete('/users/2?exclude=id');
  666. $test->expect('0');
  667. }
  668. }