* @author Bernhard Posselt * @copyright 2012 Alessandro Cosentino * @copyright 2012-2014 Bernhard Posselt */ namespace OCA\News\Tests\Unit\Db; use OC\DB\QueryBuilder\Parameter; use OC\DB\ResultAdapter; use OCA\News\Db\Feed; use OCA\News\Db\FeedMapperV2; use OCA\News\Utility\Time; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\DB\QueryBuilder\IFunctionBuilder; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; class FeedMapperTest extends MapperTestUtility { /** @var FeedMapperV2 */ private $class; /** @var Feed[] */ private $feeds; /** * @covers \OCA\News\Db\FeedMapperV2::__construct */ protected function setUp(): void { parent::setUp(); $this->class = new FeedMapperV2($this->db, new Time()); // create mock folders $feed1 = new Feed(); $feed1->setId(4); $feed1->resetUpdatedFields(); $feed2 = new Feed(); $feed2->setId(5); $feed2->resetUpdatedFields(); $this->feeds = [$feed1, $feed2]; } /** * @covers \OCA\News\Db\FeedMapperV2::__construct */ public function testSetUpSuccess(): void { $this->assertEquals('news_feeds', $this->class->getTableName()); } /** * @covers \OCA\News\Db\FeedMapperV2::findAllFromUser */ public function testFindAllFromUser() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $funcbuilder = $this->getMockBuilder(IFunctionBuilder::class) ->getMock(); $func = $this->getMockBuilder(IQueryFunction::class) ->getMock(); $funcbuilder->expects($this->once()) ->method('count') ->with('items.id', 'unreadCount') ->will($this->returnValue($func)); $this->builder->expects($this->once()) ->method('func') ->will($this->returnValue($funcbuilder)); $this->builder->expects($this->once()) ->method('select') ->with('feeds.*', $func) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds', 'feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('leftJoin') ->with('feeds', 'news_items', 'items', 'items.feed_id = feeds.id AND items.unread = :unread') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('feeds.user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('andWhere') ->with('feeds.deleted_at = 0') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('groupby') ->with('feeds.id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['unread', true], ['user_id', 'jack']) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(3)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], ['id' => 5], null ); $result = $this->class->findAllFromUser('jack', []); $this->assertEquals($this->feeds, $result); } /** * @covers \OCA\News\Db\FeedMapperV2::findFromUser */ public function testFindFromUser() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('andWhere') ->withConsecutive(['id = :id']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['user_id', 'jack'], ['id', 1]) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(2)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], false ); $result = $this->class->findFromUser('jack', 1); $this->assertEquals($this->feeds[0], $result); } /** * @covers \OCA\News\Db\FeedMapperV2::findFromUser */ public function testFindFromUserEmpty() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('andWhere') ->withConsecutive(['id = :id']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['user_id', 'jack'], ['id', 1]) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(1)) ->method('fetch') ->willReturnOnConsecutiveCalls( false ); $this->expectException(DoesNotExistException::class); $this->class->findFromUser('jack', 1); } /** * @covers \OCA\News\Db\FeedMapperV2::findByURL */ public function testFindByUrl() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('andWhere') ->withConsecutive(['url = :url']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['user_id', 'jack'], ['url', 'https://url.com']) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(2)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], false ); $result = $this->class->findByURL('jack', 'https://url.com'); $this->assertEquals($this->feeds[0], $result); } /** * @covers \OCA\News\Db\FeedMapperV2::findFromUser */ public function testFindFromUserDuplicate() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('andWhere') ->withConsecutive(['id = :id']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['user_id', 'jack'], ['id', 1]) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(2)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 1], ['id' => 2] ); $this->expectException(MultipleObjectsReturnedException::class); $this->class->findFromUser('jack', 1); } /** * @covers \OCA\News\Db\FeedMapperV2::findAll */ public function testFindAll() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('deleted_at = 0') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(3)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], ['id' => 5], null ); $result = $this->class->findAll(); $this->assertEquals($this->feeds, $result); } /** * @covers \OCA\News\Db\FeedMapperV2::findAllFromFolder */ public function testFindAllFromFolder() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('folder_id = :folder_id') ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('setParameter') ->withConsecutive(['folder_id', 1]) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(3)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], ['id' => 5], null ); $result = $this->class->findAllFromFolder(1); $this->assertEquals($this->feeds, $result); } /** * @covers \OCA\News\Db\FeedMapperV2::findAllFromFolder */ public function testFindAllFromRootFolder() { $this->db->expects($this->once()) ->method('getQueryBuilder') ->willReturn($this->builder); $this->builder->expects($this->once()) ->method('select') ->with('*') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('from') ->with('news_feeds') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') ->with('folder_id IS NULL') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('executeQuery') ->willReturn($this->cursor); $this->cursor->expects($this->exactly(3)) ->method('fetch') ->willReturnOnConsecutiveCalls( ['id' => 4], ['id' => 5], null ); $result = $this->class->findAllFromFolder(null); $this->assertEquals($this->feeds, $result); } /** * @covers \OCA\News\Db\FeedMapperV2::read */ public function testRead() { $selectbuilder = $this->getMockBuilder(IQueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $this->db->expects($this->exactly(2)) ->method('getQueryBuilder') ->willReturnOnConsecutiveCalls($selectbuilder, $this->builder); $selectbuilder->expects($this->once()) ->method('select') ->with('items.id') ->will($this->returnSelf()); $selectbuilder->expects($this->once()) ->method('from') ->with('news_items', 'items') ->will($this->returnSelf()); $selectbuilder->expects($this->once()) ->method('innerJoin') ->with('items', 'news_feeds', 'feeds', 'items.feed_id = feeds.id') ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(2)) ->method('andWhere') ->withConsecutive(['feeds.user_id = :userId'], ['feeds.id = :feedId']) ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['userId', 'admin'], ['feedId', 1]) ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(1)) ->method('getSQL') ->will($this->returnValue('SQL QUERY')); $selectbuilder->expects($this->exactly(1)) ->method('getParameters') ->will($this->returnValue([])); $result = $this->getMockBuilder(ResultAdapter::class) ->disableOriginalConstructor() ->getMock(); $result->expects($this->once()) ->method('fetchAll') ->willReturn([['id' => 1], ['id' => 2]]); $this->db->expects($this->exactly(1)) ->method('executeQuery') ->with('SQL QUERY') ->willReturn($result); $this->builder->expects($this->once()) ->method('update') ->with('news_items') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('createParameter') ->will($this->returnArgument(0)); $this->builder->expects($this->once()) ->method('set') ->with('unread', 'unread') ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('andWhere') ->withConsecutive(['id IN (:idList)'], ['unread != :unread']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['unread', false], ['idList', [1, 2]]) ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('getSQL') ->will($this->returnValue('QUERY')); $this->builder->expects($this->exactly(1)) ->method('getParameters') ->will($this->returnValue([])); $this->builder->expects($this->exactly(1)) ->method('getParameterTypes') ->will($this->returnValue([])); $this->db->expects($this->exactly(1)) ->method('executeUpdate') ->with('QUERY'); $this->class->read('admin', 1); } /** * @covers \OCA\News\Db\FeedMapperV2::read */ public function testReadWithMaxID() { $selectbuilder = $this->getMockBuilder(IQueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $this->db->expects($this->exactly(2)) ->method('getQueryBuilder') ->willReturnOnConsecutiveCalls($selectbuilder, $this->builder); $selectbuilder->expects($this->once()) ->method('select') ->with('items.id') ->will($this->returnSelf()); $selectbuilder->expects($this->once()) ->method('from') ->with('news_items', 'items') ->will($this->returnSelf()); $selectbuilder->expects($this->once()) ->method('innerJoin') ->with('items', 'news_feeds', 'feeds', 'items.feed_id = feeds.id') ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(3)) ->method('andWhere') ->withConsecutive(['feeds.user_id = :userId'], ['feeds.id = :feedId'], ['items.id <= :maxItemId']) ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(3)) ->method('setParameter') ->withConsecutive(['userId', 'admin'], ['feedId', 1], ['maxItemId', 4]) ->will($this->returnSelf()); $selectbuilder->expects($this->exactly(1)) ->method('getSQL') ->will($this->returnValue('SQL QUERY')); $selectbuilder->expects($this->exactly(1)) ->method('getParameters') ->will($this->returnValue([])); $result = $this->getMockBuilder(ResultAdapter::class) ->disableOriginalConstructor() ->getMock(); $result->expects($this->once()) ->method('fetchAll') ->willReturn([['id' => 1], ['id' => 2]]); $this->db->expects($this->exactly(1)) ->method('executeQuery') ->with('SQL QUERY') ->willReturn($result); $this->builder->expects($this->once()) ->method('createParameter') ->will($this->returnArgument(0)); $this->builder->expects($this->once()) ->method('update') ->with('news_items') ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('set') ->with('unread', 'unread') ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('andWhere') ->withConsecutive(['id IN (:idList)'], ['unread != :unread']) ->will($this->returnSelf()); $this->builder->expects($this->exactly(2)) ->method('setParameter') ->withConsecutive(['unread', false], ['idList', [1, 2]]) ->will($this->returnSelf()); $this->builder->expects($this->exactly(1)) ->method('getSQL') ->will($this->returnValue('QUERY')); $this->builder->expects($this->exactly(1)) ->method('getParameters') ->will($this->returnValue([])); $this->builder->expects($this->exactly(1)) ->method('getParameterTypes') ->will($this->returnValue([])); $this->db->expects($this->exactly(1)) ->method('executeUpdate') ->with('QUERY'); $this->class->read('admin', 1, 4); } }