PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Bundle/LichessBundle/Tests/Controller/PlayerWithOpponentControllerTest.php

http://github.com/ornicar/lichess
PHP | 332 lines | 261 code | 54 blank | 17 comment | 0 complexity | 1ee922d4953788c191d87c1cc18d118c MD5 | raw file
  1. <?php
  2. namespace Bundle\LichessBundle\Tests\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
  4. use Bundle\LichessBundle\Document\Game;
  5. class PlayerWithOpponentControllerTest extends WebTestCase
  6. {
  7. protected function createGameWithFriend($color = 'white', array $formConfig = array())
  8. {
  9. $p1 = self::createClient();
  10. $crawler = $p1->request('GET', '/start/friend');
  11. $url = $crawler->filter('div.game_config_form form')->attr('action');
  12. $p1->request('POST', $url, array('config' => array_merge(array(
  13. 'color' => $color,
  14. 'variant' => Game::VARIANT_STANDARD
  15. ), $formConfig)));
  16. $crawler = $p1->followRedirect();
  17. $this->assertTrue($p1->getResponse()->isSuccessful());
  18. $selector = 'div.lichess_game_not_started.waiting_opponent div.lichess_overboard input';
  19. $inviteUrl = $crawler->filter($selector)->attr('value');
  20. $h1 = preg_replace('#^.+([\w-]{12}+)$#', '$1', $p1->getRequest()->getUri());
  21. $p2 = self::createClient();
  22. $crawler = $p2->request('GET', $inviteUrl);
  23. $redirectUrl = $crawler->filter('a.join_redirect_url')->attr('href');
  24. $p2->request('GET', $redirectUrl);
  25. $crawler = $p2->followRedirect();
  26. $this->assertTrue($p2->getResponse()->isSuccessful());
  27. $h2 = preg_replace('#^.+([\w-]{12}+)$#', '$1', $p2->getRequest()->getUri());
  28. return array($p1, $h1, $p2, $h2);
  29. }
  30. public function testAbort()
  31. {
  32. list($p1, $h1, $p2, $h2) = $this->createGameWithFriend();
  33. $p1->request('GET', '/abort/'.$h1);
  34. $this->assertTrue($p1->getResponse()->isRedirect());
  35. $crawler = $p1->followRedirect();
  36. $this->assertTrue($p1->getResponse()->isSuccessful());
  37. $this->assertEquals(1, $crawler->filter('div.lichess_current_player p:contains("Game aborted")')->count());
  38. }
  39. public function testRematchFullProcess()
  40. {
  41. list($p1, $h1, $p2, $h2) = $this->createGameWithFriend();
  42. $p1->request('GET', '/abort/'.$h1);
  43. $crawler = $p1->followRedirect();
  44. $p1->request('POST', $crawler->selectLink('Rematch')->attr('href'));
  45. $this->assertTrue($p1->getResponse()->isSuccessful());
  46. $this->assertEquals('ok', $p1->getResponse()->getContent());
  47. $p1->request('POST', $this->getSyncUrl($h1));
  48. $response = json_decode($p1->getResponse()->getContent(), true);
  49. $this->assertEquals('redirect', $response['e'][2]['type']);
  50. $crawler = $p1->request('GET', '/'.$h1);
  51. $this->assertEquals(0, $crawler->selectLink('Rematch')->count());
  52. $this->assertRegexp('/Rematch offer sent/', $p1->getResponse()->getContent());
  53. $crawler = $p2->reload();
  54. $link = $crawler->selectLink('Join the game');
  55. $this->assertEquals(1, $link->count());
  56. $p2->request('POST', $link->attr('href'));
  57. $this->assertTrue($p2->getResponse()->isSuccessful());
  58. $this->assertEquals('ok', $p2->getResponse()->getContent());
  59. $p2->request('POST', $this->getSyncUrl($h2));
  60. $response = json_decode($p2->getResponse()->getContent(), true);
  61. $lastEvent = array_pop($response['e']);
  62. $this->assertEquals('redirect', $lastEvent['type']);
  63. $url = $lastEvent['url'];
  64. $this->assertRegexp('#/\w{12}#', $url);
  65. $p2->request('GET', $url);
  66. $this->assertTrue($p2->getResponse()->isSuccessful());
  67. }
  68. public function testRematch960KeepsInitialPositionFriend()
  69. {
  70. list($p1, $h1, $p2, $h2) = $this->createGameWithFriend('white', array('variant' => 2));
  71. $this->rematch960KeepsInitialPosition($p1, $h1, $p2, $h2);
  72. }
  73. protected function rematch960KeepsInitialPosition($p1, $h1, $p2, $h2)
  74. {
  75. $squares = array('a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1');
  76. $crawler = $p1->request('GET', '/'.$h1);
  77. $getPieceOn = function($square) use ($crawler) {
  78. return trim(preg_replace('(white|black|lichess_piece) ', '', $crawler->filter('#'.$square.' .lichess_piece')->attr('class')));
  79. };
  80. $pieces = array_map(function ($square) use ($getPieceOn) { return $getPieceOn($square); }, $squares);
  81. $p1->request('GET', '/abort/'.$h1);
  82. $p1->request('POST', '/rematch/'.$h1);
  83. $p2->request('POST', '/rematch/'.$h2);
  84. $this->assertEquals('ok', $p2->getResponse()->getContent());
  85. $p2->request('POST', $this->getSyncUrl($h2));
  86. $response = json_decode($p2->getResponse()->getContent(), true);
  87. $lastEvent = array_pop($response['e']);
  88. $url = $lastEvent['url'];
  89. $crawler = $p2->request('GET', $url);
  90. foreach ($squares as $it => $square) {
  91. $this->assertEquals($pieces[$it], $getPieceOn($square));
  92. }
  93. }
  94. public function testClaimDrawWithoutThreefold()
  95. {
  96. list($p1, $h1, $p2, $h2) = $this->createGameWithFriend();
  97. $p1->request('GET', '/claim-draw/'.$h1);
  98. $this->assertTrue($p1->getResponse()->isRedirect());
  99. $crawler = $p1->followRedirect();
  100. $this->assertTrue($p1->getResponse()->isSuccessful());
  101. $this->assertEquals(1, $crawler->filter('div.lichess_current_player p:contains("Your turn")')->count());
  102. }
  103. public function testClaimDrawWithThreefold()
  104. {
  105. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend();
  106. $this->applyMoves($data, array(
  107. 'b1 c3',
  108. 'b8 c6',
  109. 'c3 b1',
  110. 'c6 b8',
  111. 'b1 c3',
  112. 'b8 c6',
  113. 'c3 b1',
  114. 'c6 b8',
  115. 'b1 c3',
  116. 'b8 c6',
  117. 'c3 b1',
  118. 'c6 b8',
  119. ));
  120. $p1->request('GET', '/claim-draw/'.$h1);
  121. $this->assertTrue($p1->getResponse()->isRedirect());
  122. $crawler = $p1->followRedirect();
  123. $this->assertTrue($p1->getResponse()->isSuccessful());
  124. $this->assertEquals(1, $crawler->filter('div.lichess_current_player p:contains("Draw")')->count());
  125. }
  126. public function testClaimDrawWithThreefoldBadPlayer()
  127. {
  128. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend();
  129. $this->applyMoves($data, array(
  130. 'b1 c3',
  131. 'b8 c6',
  132. 'c3 b1',
  133. 'c6 b8',
  134. 'b1 c3',
  135. 'b8 c6',
  136. 'c3 b1',
  137. 'c6 b8',
  138. 'b1 c3',
  139. 'b8 c6',
  140. 'c3 b1',
  141. 'c6 b8',
  142. ));
  143. $p2->request('GET', '/claim-draw/'.$h2);
  144. $this->assertTrue($p2->getResponse()->isRedirect());
  145. $crawler = $p2->followRedirect();
  146. $this->assertTrue($p2->getResponse()->isSuccessful());
  147. $this->assertEquals(0, $crawler->filter('div.lichess_current_player p:contains("Draw")')->count());
  148. }
  149. public function testDrawOfferTooEarly()
  150. {
  151. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend();
  152. $p1->request('GET', '/offer-draw/'.$h1);
  153. $this->assertFalse($p1->getResponse()->isSuccessful());
  154. }
  155. public function testDrawOffer()
  156. {
  157. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend();
  158. $this->applyMoves($data, array('b1 c3', 'b8 c6'));
  159. $crawler = $p1->request('GET', '/'.$h1);
  160. $p1->click($crawler->selectLink('Offer draw')->link());
  161. $this->assertTrue($p1->getResponse()->isRedirect());
  162. $crawler = $p1->followRedirect();
  163. $this->assertTrue($p1->getResponse()->isSuccessful());
  164. $this->assertEquals('Cancel', $crawler->filter('div.offered_draw a')->text());
  165. return $data;
  166. }
  167. /**
  168. * @depends testDrawOffer
  169. */
  170. public function testDrawCancel(array $data)
  171. {
  172. list($p1, $h1, $p2, $h2) = $data;
  173. $p1->request('GET', '/cancel-draw-offer/'.$h1);
  174. $this->assertTrue($p1->getResponse()->isRedirect());
  175. $crawler = $p1->followRedirect();
  176. $this->assertTrue($p1->getResponse()->isSuccessful());
  177. $this->assertEquals(0, $crawler->filter('div.offered_draw a')->count());
  178. // Can no more accept draw this turn
  179. $this->assertEquals(0, $crawler->filter('a.offer_draw')->count());
  180. // Do some move do be allowed to offer a draw
  181. $this->applyMoves($data, array('a2 a4', 'a7 a5'));
  182. $crawler = $p1->request('GET', '/'.$h1);
  183. $this->assertEquals(1, $crawler->filter('a.offer_draw')->count());
  184. return $data;
  185. }
  186. /**
  187. * @depends testDrawCancel
  188. */
  189. public function testDrawDecline(array $data)
  190. {
  191. list($p1, $h1, $p2, $h2) = $data;
  192. $p1->request('GET', '/offer-draw/'.$h1);
  193. $this->assertTrue($p1->getResponse()->isRedirect());
  194. $crawler = $p1->followRedirect();
  195. $this->assertTrue($p1->getResponse()->isSuccessful());
  196. $this->assertEquals('Cancel', $crawler->filter('.offered_draw a')->text());
  197. $crawler = $p2->request('GET', '/'.$h2);
  198. // p2 sees the draw offer
  199. $this->assertRegexp('/Your opponent offers a draw/', $p2->getResponse()->getContent());
  200. $this->assertEquals(1, $crawler->filter('.offered_draw')->count());
  201. $this->assertEquals(2, $crawler->filter('.offered_draw a')->count());
  202. // p2 declines the draw
  203. $p2->click($crawler->selectLink('Decline')->link());
  204. $this->assertTrue($p2->getResponse()->isRedirect());
  205. $crawler = $p2->followRedirect();
  206. $this->assertTrue($p2->getResponse()->isSuccessful());
  207. $this->assertEquals(0, $crawler->filter('.offered_draw')->count());
  208. // p1 reloads and no more sees his draw offer
  209. $crawler = $p1->request('GET', '/'.$h1);
  210. $this->assertEquals(0, $crawler->filter('.offered_draw')->count());
  211. return $data;
  212. }
  213. /**
  214. * @depends testDrawDecline
  215. */
  216. public function testDrawAccept(array $data)
  217. {
  218. list($p1, $h1, $p2, $h2) = $data;
  219. $p2->request('GET', '/offer-draw/'.$h2);
  220. $this->assertTrue($p2->getResponse()->isRedirect());
  221. $crawler = $p2->followRedirect();
  222. $this->assertTrue($p2->getResponse()->isSuccessful());
  223. $this->assertEquals('Cancel', $crawler->filter('.offered_draw a')->text());
  224. $crawler = $p1->request('GET', '/'.$h1);
  225. // p1 sees the draw offer
  226. $this->assertRegexp('/Your opponent offers a draw/', $p1->getResponse()->getContent());
  227. $this->assertEquals(1, $crawler->filter('.offered_draw')->count());
  228. $this->assertEquals(2, $crawler->filter('.offered_draw a')->count());
  229. // p1 accepts the draw
  230. $p1->click($crawler->selectLink('Accept')->link());
  231. $this->assertTrue($p1->getResponse()->isRedirect());
  232. $crawler = $p1->followRedirect();
  233. $this->assertTrue($p1->getResponse()->isSuccessful());
  234. $this->assertEquals(0, $crawler->filter('.offered_draw')->count());
  235. // p2 reloads and no more sees his draw offer
  236. $crawler = $p2->request('GET', '/'.$h2);
  237. $this->assertEquals(0, $crawler->filter('.offered_draw')->count());
  238. }
  239. public function testOutoftimeNoClock()
  240. {
  241. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend('white', array('time' => 0));
  242. $p1->request('POST', '/outoftime/'.$h1.'/1');
  243. $this->assertFalse($p1->getResponse()->isSuccessful());
  244. }
  245. public function testOutOfTimeTooEarly()
  246. {
  247. list($p1, $h1, $p2, $h2) = $data = $this->createGameWithFriend('white', array('time' => 10));
  248. $p1->request('POST', '/outoftime/'.$h1.'/1');
  249. $this->assertFalse($p1->getResponse()->isSuccessful());
  250. $crawler = $p1->request('GET', '/'.$h1);
  251. $this->assertTrue($p1->getResponse()->isSuccessful());
  252. $this->assertRegexp('/Your turn/', $crawler->filter('.lichess_player')->text());
  253. }
  254. protected function applyMoves(array $data, array $moves)
  255. {
  256. list($p1, $h1, $p2, $h2) = $data;
  257. foreach($moves as $it => $move) {
  258. list($from, $to) = explode(' ', $move);
  259. $player = $it%2 ? $p2 : $p1;
  260. $id = $it%2 ? $h2 : $h1;
  261. $moveUrl = '/move/'.$id;
  262. $player->request('POST', $moveUrl, array('from' => $from, 'to' => $to));
  263. $this->assertTrue($player->getResponse()->isSuccessful());
  264. }
  265. }
  266. protected function getSyncUrl($id)
  267. {
  268. $client = self::createClient();
  269. $client->request('GET', $id);
  270. return str_replace(array('\\', '9999999'), array('', '0'), preg_replace('#.+"sync":"([^"]+)".+#s', '$1', $client->getResponse()->getContent()));
  271. }
  272. protected function getMoveUrl($id)
  273. {
  274. $client = self::createClient();
  275. $client->request('GET', $id);
  276. return str_replace(array('\\', '9999999'), array('', '0'), preg_replace('#.+"move":"([^"]+)".+#s', '$1', $client->getResponse()->getContent()));
  277. }
  278. }