user = $userRepo->create(new CreateUserDto( email: new EmailAddress('a@b.com'), passwordHash: '', isAdmin: false, )); $this->otherUser = $userRepo->create(new CreateUserDto( email: new EmailAddress('other@b.com'), passwordHash: '', isAdmin: false, )); $this->admin = $userRepo->create(new CreateUserDto( email: new EmailAddress('admin@b.com'), passwordHash: '', isAdmin: true, )); $this->textRepo = new FakeTextRepository(); $this->textRepo->create(new CreateTextDto( name: 'test text', user: $this->user, )); $this->nodeRepo = new FakeNodeRepository(); $this->controller = new NodeController( $this->nodeRepo, $this->textRepo, ); } private function makeRequest( array $body, ?User $user, ): ServerRequestInterface { $stream = new StreamFactory()->createStream(json_encode($body)); $request = new ServerRequestFactory() ->createServerRequest('POST', 'http://localhost/api/nodes') ->withHeader('Content-Type', 'application/json') ->withBody($stream); if ($user !== null) { $request = $request->withAttribute('user', $user); } return $request; } private function makeGetRequest(?User $user): ServerRequestInterface { $request = new ServerRequestFactory() ->createServerRequest('GET', 'http://localhost/api/nodes/0'); if ($user !== null) { $request = $request->withAttribute('user', $user); } return $request; } public function test_get_nodes_of_text_returns_flat_array(): void { $text = $this->textRepo->find(0); $this->nodeRepo->create(new CreateNodeDto( text: $text, title: 'Root Node', parentNode: null, )); $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->user), new Response(), 0, ); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals( json_encode([ ['id' => 0, 'title' => 'Root Node', 'parentNodeId' => null], ]), $response->getBody(), ); } public function test_get_nodes_of_text_returns_empty_array_when_no_nodes(): void { $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->user), new Response(), 0, ); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(json_encode([]), $response->getBody()); } public function test_get_nodes_of_text_returns_404_for_unknown_text(): void { $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->user), new Response(), 99, ); $this->assertEquals(404, $response->getStatusCode()); } public function test_get_nodes_of_text_returns_403_when_not_owner(): void { $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->otherUser), new Response(), 0, ); $this->assertEquals(403, $response->getStatusCode()); } public function test_get_nodes_of_text_allows_admin(): void { $text = $this->textRepo->find(0); $this->nodeRepo->create(new CreateNodeDto( text: $text, title: 'Root Node', parentNode: null, )); $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->admin), new Response(), 0, ); $this->assertEquals(200, $response->getStatusCode()); } public function test_get_nodes_includes_parent_node_id(): void { $text = $this->textRepo->find(0); $rootNode = $this->nodeRepo->create(new CreateNodeDto( text: $text, title: 'Root Node', parentNode: null, )); $this->nodeRepo->create(new CreateNodeDto( text: $text, title: 'Child Node', parentNode: $rootNode, )); $response = $this->controller->getNodesOfText( $this->makeGetRequest($this->user), new Response(), 0, ); $body = json_decode($response->getBody(), true); $this->assertEquals(0, $body[1]['parentNodeId']); } public function test_create_node_returns_created_node(): void { $text = $this->textRepo->find(0); $rootNode = $this->nodeRepo->create(new CreateNodeDto( text: $text, title: 'Root Node', parentNode: null, )); $request = $this->makeRequest( [ 'textId' => 0, 'title' => 'Child Node', 'parentNodeId' => $rootNode->getId(), ], $this->user, ); $response = $this->controller->createNode( $request, new Response(), new CreateNode($this->nodeRepo, $this->textRepo), ); $this->assertEquals(201, $response->getStatusCode()); $body = json_decode($response->getBody(), true); $this->assertEquals('Child Node', $body['title']); $this->assertEquals($rootNode->getId(), $body['parentNodeId']); $this->assertArrayHasKey('id', $body); } public function test_create_node_returns_400_when_title_missing(): void { $request = $this->makeRequest( [ 'textId' => 0, 'parentNodeId' => null, ], $this->user, ); $response = $this->controller->createNode( $request, new Response(), new CreateNode($this->nodeRepo, $this->textRepo), ); $this->assertEquals(400, $response->getStatusCode()); } public function test_create_node_returns_404_when_text_not_found(): void { $request = $this->makeRequest( [ 'textId' => 99, 'title' => 'Some Node', 'parentNodeId' => null, ], $this->user, ); $response = $this->controller->createNode( $request, new Response(), new CreateNode($this->nodeRepo, $this->textRepo), ); $this->assertEquals(404, $response->getStatusCode()); } public function test_create_node_returns_403_when_not_owner(): void { $request = $this->makeRequest( [ 'textId' => 0, 'title' => 'Hijack', 'parentNodeId' => null, ], $this->otherUser, ); $response = $this->controller->createNode( $request, new Response(), new CreateNode($this->nodeRepo, $this->textRepo), ); $this->assertEquals(403, $response->getStatusCode()); } public function test_create_node_allows_admin_on_any_text(): void { $request = $this->makeRequest( [ 'textId' => 0, 'title' => 'Admin Root', 'parentNodeId' => null, ], $this->admin, ); $response = $this->controller->createNode( $request, new Response(), new CreateNode($this->nodeRepo, $this->textRepo), ); $this->assertEquals(201, $response->getStatusCode()); } }