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
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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. }