diff options
-rw-r--r-- | core/register_command.php | 2 | ||||
-rw-r--r-- | lib/private/App/InfoParser.php | 45 | ||||
-rw-r--r-- | lib/private/AppFramework/App.php | 21 | ||||
-rw-r--r-- | lib/private/Notification/Notification.php | 32 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 79 | ||||
-rw-r--r-- | lib/private/legacy/app.php | 17 | ||||
-rw-r--r-- | lib/public/Notification/INotification.php | 28 | ||||
-rw-r--r-- | tests/data/app/expected-info.json | 4 | ||||
-rw-r--r-- | tests/lib/App/CodeChecker/InfoCheckerTest.php | 4 | ||||
-rw-r--r-- | tests/lib/App/InfoParserTest.php | 47 | ||||
-rw-r--r-- | tests/lib/InfoXmlTest.php | 122 | ||||
-rw-r--r-- | tests/lib/Notification/NotificationTest.php | 28 |
12 files changed, 318 insertions, 111 deletions
diff --git a/core/register_command.php b/core/register_command.php index 23621e54f8d..a6da3cbd899 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -36,7 +36,7 @@ $application->add(new \Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand()); $application->add(new OC\Core\Command\Status); $application->add(new OC\Core\Command\Check(\OC::$server->getConfig())); -$infoParser = new \OC\App\InfoParser(\OC::$server->getURLGenerator()); +$infoParser = new \OC\App\InfoParser(); $application->add(new OC\Core\Command\App\CheckCode($infoParser)); $application->add(new OC\Core\Command\L10n\CreateJs()); $application->add(new \OC\Core\Command\Integrity\SignApp( diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php index e975ad6f096..fbeb932763e 100644 --- a/lib/private/App/InfoParser.php +++ b/lib/private/App/InfoParser.php @@ -1,6 +1,7 @@ <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. + * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> * * @author Andreas Fischer <bantu@owncloud.com> * @author Christoph Wurst <christoph@owncloud.com> @@ -26,18 +27,17 @@ namespace OC\App; -use OCP\IURLGenerator; +use OCP\ICache; class InfoParser { - - /** @var IURLGenerator */ - private $urlGenerator; + /** @var \OCP\ICache|null */ + private $cache; /** - * @param IURLGenerator $urlGenerator + * @param ICache|null $cache */ - public function __construct(IURLGenerator $urlGenerator) { - $this->urlGenerator = $urlGenerator; + public function __construct(ICache $cache = null) { + $this->cache = $cache; } /** @@ -49,18 +49,28 @@ class InfoParser { return null; } + if(!is_null($this->cache)) { + $fileCacheKey = $file . filemtime($file); + if ($cachedValue = $this->cache->get($fileCacheKey)) { + return json_decode($cachedValue, true); + } + } + libxml_use_internal_errors(true); $loadEntities = libxml_disable_entity_loader(false); $xml = simplexml_load_file($file); + libxml_disable_entity_loader($loadEntities); - if ($xml == false) { + if ($xml === false) { libxml_clear_errors(); return null; } $array = $this->xmlToArray($xml); + if (is_null($array)) { return null; } + if (!array_key_exists('info', $array)) { $array['info'] = []; } @@ -98,17 +108,6 @@ class InfoParser { $array['two-factor-providers'] = []; } - if (array_key_exists('documentation', $array) && is_array($array['documentation'])) { - foreach ($array['documentation'] as $key => $url) { - // If it is not an absolute URL we assume it is a key - // i.e. admin-ldap will get converted to go.php?to=admin-ldap - if (!$this->isHTTPURL($url)) { - $url = $this->urlGenerator->linkToDocs($url); - } - - $array['documentation'][$key] = $url; - } - } if (array_key_exists('types', $array)) { if (is_array($array['types'])) { foreach ($array['types'] as $type => $v) { @@ -139,6 +138,10 @@ class InfoParser { if (isset($array['background-jobs']['job']) && is_array($array['background-jobs']['job'])) { $array['background-jobs'] = $array['background-jobs']['job']; } + + if(!is_null($this->cache)) { + $this->cache->set($fileCacheKey, json_encode($array)); + } return $array; } @@ -193,8 +196,4 @@ class InfoParser { return $array; } - - private function isHTTPURL($url) { - return stripos($url, 'https://') === 0 || stripos($url, 'http://') === 0; - } } diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php index 427a850f396..e15e4a797ea 100644 --- a/lib/private/AppFramework/App.php +++ b/lib/private/AppFramework/App.php @@ -59,24 +59,11 @@ class App { return $topNamespace . self::$nameSpaceCache[$appId]; } - // first try to parse the app's appinfo/info.xml <namespace> tag - $appPath = OC_App::getAppPath($appId); - if ($appPath !== false) { - $filePath = "$appPath/appinfo/info.xml"; - if (is_file($filePath)) { - $loadEntities = libxml_disable_entity_loader(false); - $xml = @simplexml_load_file($filePath); - libxml_disable_entity_loader($loadEntities); - if ($xml) { - $result = $xml->xpath('/info/namespace'); - if ($result && count($result) > 0) { - self::$nameSpaceCache[$appId] = trim((string) $result[0]); - // take first namespace result - return $topNamespace . self::$nameSpaceCache[$appId]; - } - } - } + $appInfo = \OC_App::getAppInfo($appId); + if (isset($appInfo['namespace'])) { + return $topNamespace . trim($appInfo['namespace']); } + // if the tag is not found, fall back to uppercasing the first letter self::$nameSpaceCache[$appId] = ucfirst($appId); return $topNamespace . self::$nameSpaceCache[$appId]; diff --git a/lib/private/Notification/Notification.php b/lib/private/Notification/Notification.php index 9b5877a3058..7bf4b9a74cf 100644 --- a/lib/private/Notification/Notification.php +++ b/lib/private/Notification/Notification.php @@ -242,7 +242,7 @@ class Notification implements INotification { /** * @param string $subject * @return $this - * @throws \InvalidArgumentException if the subject are invalid + * @throws \InvalidArgumentException if the subject is invalid * @since 8.2.0 */ public function setParsedSubject($subject) { @@ -300,7 +300,7 @@ class Notification implements INotification { /** * @param string $message * @return $this - * @throws \InvalidArgumentException if the message are invalid + * @throws \InvalidArgumentException if the message is invalid * @since 8.2.0 */ public function setParsedMessage($message) { @@ -322,7 +322,7 @@ class Notification implements INotification { /** * @param string $link * @return $this - * @throws \InvalidArgumentException if the link are invalid + * @throws \InvalidArgumentException if the link is invalid * @since 8.2.0 */ public function setLink($link) { @@ -342,6 +342,28 @@ class Notification implements INotification { } /** + * @param string $icon + * @return $this + * @throws \InvalidArgumentException if the icon is invalid + * @since 9.2.0 + */ + public function setIcon($icon) { + if (!is_string($icon) || $icon === '' || isset($icon[4000])) { + throw new \InvalidArgumentException('The given icon is invalid'); + } + $this->icon = $icon; + return $this; + } + + /** + * @return string + * @since 9.2.0 + */ + public function getIcon() { + return $this->icon; + } + + /** * @return IAction * @since 8.2.0 */ @@ -352,7 +374,7 @@ class Notification implements INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action are invalid + * @throws \InvalidArgumentException if the action is invalid * @since 8.2.0 */ public function addAction(IAction $action) { @@ -383,7 +405,7 @@ class Notification implements INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action are invalid + * @throws \InvalidArgumentException if the action is invalid * @since 8.2.0 */ public function addParsedAction(IAction $action) { diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index d6afcf99912..56b9d5b1ee8 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -543,7 +543,7 @@ class DefaultShareProvider implements IShareProvider { // If the recipient is set for a group share resolve to that user if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) { - $share = $this->resolveGroupShare($share, $recipientId); + $share = $this->resolveGroupShares([$share], $recipientId)[0]; } return $share; @@ -709,11 +709,8 @@ class DefaultShareProvider implements IShareProvider { /* * Resolve all group shares to user specific shares - * TODO: Optmize this! */ - foreach($shares2 as $share) { - $shares[] = $this->resolveGroupShare($share, $userId); - } + $shares = $this->resolveGroupShares($shares2, $userId); } else { throw new BackendError('Invalid backend'); } @@ -802,37 +799,59 @@ class DefaultShareProvider implements IShareProvider { } /** - * Resolve a group share to a user specific share - * Thus if the user moved their group share make sure this is properly reflected here. - * - * @param \OCP\Share\IShare $share - * @param string $userId - * @return Share Returns the updated share if one was found else return the original share. + * @param Share[] $shares + * @param $userId + * @return Share[] The updates shares if no update is found for a share return the original */ - private function resolveGroupShare(\OCP\Share\IShare $share, $userId) { - $qb = $this->dbConn->getQueryBuilder(); + private function resolveGroupShares($shares, $userId) { + $result = []; - $stmt = $qb->select('*') - ->from('share') - ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))) - ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) - ->setMaxResults(1) - ->execute(); + $start = 0; + while(true) { + /** @var Share[] $shareSlice */ + $shareSlice = array_slice($shares, $start, 100); + $start += 100; + + if ($shareSlice === []) { + break; + } + + /** @var int[] $ids */ + $ids = []; + /** @var Share[] $shareMap */ + $shareMap = []; + + foreach ($shareSlice as $share) { + $ids[] = (int)$share->getId(); + $shareMap[$share->getId()] = $share; + } - $data = $stmt->fetch(); - $stmt->closeCursor(); + $qb = $this->dbConn->getQueryBuilder(); + + $query = $qb->select('*') + ->from('share') + ->where($qb->expr()->in('parent', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) + ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))) + ->andWhere($qb->expr()->orX( + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) + )); - if ($data !== false) { - $share->setPermissions((int)$data['permissions']); - $share->setTarget($data['file_target']); + $stmt = $query->execute(); + + while($data = $stmt->fetch()) { + $shareMap[$data['parent']]->setPermissions((int)$data['permissions']); + $shareMap[$data['parent']]->setTarget($data['file_target']); + } + + $stmt->closeCursor(); + + foreach ($shareMap as $share) { + $result[] = $share; + } } - return $share; + return $result; } /** diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php index c3d2d1d6ad4..5e05884f5c0 100644 --- a/lib/private/legacy/app.php +++ b/lib/private/legacy/app.php @@ -47,6 +47,7 @@ * */ use OC\App\DependencyAnalyzer; +use OC\App\InfoParser; use OC\App\Platform; use OC\Installer; use OC\OCSClient; @@ -681,7 +682,7 @@ class OC_App { $file = $appPath . '/appinfo/info.xml'; } - $parser = new \OC\App\InfoParser(\OC::$server->getURLGenerator()); + $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo')); $data = $parser->parse($file); if (is_array($data)) { @@ -847,6 +848,7 @@ class OC_App { $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps(); $appList = array(); $langCode = \OC::$server->getL10N('core')->getLanguageCode(); + $urlGenerator = \OC::$server->getURLGenerator(); foreach ($installedApps as $app) { if (array_search($app, $blacklist) === false) { @@ -900,6 +902,19 @@ class OC_App { } } } + // fix documentation + if (isset($info['documentation']) && is_array($info['documentation'])) { + foreach ($info['documentation'] as $key => $url) { + // If it is not an absolute URL we assume it is a key + // i.e. admin-ldap will get converted to go.php?to=admin-ldap + if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) { + $url = $urlGenerator->linkToDocs($url); + } + + $info['documentation'][$key] = $url; + } + } + $info['version'] = OC_App::getAppVersion($app); $appList[] = $info; } diff --git a/lib/public/Notification/INotification.php b/lib/public/Notification/INotification.php index 492e30dfaf1..fd16876a666 100644 --- a/lib/public/Notification/INotification.php +++ b/lib/public/Notification/INotification.php @@ -32,7 +32,7 @@ interface INotification { /** * @param string $app * @return $this - * @throws \InvalidArgumentException if the app id are invalid + * @throws \InvalidArgumentException if the app id is invalid * @since 9.0.0 */ public function setApp($app); @@ -46,7 +46,7 @@ interface INotification { /** * @param string $user * @return $this - * @throws \InvalidArgumentException if the user id are invalid + * @throws \InvalidArgumentException if the user id is invalid * @since 9.0.0 */ public function setUser($user); @@ -116,7 +116,7 @@ interface INotification { /** * @param string $subject * @return $this - * @throws \InvalidArgumentException if the subject are invalid + * @throws \InvalidArgumentException if the subject is invalid * @since 9.0.0 */ public function setParsedSubject($subject); @@ -151,7 +151,7 @@ interface INotification { /** * @param string $message * @return $this - * @throws \InvalidArgumentException if the message are invalid + * @throws \InvalidArgumentException if the message is invalid * @since 9.0.0 */ public function setParsedMessage($message); @@ -165,7 +165,7 @@ interface INotification { /** * @param string $link * @return $this - * @throws \InvalidArgumentException if the link are invalid + * @throws \InvalidArgumentException if the link is invalid * @since 9.0.0 */ public function setLink($link); @@ -177,6 +177,20 @@ interface INotification { public function getLink(); /** + * @param string $icon + * @return $this + * @throws \InvalidArgumentException if the icon is invalid + * @since 9.2.0 + */ + public function setIcon($icon); + + /** + * @return string + * @since 9.2.0 + */ + public function getIcon(); + + /** * @return IAction * @since 9.0.0 */ @@ -185,7 +199,7 @@ interface INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action are invalid + * @throws \InvalidArgumentException if the action is invalid * @since 9.0.0 */ public function addAction(IAction $action); @@ -199,7 +213,7 @@ interface INotification { /** * @param IAction $action * @return $this - * @throws \InvalidArgumentException if the action are invalid + * @throws \InvalidArgumentException if the action is invalid * @since 9.0.0 */ public function addParsedAction(IAction $action); diff --git a/tests/data/app/expected-info.json b/tests/data/app/expected-info.json index 6d8d85ab552..6ddd3ae8568 100644 --- a/tests/data/app/expected-info.json +++ b/tests/data/app/expected-info.json @@ -10,8 +10,8 @@ "requiremin": "4", "shipped": "true", "documentation": { - "user": "https://docs.example.com/server/go.php?to=user-encryption", - "admin": "https://docs.example.com/server/go.php?to=admin-encryption" + "user": "user-encryption", + "admin": "admin-encryption" }, "rememberlogin": "false", "types": ["filesystem"], diff --git a/tests/lib/App/CodeChecker/InfoCheckerTest.php b/tests/lib/App/CodeChecker/InfoCheckerTest.php index 1032e800be1..c16874fbd33 100644 --- a/tests/lib/App/CodeChecker/InfoCheckerTest.php +++ b/tests/lib/App/CodeChecker/InfoCheckerTest.php @@ -44,9 +44,7 @@ class InfoCheckerTest extends TestCase { protected function setUp() { parent::setUp(); - $infoParser = new InfoParser(\OC::$server->getURLGenerator()); - - $this->infoChecker = new InfoChecker($infoParser); + $this->infoChecker = new InfoChecker(new InfoParser()); } public function appInfoData() { diff --git a/tests/lib/App/InfoParserTest.php b/tests/lib/App/InfoParserTest.php index 7f52507bcf7..5a3847a71e8 100644 --- a/tests/lib/App/InfoParserTest.php +++ b/tests/lib/App/InfoParserTest.php @@ -1,5 +1,4 @@ <?php - /** * @author Thomas Müller * @copyright 2014 Thomas Müller deepdiver@owncloud.com @@ -10,46 +9,50 @@ namespace Test\App; use OC; -use OCP\IURLGenerator; +use OC\App\InfoParser; use Test\TestCase; class InfoParserTest extends TestCase { + /** @var OC\Cache\CappedMemoryCache */ + private static $cache; - /** @var \OC\App\InfoParser */ - private $parser; + public static function setUpBeforeClass() { + self::$cache = new OC\Cache\CappedMemoryCache(); + } - public function setUp() { - $urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator') - ->disableOriginalConstructor() - ->getMock(); - /** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject $urlGenerator */ - $urlGenerator->expects($this->any()) - ->method('linkToDocs') - ->will($this->returnCallback(function ($url) { - return "https://docs.example.com/server/go.php?to=$url"; - })); + public function parserTest($expectedJson, $xmlFile, $cache = null) { + $parser = new InfoParser($cache); - $this->parser = new \OC\App\InfoParser($urlGenerator); - } - - /** - * @dataProvider providesInfoXml - */ - public function testParsingValidXml($expectedJson, $xmlFile) { $expectedData = null; if (!is_null($expectedJson)) { $expectedData = json_decode(file_get_contents(OC::$SERVERROOT . "/tests/data/app/$expectedJson"), true); } - $data = $this->parser->parse(OC::$SERVERROOT. "/tests/data/app/$xmlFile"); + $data = $parser->parse(OC::$SERVERROOT. "/tests/data/app/$xmlFile"); $this->assertEquals($expectedData, $data); } + /** + * @dataProvider providesInfoXml + */ + public function testParsingValidXmlWithoutCache($expectedJson, $xmlFile) { + $this->parserTest($expectedJson, $xmlFile); + } + + /** + * @dataProvider providesInfoXml + */ + public function testParsingValidXmlWithCache($expectedJson, $xmlFile) { + $this->parserTest($expectedJson, $xmlFile, self::$cache); + } + function providesInfoXml() { return array( array('expected-info.json', 'valid-info.xml'), array(null, 'invalid-info.xml'), + array('expected-info.json', 'valid-info.xml'), + array(null, 'invalid-info.xml'), ); } } diff --git a/tests/lib/InfoXmlTest.php b/tests/lib/InfoXmlTest.php new file mode 100644 index 00000000000..bf6cd08ee39 --- /dev/null +++ b/tests/lib/InfoXmlTest.php @@ -0,0 +1,122 @@ +<?php +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace Test; + + +/** + * Class InfoXmlTest + * + * @group DB + * @package Test + */ +class InfoXmlTest extends TestCase { + + public function dataApps() { + return [ + ['admin_audit'], + ['comments'], + ['dav'], + ['encryption'], + ['federatedfilesharing'], + ['federation'], + ['files'], + ['files_external'], + ['files_sharing'], + ['files_trashbin'], + ['files_versions'], + ['provisioning_api'], + ['systemtags'], + ['theming'], + ['twofactor_backupcodes'], + ['updatenotification'], + ['user_ldap'], + ['workflowengine'], + ]; + } + + /** + * @dataProvider dataApps + * + * @param string $app + */ + public function testClasses($app) { + $appInfo = \OC_App::getAppInfo($app); + $appPath = \OC_App::getAppPath($app); + \OC_App::registerAutoloading($app, $appPath); + + if (isset($appInfo['background-jobs'])) { + foreach ($appInfo['background-jobs'] as $job) { + $this->assertTrue(class_exists($job), 'Asserting background job "' . $job . '" exists'); + $this->assertInstanceOf($job, \OC::$server->query($job)); + } + } + + if (isset($appInfo['two-factor-providers'])) { + foreach ($appInfo['two-factor-providers'] as $provider) { + $this->assertTrue(class_exists($provider), 'Asserting two-factor providers "' . $provider . '" exists'); + $this->assertInstanceOf($provider, \OC::$server->query($provider)); + } + } + + if (isset($appInfo['commands'])) { + foreach ($appInfo['commands'] as $command) { + $this->assertTrue(class_exists($command), 'Asserting command "' . $command . '" exists'); + $this->assertInstanceOf($command, \OC::$server->query($command)); + } + } + + if (isset($appInfo['repair-steps']['pre-migration'])) { + foreach ($appInfo['repair-steps']['pre-migration'] as $migration) { + $this->assertTrue(class_exists($migration), 'Asserting pre-migration "' . $migration . '" exists'); + $this->assertInstanceOf($migration, \OC::$server->query($migration)); + } + } + + if (isset($appInfo['repair-steps']['post-migration'])) { + foreach ($appInfo['repair-steps']['post-migration'] as $migration) { + $this->assertTrue(class_exists($migration), 'Asserting post-migration "' . $migration . '" exists'); + $this->assertInstanceOf($migration, \OC::$server->query($migration)); + } + } + + if (isset($appInfo['repair-steps']['live-migration'])) { + foreach ($appInfo['repair-steps']['live-migration'] as $migration) { + $this->assertTrue(class_exists($migration), 'Asserting live-migration "' . $migration . '" exists'); + $this->assertInstanceOf($migration, \OC::$server->query($migration)); + } + } + + if (isset($appInfo['repair-steps']['install'])) { + foreach ($appInfo['repair-steps']['install'] as $migration) { + $this->assertTrue(class_exists($migration), 'Asserting install-migration "' . $migration . '" exists'); + $this->assertInstanceOf($migration, \OC::$server->query($migration)); + } + } + + if (isset($appInfo['repair-steps']['uninstall'])) { + foreach ($appInfo['repair-steps']['uninstall'] as $migration) { + $this->assertTrue(class_exists($migration), 'Asserting uninstall-migration "' . $migration . '" exists'); + $this->assertInstanceOf($migration, \OC::$server->query($migration)); + } + } + } +} diff --git a/tests/lib/Notification/NotificationTest.php b/tests/lib/Notification/NotificationTest.php index 93d48dfd604..77d9e989cf1 100644 --- a/tests/lib/Notification/NotificationTest.php +++ b/tests/lib/Notification/NotificationTest.php @@ -386,6 +386,34 @@ class NotificationTest extends TestCase { $this->notification->setLink($link); } + public function dataSetIcon() { + return $this->dataValidString(4000); + } + + /** + * @dataProvider dataSetIcon + * @param string $icon + */ + public function testSetIcon($icon) { + $this->assertSame('', $this->notification->getIcon()); + $this->assertSame($this->notification, $this->notification->setIcon($icon)); + $this->assertSame($icon, $this->notification->getIcon()); + } + + public function dataSetIconInvalid() { + return $this->dataInvalidString(4000); + } + + /** + * @dataProvider dataSetIconInvalid + * @param mixed $icon + * + * @expectedException \InvalidArgumentException + */ + public function testSetIconInvalid($icon) { + $this->notification->setIcon($icon); + } + public function testCreateAction() { $action = $this->notification->createAction(); $this->assertInstanceOf('OCP\Notification\IAction', $action); |