diff --git a/src/Api/Jobs/AddCommentJob.php b/src/Api/Jobs/AddCommentJob.php index 52a49c62..4d995804 100644 --- a/src/Api/Jobs/AddCommentJob.php +++ b/src/Api/Jobs/AddCommentJob.php @@ -28,7 +28,7 @@ class AddCommentJob extends AbstractJob public function requiresAuthentication() { - return true; + return false; } public function requiresConfirmedEmail() diff --git a/src/Models/Entities/AbstractEntity.php b/src/Models/Entities/AbstractEntity.php index cf497596..c4cc469b 100644 --- a/src/Models/Entities/AbstractEntity.php +++ b/src/Models/Entities/AbstractEntity.php @@ -2,7 +2,12 @@ abstract class AbstractEntity implements IValidatable { public $id; - protected $__cache; + protected $__cache = []; + + public function resetCache() + { + $this->__cache = []; + } public function setCache($key, $value) { diff --git a/tests/AbstractTest.php b/tests/AbstractTest.php index 80e58676..043b1c31 100644 --- a/tests/AbstractTest.php +++ b/tests/AbstractTest.php @@ -7,4 +7,35 @@ class AbstractTest { $this->assert = new Assert(); } + + protected function mockUser() + { + $user = UserModel::spawn(); + $user->setAccessRank(new AccessRank(AccessRank::Registered)); + $user->setName('dummy'); + $user->passHash = UserModel::hashPassword('ble', $user->passSalt); + return UserModel::save($user); + } + + protected function mockPost() + { + $post = PostModel::spawn(); + $post->setType(new PostType(PostType::Image)); + return PostModel::save($post); + } + + protected function login($user) + { + Auth::setCurrentUser($user); + } + + protected function mockComment($owner) + { + $post = $this->mockPost(); + $comment = CommentModel::spawn(); + $comment->setPost($post); + $comment->setCommenter($owner); + $comment->text = 'test test'; + return CommentModel::save($comment); + } } diff --git a/tests/CommentAddTest.php b/tests/CommentAddTest.php new file mode 100644 index 00000000..d592e479 --- /dev/null +++ b/tests/CommentAddTest.php @@ -0,0 +1,157 @@ +prepare(); + + $text = 'alohaaaaaaa'; + $comment = $this->assert->doesNotThrow(function() use ($text) + { + return $this->runApi($text); + }); + + $this->assert->areEqual(1, CommentModel::getCount()); + $this->assert->areEqual($text, $comment->text); + $this->assert->areEqual(Auth::getCurrentUser()->id, $comment->getCommenter()->id); + $this->assert->areEqual(1, $comment->getPost()->id); + $this->assert->isNotNull($comment->commentDate); + $this->assert->doesNotThrow(function() use ($comment) + { + UserModel::findById($comment->id); + }); + } + + public function testAlmostTooShortText() + { + $this->prepare(); + $this->assert->doesNotThrow(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->minLength)); + }); + } + + public function testAlmostTooLongText() + { + $this->prepare(); + $this->assert->doesNotThrow(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->maxLength)); + }); + } + + public function testTooShortText() + { + $this->prepare(); + $this->assert->throws(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->minLength - 1)); + }, 'Comment must have at least'); + } + + public function testTooLongText() + { + $this->prepare(); + $this->assert->throws(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->maxLength + 1)); + }, 'Comment must have at most'); + } + + public function testNoAuth() + { + $this->prepare(); + Auth::setCurrentUser(null); + + $this->assert->throws(function() + { + $this->assert->isFalse(Auth::isLoggedIn()); + return $this->runApi('alohaaaaaaa'); + }, 'Insufficient privileges'); + } + + public function testAccessDenial() + { + $this->prepare(); + + getConfig()->privileges->addComment = 'nobody'; + Access::init(); + $this->assert->isFalse(Access::check(new Privilege(Privilege::AddComment))); + + $this->assert->throws(function() + { + return $this->runApi('alohaaaaaaa'); + }, 'Insufficient privileges'); + } + + public function testAnonymous() + { + $this->prepare(); + + Auth::setCurrentUser(null); + getConfig()->privileges->addComment = 'anonymous'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::AddComment))); + + $text = 'alohaaaaaaa'; + $comment = $this->assert->doesNotThrow(function() use ($text) + { + return $this->runApi($text); + }); + + $this->assert->areEqual($text, $comment->text); + $this->assert->areEqual(Auth::getCurrentUser()->id, $comment->getCommenter()->id); + $this->assert->areEqual(UserModel::getAnonymousName(), $comment->getCommenter()->getName()); + } + + public function testPrivilegeDependancies() + { + $this->prepare(); + + getConfig()->privileges->{'editComment'} = 'nobody'; + getConfig()->privileges->{'editComment.own'} = 'nobody'; + getConfig()->privileges->{'editComment.all'} = 'nobody'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::AddComment))); + $this->assert->isFalse(Access::check(new Privilege(Privilege::EditComment))); + + $this->assert->doesNotThrow(function() + { + return $this->runApi('alohaaaaaaa'); + }, 'insufficient privileges'); + } + + public function testWrongPostId() + { + $this->prepare(); + $this->assert->throws(function() + { + return Api::run( + new AddCommentJob(), + [ + AddCommentJob::POST_ID => 100, + AddCommentJob::TEXT => 'alohaa', + ]); + }, 'Invalid post ID'); + } + + + protected function runApi($text) + { + $post = $this->mockPost(); + + return Api::run( + new AddCommentJob(), + [ + AddCommentJob::POST_ID => $post->id, + AddCommentJob::TEXT => $text, + ]); + } + + protected function prepare() + { + $this->login($this->mockUser()); + } +} diff --git a/tests/CommentDeleteTest.php b/tests/CommentDeleteTest.php new file mode 100644 index 00000000..1c07ea2c --- /dev/null +++ b/tests/CommentDeleteTest.php @@ -0,0 +1,110 @@ +prepare(); + + $this->assert->doesNotThrow(function() + { + return $this->runApi(); + }); + + $this->assert->areEqual(0, CommentModel::getCount()); + } + + public function testNoAuth() + { + $this->prepare(); + Auth::setCurrentUser(null); + + $this->assert->throws(function() + { + $this->assert->isFalse(Auth::isLoggedIn()); + return $this->runApi(); + }, 'Not logged in'); + } + + public function testOwnAccessDenial() + { + $this->prepare(); + + getConfig()->privileges->{'deleteComment.own'} = 'nobody'; + Access::init(); + $this->assert->isFalse(Access::check(new Privilege(Privilege::DeleteComment))); + + $this->assert->throws(function() + { + return $this->runApi(); + }, 'Insufficient privileges'); + } + + public function testOtherAccessGrant() + { + $this->prepare(); + + getConfig()->privileges->{'deleteComment.all'} = 'nobody'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::DeleteComment))); + + $this->assert->doesNotThrow(function() + { + return $this->runApi(); + }); + } + + public function testOtherAccessDenial() + { + $this->prepare(); + + $comment = $this->mockComment(Auth::getCurrentUser()); + + //login as someone else + $this->login($this->mockUser()); + + getConfig()->privileges->{'deleteComment.all'} = 'nobody'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::DeleteComment))); + $this->assert->isTrue(Access::check(new Privilege(Privilege::DeleteComment, 'own'))); + $this->assert->isFalse(Access::check(new Privilege(Privilege::DeleteComment, 'all'))); + + $this->assert->throws(function() use ($comment) + { + Api::run( + new DeleteCommentJob(), + [ + DeleteCommentJob::COMMENT_ID => $comment->id, + ]); + }, 'Insufficient privileges'); + } + + public function testWrongCommentId() + { + $this->prepare(); + $this->assert->throws(function() + { + return Api::run( + new DeleteCommentJob(), + [ + DeleteCommentJob::COMMENT_ID => 100, + ]); + }, 'Invalid comment ID'); + } + + + protected function runApi() + { + $comment = $this->mockComment(Auth::getCurrentUser()); + + return Api::run( + new DeleteCommentJob(), + [ + DeleteCommentJob::COMMENT_ID => $comment->id, + ]); + } + + protected function prepare() + { + $this->login($this->mockUser()); + } +} diff --git a/tests/CommentEditTest.php b/tests/CommentEditTest.php new file mode 100644 index 00000000..cc051fc0 --- /dev/null +++ b/tests/CommentEditTest.php @@ -0,0 +1,157 @@ +prepare(); + + $text = 'alohaaaaaaa'; + $comment = $this->assert->doesNotThrow(function() use ($text) + { + return $this->runApi($text); + }); + + $this->assert->areEqual($text, $comment->text); + $this->assert->areEqual(Auth::getCurrentUser()->id, $comment->getCommenter()->id); + $this->assert->areEqual(1, $comment->getPost()->id); + $this->assert->isNotNull($comment->commentDate); + $this->assert->doesNotThrow(function() use ($comment) + { + UserModel::findById($comment->id); + }); + } + + public function testOwnAlmostTooShortText() + { + $this->prepare(); + $this->assert->doesNotThrow(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->minLength)); + }); + } + + public function testOwnAlmostTooLongText() + { + $this->prepare(); + $this->assert->doesNotThrow(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->maxLength)); + }); + } + + public function testOwnTooShortText() + { + $this->prepare(); + $this->assert->throws(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->minLength - 1)); + }, 'Comment must have at least'); + } + + public function testOwnTooLongText() + { + $this->prepare(); + $this->assert->throws(function() + { + return $this->runApi(str_repeat('b', getConfig()->comments->maxLength + 1)); + }, 'Comment must have at most'); + } + + public function testNoAuth() + { + $this->prepare(); + Auth::setCurrentUser(null); + + $this->assert->throws(function() + { + $this->assert->isFalse(Auth::isLoggedIn()); + return $this->runApi('alohaaaaaaa'); + }, 'Not logged in'); + } + + public function testOwnAccessDenial() + { + $this->prepare(); + + getConfig()->privileges->{'editComment.own'} = 'nobody'; + Access::init(); + $this->assert->isFalse(Access::check(new Privilege(Privilege::EditComment))); + + $this->assert->throws(function() + { + return $this->runApi('alohaaaaaaa'); + }, 'Insufficient privileges'); + } + + public function testOtherAccessGrant() + { + $this->prepare(); + + getConfig()->privileges->{'editComment.all'} = 'nobody'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::EditComment))); + + $this->assert->doesNotThrow(function() + { + return $this->runApi('alohaaaaaaa'); + }); + } + + public function testOtherAccessDenial() + { + $this->prepare(); + + $comment = $this->mockComment(Auth::getCurrentUser()); + + //login as someone else + $this->login($this->mockUser()); + + getConfig()->privileges->{'editComment.all'} = 'nobody'; + Access::init(); + $this->assert->isTrue(Access::check(new Privilege(Privilege::EditComment))); + $this->assert->isTrue(Access::check(new Privilege(Privilege::EditComment, 'own'))); + $this->assert->isFalse(Access::check(new Privilege(Privilege::EditComment, 'all'))); + + $this->assert->throws(function() use ($comment) + { + Api::run( + new EditCommentJob(), + [ + EditCommentJob::COMMENT_ID => $comment->id, + EditCommentJob::TEXT => 'alohaa', + ]); + }, 'Insufficient privileges'); + } + + public function testWrongCommentId() + { + $this->prepare(); + $this->assert->throws(function() + { + return Api::run( + new EditCommentJob(), + [ + EditCommentJob::COMMENT_ID => 100, + EditCommentJob::TEXT => 'alohaa', + ]); + }, 'Invalid comment ID'); + } + + + protected function runApi($text) + { + $comment = $this->mockComment(Auth::getCurrentUser()); + + return Api::run( + new EditCommentJob(), + [ + EditCommentJob::COMMENT_ID => $comment->id, + EditCommentJob::TEXT => $text, + ]); + } + + protected function prepare() + { + $this->login($this->mockUser()); + } +} diff --git a/tests/CommentListTest.php b/tests/CommentListTest.php new file mode 100644 index 00000000..5aa1ccdc --- /dev/null +++ b/tests/CommentListTest.php @@ -0,0 +1,71 @@ +assert->areEqual(0, CommentModel::getCount()); + + $ret = $this->runApi(1); + $this->assert->areEqual(0, count($ret->entities)); + } + + public function testSingle() + { + $this->assert->areEqual(0, CommentModel::getCount()); + + $this->mockComment($this->mockUser()); + + $ret = $this->runApi(1); + $this->assert->areEqual(1, count($ret->entities)); + + $post = $ret->entities[0]; + $samePost = $this->assert->doesNotThrow(function() use ($post) + { + return PostModel::findById($post->id); + }); + //posts retrieved via ListCommentsJob should already have cached its comments + $this->assert->areNotEquivalent($post, $samePost); + $post->resetCache(); + $samePost->resetCache(); + $this->assert->areEquivalent($post, $samePost); + } + + public function testPaging() + { + getConfig()->comments->commentsPerPage = 2; + + $this->assert->areEqual(0, CommentModel::getCount()); + + $this->mockComment($this->mockUser()); + $this->mockComment($this->mockUser()); + $this->mockComment($this->mockUser()); + + $ret = $this->runApi(1); + $this->assert->areEqual(2, count($ret->entities)); + + $ret = $this->runApi(2); + $this->assert->areEqual(1, count($ret->entities)); + } + + public function testAccessDenial() + { + getConfig()->privileges->listComments = 'nobody'; + Access::init(); + $this->assert->isFalse(Access::check(new Privilege(Privilege::ListComments))); + + $this->assert->throws(function() + { + $this->runApi(1); + }, 'Insufficient privileges'); + } + + + protected function runApi($page) + { + return Api::run( + new ListCommentsJob(), + [ + ListCommentsJob::PAGE_NUMBER => $page, + ]); + } +}