From fde9cabe9774b67e88ee8aa8fa39fe044fe2da2f Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 17 Aug 2013 11:16:48 +0200 Subject: initial import of appframework --- tests/lib/appframework/AppTest.php | 107 ++++++ tests/lib/appframework/classloader.php | 45 +++ .../lib/appframework/controller/ControllerTest.php | 161 +++++++++ .../dependencyinjection/DIContainerTest.php | 98 ++++++ tests/lib/appframework/http/DispatcherTest.php | 218 ++++++++++++ .../lib/appframework/http/DownloadResponseTest.php | 51 +++ tests/lib/appframework/http/HttpTest.php | 87 +++++ tests/lib/appframework/http/JSONResponseTest.php | 96 +++++ .../lib/appframework/http/RedirectResponseTest.php | 55 +++ tests/lib/appframework/http/RequestTest.php | 78 +++++ tests/lib/appframework/http/ResponseTest.php | 119 +++++++ .../lib/appframework/http/TemplateResponseTest.php | 157 +++++++++ .../middleware/MiddlewareDispatcherTest.php | 280 +++++++++++++++ .../lib/appframework/middleware/MiddlewareTest.php | 82 +++++ .../middleware/security/SecurityMiddlewareTest.php | 388 +++++++++++++++++++++ tests/lib/appframework/routing/RoutingTest.php | 214 ++++++++++++ .../utility/MethodAnnotationReaderTest.php | 58 +++ 17 files changed, 2294 insertions(+) create mode 100644 tests/lib/appframework/AppTest.php create mode 100644 tests/lib/appframework/classloader.php create mode 100644 tests/lib/appframework/controller/ControllerTest.php create mode 100644 tests/lib/appframework/dependencyinjection/DIContainerTest.php create mode 100644 tests/lib/appframework/http/DispatcherTest.php create mode 100644 tests/lib/appframework/http/DownloadResponseTest.php create mode 100644 tests/lib/appframework/http/HttpTest.php create mode 100644 tests/lib/appframework/http/JSONResponseTest.php create mode 100644 tests/lib/appframework/http/RedirectResponseTest.php create mode 100644 tests/lib/appframework/http/RequestTest.php create mode 100644 tests/lib/appframework/http/ResponseTest.php create mode 100644 tests/lib/appframework/http/TemplateResponseTest.php create mode 100644 tests/lib/appframework/middleware/MiddlewareDispatcherTest.php create mode 100644 tests/lib/appframework/middleware/MiddlewareTest.php create mode 100644 tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php create mode 100644 tests/lib/appframework/routing/RoutingTest.php create mode 100644 tests/lib/appframework/utility/MethodAnnotationReaderTest.php (limited to 'tests') diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php new file mode 100644 index 00000000000..000094d07c8 --- /dev/null +++ b/tests/lib/appframework/AppTest.php @@ -0,0 +1,107 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + +// FIXME: loading pimpl correctly from 3rdparty repo +require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . "/classloader.php"; + + +class AppTest extends \PHPUnit_Framework_TestCase { + + private $container; + private $api; + private $controller; + private $dispatcher; + private $params; + private $headers; + private $output; + private $controllerName; + private $controllerMethod; + + protected function setUp() { + $this->container = new \Pimple(); + $this->controller = $this->getMockBuilder( + 'OC\AppFramework\Controller\Controller') + ->disableOriginalConstructor() + ->getMock(); + $this->dispatcher = $this->getMockBuilder( + 'OC\AppFramework\Http\Dispatcher') + ->disableOriginalConstructor() + ->getMock(); + + + $this->headers = array('key' => 'value'); + $this->output = 'hi'; + $this->controllerName = 'Controller'; + $this->controllerMethod = 'method'; + + $this->container[$this->controllerName] = $this->controller; + $this->container['Dispatcher'] = $this->dispatcher; + } + + + public function testControllerNameAndMethodAreBeingPassed(){ + $return = array(null, array(), null); + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->returnValue($return)); + + $this->expectOutputString(''); + + App::main($this->controllerName, $this->controllerMethod, array(), + $this->container); + } + + + /* + FIXME: this complains about shit headers which are already sent because + of the content length. Would be cool if someone could fix this + + public function testOutputIsPrinted(){ + $return = array(null, array(), $this->output); + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->returnValue($return)); + + $this->expectOutputString($this->output); + + App::main($this->controllerName, $this->controllerMethod, array(), + $this->container); + } + */ + + // FIXME: if someone manages to test the headers output, I'd be grateful + + +} diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php new file mode 100644 index 00000000000..ae485e67b2c --- /dev/null +++ b/tests/lib/appframework/classloader.php @@ -0,0 +1,45 @@ +. + * + */ + +// to execute without ownCloud, we need to create our own class loader +spl_autoload_register(function ($className){ + if (strpos($className, 'OC\\AppFramework') === 0) { + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../../../lib/' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } + + // FIXME: this will most probably not work anymore + if (strpos($className, 'OCA\\') === 0) { + + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../..' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } +}); diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php new file mode 100644 index 00000000000..d8357c2a685 --- /dev/null +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -0,0 +1,161 @@ +. + * + */ + + +namespace Test\AppFramework\Controller; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\JSONResponse; +use OC\AppFramework\Http\TemplateResponse; +use OC\AppFramework\Controller\Controller; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildController extends Controller {}; + +class ControllerTest extends \PHPUnit_Framework_TestCase { + + /** + * @var Controller + */ + private $controller; + private $api; + + protected function setUp(){ + $request = new Request( + array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), + 'urlParams' => array('name' => 'Johnny Weissmüller'), + 'files' => array('file' => 'filevalue'), + 'env' => array('PATH' => 'daheim'), + 'session' => array('sezession' => 'kein'), + 'method' => 'hi', + ) + ); + + $this->api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('test')); + $this->api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('apptemplate_advanced')); + + $this->controller = new ChildController($this->api, $request); + } + + + public function testParamsGet(){ + $this->assertEquals('Johnny Weissmüller', $this->controller->params('name', 'Tarzan')); + } + + + public function testParamsGetDefault(){ + $this->assertEquals('Tarzan', $this->controller->params('Ape Man', 'Tarzan')); + } + + + public function testParamsFile(){ + $this->assertEquals('filevalue', $this->controller->params('file', 'filevalue')); + } + + + public function testGetUploadedFile(){ + $this->assertEquals('filevalue', $this->controller->getUploadedFile('file')); + } + + + + public function testGetUploadedFileDefault(){ + $this->assertEquals('default', $this->controller->params('files', 'default')); + } + + + public function testGetParams(){ + $params = array( + 'name' => 'Johnny Weissmüller', + 'nickname' => 'Janey', + ); + + $this->assertEquals($params, $this->controller->getParams()); + } + + + public function testRender(){ + $this->assertTrue($this->controller->render('') instanceof TemplateResponse); + } + + + public function testSetParams(){ + $params = array('john' => 'foo'); + $response = $this->controller->render('home', $params); + + $this->assertEquals($params, $response->getParams()); + } + + + public function testRenderRenderAs(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $this->controller = new ChildController($api, new Request()); + $this->controller->render('home', array(), 'admin')->render(); + } + + + public function testRenderHeaders(){ + $headers = array('one', 'two'); + $response = $this->controller->render('', array(), '', $headers); + + $this->assertTrue(in_array($headers[0], $response->getHeaders())); + $this->assertTrue(in_array($headers[1], $response->getHeaders())); + } + + + public function testGetRequestMethod(){ + $this->assertEquals('hi', $this->controller->method()); + } + + + public function testGetEnvVariable(){ + $this->assertEquals('daheim', $this->controller->env('PATH')); + } + + public function testGetSessionVariable(){ + $this->assertEquals('kein', $this->controller->session('sezession')); + } + + +} diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php new file mode 100644 index 00000000000..ce346f0a763 --- /dev/null +++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php @@ -0,0 +1,98 @@ +. + * + */ + + +namespace OC\AppFramework\DependencyInjection; + +use \OC\AppFramework\Http\Request; + + +require_once(__DIR__ . "/../classloader.php"); + + +class DIContainerTest extends \PHPUnit_Framework_TestCase { + + private $container; + + protected function setUp(){ + $this->container = new DIContainer('name'); + $this->api = $this->getMock('OC\AppFramework\Core\API', array('getTrans'), array('hi')); + } + + private function exchangeAPI(){ + $this->api->expects($this->any()) + ->method('getTrans') + ->will($this->returnValue('yo')); + $this->container['API'] = $this->api; + } + + public function testProvidesAPI(){ + $this->assertTrue(isset($this->container['API'])); + } + + + public function testProvidesRequest(){ + $this->assertTrue(isset($this->container['Request'])); + } + + + public function testProvidesSecurityMiddleware(){ + $this->assertTrue(isset($this->container['SecurityMiddleware'])); + } + + + public function testProvidesMiddlewareDispatcher(){ + $this->assertTrue(isset($this->container['MiddlewareDispatcher'])); + } + + + public function testProvidesAppName(){ + $this->assertTrue(isset($this->container['AppName'])); + } + + + public function testAppNameIsSetCorrectly(){ + $this->assertEquals('name', $this->container['AppName']); + } + + + public function testMiddlewareDispatcherIncludesSecurityMiddleware(){ + $this->container['Request'] = new Request(); + $security = $this->container['SecurityMiddleware']; + $dispatcher = $this->container['MiddlewareDispatcher']; + + $this->assertContains($security, $dispatcher->getMiddlewares()); + } + + + public function testMiddlewareDispatcherDoesNotIncludeTwigWhenTplDirectoryNotSet(){ + $this->container['Request'] = new Request(); + $this->exchangeAPI(); + $dispatcher = $this->container['MiddlewareDispatcher']; + + $this->assertEquals(1, count($dispatcher->getMiddlewares())); + } + +} diff --git a/tests/lib/appframework/http/DispatcherTest.php b/tests/lib/appframework/http/DispatcherTest.php new file mode 100644 index 00000000000..2e3db110504 --- /dev/null +++ b/tests/lib/appframework/http/DispatcherTest.php @@ -0,0 +1,218 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OC\AppFramework\Core\API; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + +require_once(__DIR__ . "/../classloader.php"); + + +class DispatcherTest extends \PHPUnit_Framework_TestCase { + + + private $middlewareDispatcher; + private $dispatcher; + private $controllerMethod; + private $response; + private $lastModified; + private $etag; + private $http; + + protected function setUp() { + $this->controllerMethod = 'test'; + + $api = $this->getMockBuilder( + '\OC\AppFramework\Core\API') + ->disableOriginalConstructor() + ->getMock(); + $request = $this->getMockBuilder( + '\OC\AppFramework\Http\Request') + ->disableOriginalConstructor() + ->getMock(); + $this->http = $this->getMockBuilder( + '\OC\AppFramework\Http\Http') + ->disableOriginalConstructor() + ->getMock(); + + $this->middlewareDispatcher = $this->getMockBuilder( + '\OC\AppFramework\Middleware\MiddlewareDispatcher') + ->disableOriginalConstructor() + ->getMock(); + $this->controller = $this->getMock( + '\OC\AppFramework\Controller\Controller', + array($this->controllerMethod), array($api, $request)); + + $this->dispatcher = new Dispatcher( + $this->http, $this->middlewareDispatcher); + + $this->response = $this->getMockBuilder( + '\OC\AppFramework\Http\Response') + ->disableOriginalConstructor() + ->getMock(); + + $this->lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $this->etag = 'hi'; + } + + + private function setMiddlewareExpections($out=null, + $httpHeaders=null, $responseHeaders=array(), + $ex=false, $catchEx=true) { + + if($ex) { + $exception = new \Exception(); + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)) + ->will($this->throwException($exception)); + if($catchEx) { + $this->middlewareDispatcher->expects($this->once()) + ->method('afterException') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($exception)) + ->will($this->returnValue($this->response)); + } else { + $this->middlewareDispatcher->expects($this->once()) + ->method('afterException') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($exception)) + ->will($this->returnValue(null)); + return; + } + } else { + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod)); + $this->controller->expects($this->once()) + ->method($this->controllerMethod) + ->will($this->returnValue($this->response)); + } + + $this->response->expects($this->once()) + ->method('render') + ->will($this->returnValue($out)); + $this->response->expects($this->once()) + ->method('getStatus') + ->will($this->returnValue(Http::STATUS_OK)); + $this->response->expects($this->once()) + ->method('getLastModified') + ->will($this->returnValue($this->lastModified)); + $this->response->expects($this->once()) + ->method('getETag') + ->will($this->returnValue($this->etag)); + $this->response->expects($this->once()) + ->method('getHeaders') + ->will($this->returnValue($responseHeaders)); + $this->http->expects($this->once()) + ->method('getStatusHeader') + ->with($this->equalTo(Http::STATUS_OK), + $this->equalTo($this->lastModified), + $this->equalTo($this->etag)) + ->will($this->returnValue($httpHeaders)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('afterController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($this->response)) + ->will($this->returnValue($this->response)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('afterController') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($this->response)) + ->will($this->returnValue($this->response)); + + $this->middlewareDispatcher->expects($this->once()) + ->method('beforeOutput') + ->with($this->equalTo($this->controller), + $this->equalTo($this->controllerMethod), + $this->equalTo($out)) + ->will($this->returnValue($out)); + + + } + + + public function testDispatcherReturnsArrayWith2Entries() { + $this->setMiddlewareExpections(); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + $this->assertNull($response[0]); + $this->assertEquals(array(), $response[1]); + $this->assertNull($response[2]); + } + + + public function testHeadersAndOutputAreReturned(){ + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + $this->assertEquals($httpHeaders, $response[0]); + $this->assertEquals($responseHeaders, $response[1]); + $this->assertEquals($out, $response[2]); + } + + + public function testExceptionCallsAfterException() { + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true); + + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + $this->assertEquals($httpHeaders, $response[0]); + $this->assertEquals($responseHeaders, $response[1]); + $this->assertEquals($out, $response[2]); + } + + + public function testExceptionThrowsIfCanNotBeHandledByAfterException() { + $out = 'yo'; + $httpHeaders = 'Http'; + $responseHeaders = array('hell' => 'yeah'); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); + + $this->setExpectedException('\Exception'); + $response = $this->dispatcher->dispatch($this->controller, + $this->controllerMethod); + + } + +} diff --git a/tests/lib/appframework/http/DownloadResponseTest.php b/tests/lib/appframework/http/DownloadResponseTest.php new file mode 100644 index 00000000000..103cfe7588c --- /dev/null +++ b/tests/lib/appframework/http/DownloadResponseTest.php @@ -0,0 +1,51 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildDownloadResponse extends DownloadResponse {}; + + +class DownloadResponseTest extends \PHPUnit_Framework_TestCase { + + protected $response; + + protected function setUp(){ + $this->response = new ChildDownloadResponse('file', 'content'); + } + + + public function testHeaders() { + $headers = $this->response->getHeaders(); + + $this->assertContains('attachment; filename="file"', $headers['Content-Disposition']); + $this->assertContains('content', $headers['Content-Type']); + } + + +} diff --git a/tests/lib/appframework/http/HttpTest.php b/tests/lib/appframework/http/HttpTest.php new file mode 100644 index 00000000000..306bc3caf42 --- /dev/null +++ b/tests/lib/appframework/http/HttpTest.php @@ -0,0 +1,87 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class HttpTest extends \PHPUnit_Framework_TestCase { + + private $server; + private $http; + + protected function setUp(){ + $this->server = array(); + $this->http = new Http($this->server); + } + + + public function testProtocol() { + $header = $this->http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); + $this->assertEquals('HTTP/1.1 307 Temporary Redirect', $header); + } + + + public function testProtocol10() { + $this->http = new Http($this->server, 'HTTP/1.0'); + $header = $this->http->getStatusHeader(Http::STATUS_OK); + $this->assertEquals('HTTP/1.0 200 OK', $header); + } + + + public function testEtagMatchReturnsNotModified() { + $http = new Http(array('HTTP_IF_NONE_MATCH' => 'hi')); + + $header = $http->getStatusHeader(Http::STATUS_OK, null, 'hi'); + $this->assertEquals('HTTP/1.1 304 Not Modified', $header); + } + + + public function testLastModifiedMatchReturnsNotModified() { + $dateTime = new \DateTime(null, new \DateTimeZone('GMT')); + $dateTime->setTimestamp('12'); + + $http = new Http( + array( + 'HTTP_IF_MODIFIED_SINCE' => 'Thu, 01 Jan 1970 00:00:12 +0000') + ); + + $header = $http->getStatusHeader(Http::STATUS_OK, $dateTime); + $this->assertEquals('HTTP/1.1 304 Not Modified', $header); + } + + + + public function testTempRedirectBecomesFoundInHttp10() { + $http = new Http(array(), 'HTTP/1.0'); + + $header = $http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); + $this->assertEquals('HTTP/1.0 302 Found', $header); + } + // TODO: write unittests for http codes + +} diff --git a/tests/lib/appframework/http/JSONResponseTest.php b/tests/lib/appframework/http/JSONResponseTest.php new file mode 100644 index 00000000000..d15e08f6ce1 --- /dev/null +++ b/tests/lib/appframework/http/JSONResponseTest.php @@ -0,0 +1,96 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class JSONResponseTest extends \PHPUnit_Framework_TestCase { + + /** + * @var JSONResponse + */ + private $json; + + protected function setUp() { + $this->json = new JSONResponse(); + } + + + public function testHeader() { + $headers = $this->json->getHeaders(); + $this->assertEquals('application/json; charset=utf-8', $headers['Content-type']); + } + + + public function testSetData() { + $params = array('hi', 'yo'); + $this->json->setData($params); + + $this->assertEquals(array('hi', 'yo'), $this->json->getData()); + } + + + public function testSetRender() { + $params = array('test' => 'hi'); + $this->json->setData($params); + + $expected = '{"test":"hi"}'; + + $this->assertEquals($expected, $this->json->render()); + } + + + public function testRender() { + $params = array('test' => 'hi'); + $this->json->setData($params); + + $expected = '{"test":"hi"}'; + + $this->assertEquals($expected, $this->json->render()); + } + + + public function testShouldHaveXContentHeaderByDefault() { + $headers = $this->json->getHeaders(); + $this->assertEquals('nosniff', $headers['X-Content-Type-Options']); + } + + + public function testConstructorAllowsToSetData() { + $data = array('hi'); + $code = 300; + $response = new JSONResponse($data, $code); + + $expected = '["hi"]'; + $this->assertEquals($expected, $response->render()); + $this->assertEquals($code, $response->getStatus()); + } + +} diff --git a/tests/lib/appframework/http/RedirectResponseTest.php b/tests/lib/appframework/http/RedirectResponseTest.php new file mode 100644 index 00000000000..a8577feed29 --- /dev/null +++ b/tests/lib/appframework/http/RedirectResponseTest.php @@ -0,0 +1,55 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class RedirectResponseTest extends \PHPUnit_Framework_TestCase { + + + protected $response; + + protected function setUp(){ + $this->response = new RedirectResponse('/url'); + } + + + public function testHeaders() { + $headers = $this->response->getHeaders(); + $this->assertEquals('/url', $headers['Location']); + $this->assertEquals(Http::STATUS_TEMPORARY_REDIRECT, + $this->response->getStatus()); + } + + + public function testGetRedirectUrl(){ + $this->assertEquals('/url', $this->response->getRedirectUrl()); + } + + +} diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php new file mode 100644 index 00000000000..c1f56c01636 --- /dev/null +++ b/tests/lib/appframework/http/RequestTest.php @@ -0,0 +1,78 @@ + array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + + // Countable + $this->assertEquals(2, count($request)); + // Array access + $this->assertEquals('Joey', $request['nickname']); + // "Magic" accessors + $this->assertEquals('Joey', $request->{'nickname'}); + $this->assertTrue(isset($request['nickname'])); + $this->assertTrue(isset($request->{'nickname'})); + $this->assertEquals(false, isset($request->{'flickname'})); + // Only testing 'get', but same approach for post, files etc. + $this->assertEquals('Joey', $request->get['nickname']); + // Always returns null if variable not set. + $this->assertEquals(null, $request->{'flickname'}); + } + + // urlParams has precedence over POST which has precedence over GET + public function testPrecedence() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'), + 'urlParams' => array('user' => 'jw', 'name' => 'Johnny Weissmüller'), + ); + + $request = new Request($vars); + + $this->assertEquals(3, count($request)); + $this->assertEquals('Janey', $request->{'nickname'}); + $this->assertEquals('Johnny Weissmüller', $request->{'name'}); + } + + + /** + * @expectedException RuntimeException + */ + public function testImmutableArrayAccess() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + $request['nickname'] = 'Janey'; + } + + /** + * @expectedException RuntimeException + */ + public function testImmutableMagicAccess() { + $vars = array( + 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'), + ); + + $request = new Request($vars); + $request->{'nickname'} = 'Janey'; + } + +} diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php new file mode 100644 index 00000000000..621ba66545f --- /dev/null +++ b/tests/lib/appframework/http/ResponseTest.php @@ -0,0 +1,119 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + + +require_once(__DIR__ . "/../classloader.php"); + + + +class ResponseTest extends \PHPUnit_Framework_TestCase { + + + private $childResponse; + + protected function setUp(){ + $this->childResponse = new Response(); + } + + + public function testAddHeader(){ + $this->childResponse->addHeader('hello', 'world'); + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('world', $headers['hello']); + } + + + public function testAddHeaderValueNullDeletesIt(){ + $this->childResponse->addHeader('hello', 'world'); + $this->childResponse->addHeader('hello', null); + $this->assertEquals(1, count($this->childResponse->getHeaders())); + } + + + public function testCacheHeadersAreDisabledByDefault(){ + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); + } + + + public function testRenderReturnNullByDefault(){ + $this->assertEquals(null, $this->childResponse->render()); + } + + + public function testGetStatus() { + $default = $this->childResponse->getStatus(); + + $this->childResponse->setStatus(Http::STATUS_NOT_FOUND); + + $this->assertEquals(Http::STATUS_OK, $default); + $this->assertEquals(Http::STATUS_NOT_FOUND, $this->childResponse->getStatus()); + } + + + public function testGetEtag() { + $this->childResponse->setEtag('hi'); + $this->assertEquals('hi', $this->childResponse->getEtag()); + } + + + public function testGetLastModified() { + $lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $lastModified->setTimestamp(1); + $this->childResponse->setLastModified($lastModified); + $this->assertEquals($lastModified, $this->childResponse->getLastModified()); + } + + + + public function testCacheSecondsZero() { + $this->childResponse->cacheFor(0); + + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('no-cache, must-revalidate', $headers['Cache-Control']); + } + + + public function testCacheSeconds() { + $this->childResponse->cacheFor(33); + + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('max-age=33, must-revalidate', + $headers['Cache-Control']); + } + + + + public function testEtagLastModifiedHeaders() { + $lastModified = new \DateTime(null, new \DateTimeZone('GMT')); + $lastModified->setTimestamp(1); + $this->childResponse->setLastModified($lastModified); + $headers = $this->childResponse->getHeaders(); + $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); + } + + +} diff --git a/tests/lib/appframework/http/TemplateResponseTest.php b/tests/lib/appframework/http/TemplateResponseTest.php new file mode 100644 index 00000000000..30684725b72 --- /dev/null +++ b/tests/lib/appframework/http/TemplateResponseTest.php @@ -0,0 +1,157 @@ +. + * + */ + + +namespace OC\AppFramework\Http; + +use OC\AppFramework\Core\API; + + +require_once(__DIR__ . "/../classloader.php"); + + +class TemplateResponseTest extends \PHPUnit_Framework_TestCase { + + private $tpl; + private $api; + + protected function setUp() { + $this->api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('test')); + $this->api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + + $this->tpl = new TemplateResponse($this->api, 'home'); + } + + + public function testSetParams(){ + $params = array('hi' => 'yo'); + $this->tpl->setParams($params); + + $this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams()); + } + + + public function testGetTemplateName(){ + $this->assertEquals('home', $this->tpl->getTemplateName()); + } + + + public function testRender(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + + $tpl->render(); + } + + + public function testRenderAssignsParams(){ + $params = array('john' => 'doe'); + + $ocTpl = $this->getMock('Template', array('assign', 'fetchPage')); + $ocTpl->expects($this->once()) + ->method('assign') + ->with($this->equalTo('john'), $this->equalTo('doe')); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + $tpl->setParams($params); + + $tpl->render(); + } + + + public function testRenderDifferentApp(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('user'), $this->equalTo('app2')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home', 'app2'); + + $tpl->render(); + } + + + public function testRenderDifferentRenderAs(){ + $ocTpl = $this->getMock('Template', array('fetchPage')); + $ocTpl->expects($this->once()) + ->method('fetchPage'); + + $api = $this->getMock('OC\AppFramework\Core\API', + array('getAppName', 'getTemplate'), array('app')); + $api->expects($this->any()) + ->method('getAppName') + ->will($this->returnValue('app')); + $api->expects($this->once()) + ->method('getTemplate') + ->with($this->equalTo('home'), $this->equalTo('admin'), $this->equalTo('app')) + ->will($this->returnValue($ocTpl)); + + $tpl = new TemplateResponse($api, 'home'); + $tpl->renderAs('admin'); + + $tpl->render(); + } + + + public function testGetRenderAs(){ + $render = 'myrender'; + $this->tpl->renderAs($render); + $this->assertEquals($render, $this->tpl->getRenderAs()); + } + +} diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php new file mode 100644 index 00000000000..bfa54a48ea3 --- /dev/null +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -0,0 +1,280 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Controller\Controller; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\Response; +use OC\AppFramework\Middleware\Middleware; +use OC\AppFramework\Middleware\MiddlewareDispatcher; + + +require_once(__DIR__ . "/../classloader.php"); + + +// needed to test ordering +class TestMiddleware extends Middleware { + public static $beforeControllerCalled = 0; + public static $afterControllerCalled = 0; + public static $afterExceptionCalled = 0; + public static $beforeOutputCalled = 0; + + public $beforeControllerOrder = 0; + public $afterControllerOrder = 0; + public $afterExceptionOrder = 0; + public $beforeOutputOrder = 0; + + public $controller; + public $methodName; + public $exception; + public $response; + public $output; + + private $beforeControllerThrowsEx; + + public function __construct($beforeControllerThrowsEx) { + self::$beforeControllerCalled = 0; + self::$afterControllerCalled = 0; + self::$afterExceptionCalled = 0; + self::$beforeOutputCalled = 0; + $this->beforeControllerThrowsEx = $beforeControllerThrowsEx; + } + + public function beforeController($controller, $methodName){ + self::$beforeControllerCalled++; + $this->beforeControllerOrder = self::$beforeControllerCalled; + $this->controller = $controller; + $this->methodName = $methodName; + if($this->beforeControllerThrowsEx){ + throw new \Exception(); + } + } + + public function afterException($controller, $methodName, \Exception $exception){ + self::$afterExceptionCalled++; + $this->afterExceptionOrder = self::$afterExceptionCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->exception = $exception; + parent::afterException($controller, $methodName, $exception); + } + + public function afterController($controller, $methodName, Response $response){ + self::$afterControllerCalled++; + $this->afterControllerOrder = self::$afterControllerCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->response = $response; + return parent::afterController($controller, $methodName, $response); + } + + public function beforeOutput($controller, $methodName, $output){ + self::$beforeOutputCalled++; + $this->beforeOutputOrder = self::$beforeOutputCalled; + $this->controller = $controller; + $this->methodName = $methodName; + $this->output = $output; + return parent::beforeOutput($controller, $methodName, $output); + } +} + + +class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { + + private $dispatcher; + + + public function setUp() { + $this->dispatcher = new MiddlewareDispatcher(); + $this->controller = $this->getControllerMock(); + $this->method = 'method'; + $this->response = new Response(); + $this->output = 'hi'; + $this->exception = new \Exception(); + } + + + private function getAPIMock(){ + return $this->getMock('OC\AppFramework\Core\API', + array('getAppName'), array('app')); + } + + + private function getControllerMock(){ + return $this->getMock('OC\AppFramework\Controller\Controller', array('method'), + array($this->getAPIMock(), new Request())); + } + + + private function getMiddleware($beforeControllerThrowsEx=false){ + $m1 = new TestMiddleware($beforeControllerThrowsEx); + $this->dispatcher->registerMiddleware($m1); + return $m1; + } + + + public function testAfterExceptionShouldReturnResponseOfMiddleware(){ + $response = new Response(); + $m1 = $this->getMock('\OC\AppFramework\Middleware\Middleware', + array('afterException', 'beforeController')); + $m1->expects($this->never()) + ->method('afterException'); + + $m2 = $this->getMock('OC\AppFramework\Middleware\Middleware', + array('afterException', 'beforeController')); + $m2->expects($this->once()) + ->method('afterException') + ->will($this->returnValue($response)); + + $this->dispatcher->registerMiddleware($m1); + $this->dispatcher->registerMiddleware($m2); + + $this->dispatcher->beforeController($this->controller, $this->method); + $this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception)); + } + + + public function testAfterExceptionShouldThrowAgainWhenNotHandled(){ + $m1 = new TestMiddleware(false); + $m2 = new TestMiddleware(true); + + $this->dispatcher->registerMiddleware($m1); + $this->dispatcher->registerMiddleware($m2); + + $this->setExpectedException('\Exception'); + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + } + + + public function testBeforeControllerCorrectArguments(){ + $m1 = $this->getMiddleware(); + $this->dispatcher->beforeController($this->controller, $this->method); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + } + + + public function testAfterControllerCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->dispatcher->afterController($this->controller, $this->method, $this->response); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->response, $m1->response); + } + + + public function testAfterExceptionCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->setExpectedException('\Exception'); + + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->exception, $m1->exception); + } + + + public function testBeforeOutputCorrectArguments(){ + $m1 = $this->getMiddleware(); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals($this->controller, $m1->controller); + $this->assertEquals($this->method, $m1->methodName); + $this->assertEquals($this->output, $m1->output); + } + + + public function testBeforeControllerOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->beforeController($this->controller, $this->method); + + $this->assertEquals(1, $m1->beforeControllerOrder); + $this->assertEquals(2, $m2->beforeControllerOrder); + } + + public function testAfterControllerOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->afterController($this->controller, $this->method, $this->response); + + $this->assertEquals(2, $m1->afterControllerOrder); + $this->assertEquals(1, $m2->afterControllerOrder); + } + + + public function testAfterExceptionOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->setExpectedException('\Exception'); + $this->dispatcher->beforeController($this->controller, $this->method); + $this->dispatcher->afterException($this->controller, $this->method, $this->exception); + + $this->assertEquals(1, $m1->afterExceptionOrder); + $this->assertEquals(1, $m2->afterExceptionOrder); + } + + + public function testBeforeOutputOrder(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals(2, $m1->beforeOutputOrder); + $this->assertEquals(1, $m2->beforeOutputOrder); + } + + + public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(){ + $m1 = $this->getMiddleware(); + $m2 = $this->getMiddleware(true); + $m3 = $this->getMock('\OC\AppFramework\Middleware\Middleware'); + $m3->expects($this->never()) + ->method('afterException'); + $m3->expects($this->never()) + ->method('beforeController'); + $m3->expects($this->never()) + ->method('afterController'); + + $this->dispatcher->registerMiddleware($m3); + + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + + $this->assertEquals(2, $m1->beforeOutputOrder); + $this->assertEquals(1, $m2->beforeOutputOrder); + } +} diff --git a/tests/lib/appframework/middleware/MiddlewareTest.php b/tests/lib/appframework/middleware/MiddlewareTest.php new file mode 100644 index 00000000000..1adce6b3d4f --- /dev/null +++ b/tests/lib/appframework/middleware/MiddlewareTest.php @@ -0,0 +1,82 @@ +. + * + */ + + +namespace OC\AppFramework; + +use OC\AppFramework\Http\Request; +use OC\AppFramework\Middleware\Middleware; + + +require_once(__DIR__ . "/../classloader.php"); + + +class ChildMiddleware extends Middleware {}; + + +class MiddlewareTest extends \PHPUnit_Framework_TestCase { + + private $middleware; + private $controller; + private $exception; + private $api; + + protected function setUp(){ + $this->middleware = new ChildMiddleware(); + + $this->api = $this->getMock('OC\AppFramework\Core\API', + array(), array('test')); + + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($this->api, new Request())); + $this->exception = new \Exception(); + $this->response = $this->getMock('OC\AppFramework\Http\Response'); + } + + + public function testBeforeController() { + $this->middleware->beforeController($this->controller, null, $this->exception); + } + + + public function testAfterExceptionRaiseAgainWhenUnhandled() { + $this->setExpectedException('Exception'); + $afterEx = $this->middleware->afterException($this->controller, null, $this->exception); + } + + + public function testAfterControllerReturnResponseWhenUnhandled() { + $response = $this->middleware->afterController($this->controller, null, $this->response); + + $this->assertEquals($this->response, $response); + } + + + public function testBeforeOutputReturnOutputhenUnhandled() { + $output = $this->middleware->beforeOutput($this->controller, null, 'test'); + + $this->assertEquals('test', $output); + } + + +} diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php new file mode 100644 index 00000000000..0b2103564e4 --- /dev/null +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -0,0 +1,388 @@ +. + * + */ + + +namespace OC\AppFramework\Middleware\Security; + +use OC\AppFramework\Http\Http; +use OC\AppFramework\Http\Request; +use OC\AppFramework\Http\RedirectResponse; +use OC\AppFramework\Http\JSONResponse; +use OC\AppFramework\Middleware\Middleware; + + +require_once(__DIR__ . "/../../classloader.php"); + + +class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { + + private $middleware; + private $controller; + private $secException; + private $secAjaxException; + private $request; + + public function setUp() { + $api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($api, new Request())); + + $this->request = new Request(); + $this->middleware = new SecurityMiddleware($api, $this->request); + $this->secException = new SecurityException('hey', false); + $this->secAjaxException = new SecurityException('hey', true); + } + + + private function getAPI(){ + return $this->getMock('OC\AppFramework\Core\API', + array('isLoggedIn', 'passesCSRFCheck', 'isAdminUser', + 'isSubAdminUser', 'activateNavigationEntry', + 'getUserId'), + array('app')); + } + + + private function checkNavEntry($method, $shouldBeActivated=false){ + $api = $this->getAPI(); + + if($shouldBeActivated){ + $api->expects($this->once()) + ->method('activateNavigationEntry'); + } else { + $api->expects($this->never()) + ->method('activateNavigationEntry'); + } + + $sec = new SecurityMiddleware($api, $this->request); + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testSetNavigationEntry(){ + $this->checkNavEntry('testSetNavigationEntry', true); + } + + + private function ajaxExceptionCheck($method, $shouldBeAjax=false){ + $api = $this->getAPI(); + $api->expects($this->any()) + ->method('passesCSRFCheck') + ->will($this->returnValue(false)); + + $sec = new SecurityMiddleware($api, $this->request); + + try { + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + $method); + } catch (SecurityException $ex){ + if($shouldBeAjax){ + $this->assertTrue($ex->isAjax()); + } else { + $this->assertFalse($ex->isAjax()); + } + + } + } + + + /** + * @Ajax + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxException(){ + $this->ajaxExceptionCheck('testAjaxException'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testNoAjaxException(){ + $this->ajaxExceptionCheck('testNoAjaxException'); + } + + + private function ajaxExceptionStatus($method, $test, $status) { + $api = $this->getAPI(); + $api->expects($this->any()) + ->method($test) + ->will($this->returnValue(false)); + + $sec = new SecurityMiddleware($api, $this->request); + + try { + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + $method); + } catch (SecurityException $ex){ + $this->assertEquals($status, $ex->getCode()); + } + } + + /** + * @Ajax + */ + public function testAjaxStatusLoggedInCheck() { + $this->ajaxExceptionStatus( + 'testAjaxStatusLoggedInCheck', + 'isLoggedIn', + Http::STATUS_UNAUTHORIZED + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + */ + public function testAjaxNotAdminCheck() { + $this->ajaxExceptionStatus( + 'testAjaxNotAdminCheck', + 'isAdminUser', + Http::STATUS_FORBIDDEN + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + * @IsAdminExemption + */ + public function testAjaxNotSubAdminCheck() { + $this->ajaxExceptionStatus( + 'testAjaxNotSubAdminCheck', + 'isSubAdminUser', + Http::STATUS_FORBIDDEN + ); + } + + /** + * @Ajax + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxStatusCSRFCheck() { + $this->ajaxExceptionStatus( + 'testAjaxStatusCSRFCheck', + 'passesCSRFCheck', + Http::STATUS_PRECONDITION_FAILED + ); + } + + /** + * @Ajax + * @CSRFExemption + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testAjaxStatusAllGood() { + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isLoggedIn', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isAdminUser', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'isSubAdminUser', + 0 + ); + $this->ajaxExceptionStatus( + 'testAjaxStatusAllGood', + 'passesCSRFCheck', + 0 + ); + } + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testNoChecks(){ + $api = $this->getAPI(); + $api->expects($this->never()) + ->method('passesCSRFCheck') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isAdminUser') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isSubAdminUser') + ->will($this->returnValue(true)); + $api->expects($this->never()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + + $sec = new SecurityMiddleware($api, $this->request); + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', + 'testNoChecks'); + } + + + private function securityCheck($method, $expects, $shouldFail=false){ + $api = $this->getAPI(); + $api->expects($this->once()) + ->method($expects) + ->will($this->returnValue(!$shouldFail)); + + $sec = new SecurityMiddleware($api, $this->request); + + if($shouldFail){ + $this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); + } + + $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); + } + + + /** + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testCsrfCheck(){ + $this->securityCheck('testCsrfCheck', 'passesCSRFCheck'); + } + + + /** + * @IsLoggedInExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testFailCsrfCheck(){ + $this->securityCheck('testFailCsrfCheck', 'passesCSRFCheck', true); + } + + + /** + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testLoggedInCheck(){ + $this->securityCheck('testLoggedInCheck', 'isLoggedIn'); + } + + + /** + * @CSRFExemption + * @IsAdminExemption + * @IsSubAdminExemption + */ + public function testFailLoggedInCheck(){ + $this->securityCheck('testFailLoggedInCheck', 'isLoggedIn', true); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsSubAdminExemption + */ + public function testIsAdminCheck(){ + $this->securityCheck('testIsAdminCheck', 'isAdminUser'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsSubAdminExemption + */ + public function testFailIsAdminCheck(){ + $this->securityCheck('testFailIsAdminCheck', 'isAdminUser', true); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + */ + public function testIsSubAdminCheck(){ + $this->securityCheck('testIsSubAdminCheck', 'isSubAdminUser'); + } + + + /** + * @IsLoggedInExemption + * @CSRFExemption + * @IsAdminExemption + */ + public function testFailIsSubAdminCheck(){ + $this->securityCheck('testFailIsSubAdminCheck', 'isSubAdminUser', true); + } + + + + public function testAfterExceptionNotCaughtThrowsItAgain(){ + $ex = new \Exception(); + $this->setExpectedException('\Exception'); + $this->middleware->afterException($this->controller, 'test', $ex); + } + + + public function testAfterExceptionReturnsRedirect(){ + $api = $this->getMock('OC\AppFramework\Core\API', array(), array('test')); + $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', + array(), array($api, new Request())); + + $this->request = new Request( + array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'))); + $this->middleware = new SecurityMiddleware($api, $this->request); + $response = $this->middleware->afterException($this->controller, 'test', + $this->secException); + + $this->assertTrue($response instanceof RedirectResponse); + } + + + public function testAfterAjaxExceptionReturnsJSONError(){ + $response = $this->middleware->afterException($this->controller, 'test', + $this->secAjaxException); + + $this->assertTrue($response instanceof JSONResponse); + } + + +} diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php new file mode 100644 index 00000000000..92ad461471d --- /dev/null +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -0,0 +1,214 @@ + array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + public function testSimpleRouteWithMissingVerb() + { + $routes = array('routes' => array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + public function testSimpleRouteWithLowercaseVerb() + { + $routes = array('routes' => array( + array('name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + + /** + * @expectedException \UnexpectedValueException + */ + public function testSimpleRouteWithBrokenName() + { + $routes = array('routes' => array( + array('name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + + public function testSimpleRouteWithUnderScoreNames() + { + $routes = array('routes' => array( + array('name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete') + )); + + $this->assertSimpleRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); + } + + public function testResource() + { + $routes = array('resources' => array('accounts' => array('url' => '/accounts'))); + + $this->assertResource($routes, 'accounts', '/accounts', 'AccountsController', 'accountId'); + } + + public function testResourceWithUnderScoreName() + { + $routes = array('resources' => array('admin_accounts' => array('url' => '/admin/accounts'))); + + $this->assertResource($routes, 'admin_accounts', '/admin/accounts', 'AdminAccountsController', 'adminAccountId'); + } + + private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName) + { + // route mocks + $route = $this->mockRoute($verb, $controllerName, $actionName); + + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // we expect create to be called once: + $router + ->expects($this->once()) + ->method('create') + ->with($this->equalTo('app1.' . $name), $this->equalTo($url)) + ->will($this->returnValue($route)); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + + private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) + { + // router mock + $router = $this->getMock("\OC_Router", array('create')); + + // route mocks + $indexRoute = $this->mockRoute('GET', $controllerName, 'index'); + $showRoute = $this->mockRoute('GET', $controllerName, 'show'); + $createRoute = $this->mockRoute('POST', $controllerName, 'create'); + $updateRoute = $this->mockRoute('PUT', $controllerName, 'update'); + $destroyRoute = $this->mockRoute('DELETE', $controllerName, 'destroy'); + + $urlWithParam = $url . '/{' . $paramName . '}'; + + // we expect create to be called once: + $router + ->expects($this->at(0)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.index'), $this->equalTo($url)) + ->will($this->returnValue($indexRoute)); + + $router + ->expects($this->at(1)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($showRoute)); + + $router + ->expects($this->at(2)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.create'), $this->equalTo($url)) + ->will($this->returnValue($createRoute)); + + $router + ->expects($this->at(3)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($updateRoute)); + + $router + ->expects($this->at(4)) + ->method('create') + ->with($this->equalTo('app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)) + ->will($this->returnValue($destroyRoute)); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $yaml); + + $config->register(); + } + + /** + * @param $verb + * @param $controllerName + * @param $actionName + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function mockRoute($verb, $controllerName, $actionName) + { + $container = new DIContainer('app1'); + $route = $this->getMock("\OC_Route", array('method', 'action'), array(), '', false); + $route + ->expects($this->exactly(1)) + ->method('method') + ->with($this->equalTo($verb)) + ->will($this->returnValue($route)); + + $route + ->expects($this->exactly(1)) + ->method('action') + ->with($this->equalTo(new RouteActionHandler($container, $controllerName, $actionName))) + ->will($this->returnValue($route)); + return $route; + } + +} + +/* +# +# sample routes.yaml for ownCloud +# +# the section simple describes one route + +routes: + - name: folders#open + url: /folders/{folderId}/open + verb: GET + # controller: name.split()[0] + # action: name.split()[1] + +# for a resource following actions will be generated: +# - index +# - create +# - show +# - update +# - destroy +# - new +resources: + accounts: + url: /accounts + + folders: + url: /accounts/{accountId}/folders + # actions can be used to define additional actions on the resource + actions: + - name: validate + verb: GET + on-collection: false + + * */ diff --git a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php new file mode 100644 index 00000000000..bcdcf3de37b --- /dev/null +++ b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php @@ -0,0 +1,58 @@ +. + * + */ + + +namespace OC\AppFramework\Utility; + + +require_once __DIR__ . "/../classloader.php"; + + +class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { + + + /** + * @Annotation + */ + public function testReadAnnotation(){ + $reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', + 'testReadAnnotation'); + + $this->assertTrue($reader->hasAnnotation('Annotation')); + } + + + /** + * @Annotation + * @param test + */ + public function testReadAnnotationNoLowercase(){ + $reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', + 'testReadAnnotationNoLowercase'); + + $this->assertTrue($reader->hasAnnotation('Annotation')); + $this->assertFalse($reader->hasAnnotation('param')); + } + + +} -- cgit v1.2.3 From 72e1a8d83b3a21875cac6948879471661d120c52 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 12:47:23 +0200 Subject: fixing require to Pimple --- lib/appframework/dependencyinjection/dicontainer.php | 2 +- tests/lib/appframework/AppTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 34f64e72cb9..d6cf4d55020 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -34,7 +34,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Utility\TimeFactory; // register 3rdparty autoloaders -require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; /** diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index 000094d07c8..6e647f68e6f 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -29,7 +29,7 @@ use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; // FIXME: loading pimpl correctly from 3rdparty repo -require_once __DIR__ . '/../../../../3rdparty/Pimple/Pimple.php'; +require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; require_once __DIR__ . "/classloader.php"; -- cgit v1.2.3 From 0fa8f380767369b4aa85f5944a8e921009b1ed27 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 16:51:12 +0200 Subject: fixing broken test --- tests/lib/appframework/AppTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index 6e647f68e6f..dcf0e6f77e3 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -46,7 +46,7 @@ class AppTest extends \PHPUnit_Framework_TestCase { private $controllerMethod; protected function setUp() { - $this->container = new \Pimple(); + $this->container = new \OC\AppFramework\DependencyInjection\DIContainer('test'); $this->controller = $this->getMockBuilder( 'OC\AppFramework\Controller\Controller') ->disableOriginalConstructor() -- cgit v1.2.3 From 93194bb39617d4b11a0a84b8cd4caf0491155961 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 17:21:14 +0200 Subject: Introducing IContainer into public api --- .../dependencyinjection/dicontainer.php | 22 +++++------ lib/appframework/utility/simplecontainer.php | 44 ++++++++++++++++++++++ tests/lib/appframework/classloader.php | 9 +++++ 3 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 lib/appframework/utility/simplecontainer.php (limited to 'tests') diff --git a/lib/appframework/dependencyinjection/dicontainer.php b/lib/appframework/dependencyinjection/dicontainer.php index 69c645b1be3..88ad2cd414a 100644 --- a/lib/appframework/dependencyinjection/dicontainer.php +++ b/lib/appframework/dependencyinjection/dicontainer.php @@ -30,19 +30,11 @@ use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; use OC\AppFramework\Middleware\Security\SecurityMiddleware; +use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; -// register 3rdparty autoloaders -require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; - -/** - * This class extends Pimple (http://pimple.sensiolabs.org/) for reusability - * To use this class, extend your own container from this. Should you require it - * you can overwrite the dependencies with your own classes by simply redefining - * a dependency - */ -class DIContainer extends \Pimple { +class DIContainer extends SimpleContainer { /** @@ -61,8 +53,14 @@ class DIContainer extends \Pimple { * Http */ $this['Request'] = $this->share(function($c) { - $params = json_decode(file_get_contents('php://input'), true); - $params = is_array($params) ? $params: array(); + + $params = array(); + + // we json decode the body only in case of content type json + if (isset($_SERVER['CONTENT_TYPE']) && stripos($_SERVER['CONTENT_TYPE'],'json') === true ) { + $params = json_decode(file_get_contents('php://input'), true); + $params = is_array($params) ? $params: array(); + } return new Request( array( diff --git a/lib/appframework/utility/simplecontainer.php b/lib/appframework/utility/simplecontainer.php new file mode 100644 index 00000000000..04b6cd727b8 --- /dev/null +++ b/lib/appframework/utility/simplecontainer.php @@ -0,0 +1,44 @@ +offsetGet($name); + } + + function registerParameter($name, $value) + { + $this[$name] = $value; + } + + /** + * The given closure is call the first time the given service is queried. + * The closure has to return the instance for the given service. + * Created instance will be cached in case $shared is true. + * + * @param string $name name of the service to register another backend for + * @param callable $closure the closure to be called on service creation + */ + function registerService($name, \Closure $closure, $shared = true) + { + if ($shared) { + $this[$name] = \Pimple::share($closure); + } else { + $this[$name] = $closure; + } + } +} diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php index ae485e67b2c..cd9f893df30 100644 --- a/tests/lib/appframework/classloader.php +++ b/tests/lib/appframework/classloader.php @@ -32,6 +32,15 @@ spl_autoload_register(function ($className){ } } + if (strpos($className, 'OCP\\') === 0) { + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $relPath = __DIR__ . '/../../../lib/public' . $path; + + if(file_exists($relPath)){ + require_once $relPath; + } + } + // FIXME: this will most probably not work anymore if (strpos($className, 'OCA\\') === 0) { -- cgit v1.2.3 From 395deacc6760564544a76338023d9b0bf39e0bfe Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Tue, 20 Aug 2013 21:21:21 +0200 Subject: reducing controller annotations to: @PublicPage - No user logon is expected @NoAdminRequired - the login user requires no admin rights @NoCSRFRequired - the incoming request will not check for CSRF token --- .../middleware/security/securitymiddleware.php | 19 +-- .../middleware/security/SecurityMiddlewareTest.php | 156 +++++---------------- 2 files changed, 41 insertions(+), 134 deletions(-) (limited to 'tests') diff --git a/lib/appframework/middleware/security/securitymiddleware.php b/lib/appframework/middleware/security/securitymiddleware.php index 7a715f309a0..52818b1b53e 100644 --- a/lib/appframework/middleware/security/securitymiddleware.php +++ b/lib/appframework/middleware/security/securitymiddleware.php @@ -77,25 +77,20 @@ class SecurityMiddleware extends Middleware { $this->api->activateNavigationEntry(); // security checks - if(!$annotationReader->hasAnnotation('IsLoggedInExemption')) { + $isPublicPage = $annotationReader->hasAnnotation('PublicPage'); + if(!$isPublicPage) { if(!$this->api->isLoggedIn()) { throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); } - } - - if(!$annotationReader->hasAnnotation('IsAdminExemption')) { - if(!$this->api->isAdminUser($this->api->getUserId())) { - throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); - } - } - if(!$annotationReader->hasAnnotation('IsSubAdminExemption')) { - if(!$this->api->isSubAdminUser($this->api->getUserId())) { - throw new SecurityException('Logged in user must be a subadmin', Http::STATUS_FORBIDDEN); + if(!$annotationReader->hasAnnotation('NoAdminRequired')) { + if(!$this->api->isAdminUser($this->api->getUserId())) { + throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); + } } } - if(!$annotationReader->hasAnnotation('CSRFExemption')) { + if(!$annotationReader->hasAnnotation('NoCSRFRequired')) { if(!$this->api->passesCSRFCheck()) { throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); } diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php index 0b2103564e4..90a19c9999d 100644 --- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -80,67 +80,27 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testSetNavigationEntry(){ $this->checkNavEntry('testSetNavigationEntry', true); } - private function ajaxExceptionCheck($method, $shouldBeAjax=false){ - $api = $this->getAPI(); - $api->expects($this->any()) - ->method('passesCSRFCheck') - ->will($this->returnValue(false)); - - $sec = new SecurityMiddleware($api, $this->request); - - try { - $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', - $method); - } catch (SecurityException $ex){ - if($shouldBeAjax){ - $this->assertTrue($ex->isAjax()); - } else { - $this->assertFalse($ex->isAjax()); - } - - } - } - - - /** - * @Ajax - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption - */ - public function testAjaxException(){ - $this->ajaxExceptionCheck('testAjaxException'); - } - - - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption - */ - public function testNoAjaxException(){ - $this->ajaxExceptionCheck('testNoAjaxException'); - } - - private function ajaxExceptionStatus($method, $test, $status) { $api = $this->getAPI(); $api->expects($this->any()) ->method($test) ->will($this->returnValue(false)); + // isAdminUser requires isLoggedIn call to return true + if ($test === 'isAdminUser') { + $api->expects($this->any()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + } + $sec = new SecurityMiddleware($api, $this->request); try { @@ -151,9 +111,6 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } } - /** - * @Ajax - */ public function testAjaxStatusLoggedInCheck() { $this->ajaxExceptionStatus( 'testAjaxStatusLoggedInCheck', @@ -163,8 +120,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @IsLoggedInExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testAjaxNotAdminCheck() { $this->ajaxExceptionStatus( @@ -175,23 +132,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @IsLoggedInExemption - * @IsAdminExemption - */ - public function testAjaxNotSubAdminCheck() { - $this->ajaxExceptionStatus( - 'testAjaxNotSubAdminCheck', - 'isSubAdminUser', - Http::STATUS_FORBIDDEN - ); - } - - /** - * @Ajax - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testAjaxStatusCSRFCheck() { $this->ajaxExceptionStatus( @@ -202,11 +143,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { } /** - * @Ajax - * @CSRFExemption - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testAjaxStatusAllGood() { $this->ajaxExceptionStatus( @@ -231,11 +169,10 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { ); } + /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage + * @NoCSRFRequired */ public function testNoChecks(){ $api = $this->getAPI(); @@ -245,9 +182,6 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { $api->expects($this->never()) ->method('isAdminUser') ->will($this->returnValue(true)); - $api->expects($this->never()) - ->method('isSubAdminUser') - ->will($this->returnValue(true)); $api->expects($this->never()) ->method('isLoggedIn') ->will($this->returnValue(true)); @@ -264,10 +198,19 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { ->method($expects) ->will($this->returnValue(!$shouldFail)); + // admin check requires login + if ($expects === 'isAdminUser') { + $api->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + } + $sec = new SecurityMiddleware($api, $this->request); if($shouldFail){ $this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); + } else { + $this->setExpectedException(null); } $sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); @@ -275,9 +218,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testCsrfCheck(){ $this->securityCheck('testCsrfCheck', 'passesCSRFCheck'); @@ -285,9 +226,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @PublicPage */ public function testFailCsrfCheck(){ $this->securityCheck('testFailCsrfCheck', 'passesCSRFCheck', true); @@ -295,9 +234,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testLoggedInCheck(){ $this->securityCheck('testLoggedInCheck', 'isLoggedIn'); @@ -305,9 +243,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @CSRFExemption - * @IsAdminExemption - * @IsSubAdminExemption + * @NoCSRFRequired + * @NoAdminRequired */ public function testFailLoggedInCheck(){ $this->securityCheck('testFailLoggedInCheck', 'isLoggedIn', true); @@ -315,9 +252,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsSubAdminExemption + * @NoCSRFRequired */ public function testIsAdminCheck(){ $this->securityCheck('testIsAdminCheck', 'isAdminUser'); @@ -325,36 +260,13 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsSubAdminExemption + * @NoCSRFRequired */ public function testFailIsAdminCheck(){ $this->securityCheck('testFailIsAdminCheck', 'isAdminUser', true); } - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - */ - public function testIsSubAdminCheck(){ - $this->securityCheck('testIsSubAdminCheck', 'isSubAdminUser'); - } - - - /** - * @IsLoggedInExemption - * @CSRFExemption - * @IsAdminExemption - */ - public function testFailIsSubAdminCheck(){ - $this->securityCheck('testFailIsSubAdminCheck', 'isSubAdminUser', true); - } - - - public function testAfterExceptionNotCaughtThrowsItAgain(){ $ex = new \Exception(); $this->setExpectedException('\Exception'); -- cgit v1.2.3 From 33db8a3089760947eec93149a2029164b676eae8 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 00:41:20 +0200 Subject: kill superfluent classloader from tests - this approach might be of interest within the apps --- tests/lib/appframework/AppTest.php | 2 +- tests/lib/appframework/classloader.php | 54 ---------------------- .../lib/appframework/controller/ControllerTest.php | 5 +- .../dependencyinjection/DIContainerTest.php | 2 +- tests/lib/appframework/http/DispatcherTest.php | 6 +-- .../lib/appframework/http/DownloadResponseTest.php | 2 +- tests/lib/appframework/http/HttpTest.php | 2 +- tests/lib/appframework/http/JSONResponseTest.php | 4 +- .../lib/appframework/http/RedirectResponseTest.php | 2 +- tests/lib/appframework/http/RequestTest.php | 2 - tests/lib/appframework/http/ResponseTest.php | 7 +-- .../lib/appframework/http/TemplateResponseTest.php | 12 +++-- .../middleware/MiddlewareDispatcherTest.php | 6 +-- .../lib/appframework/middleware/MiddlewareTest.php | 11 +++-- .../middleware/security/SecurityMiddlewareTest.php | 6 +-- tests/lib/appframework/routing/RoutingTest.php | 1 - .../utility/MethodAnnotationReaderTest.php | 3 -- 17 files changed, 33 insertions(+), 94 deletions(-) delete mode 100644 tests/lib/appframework/classloader.php (limited to 'tests') diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index dcf0e6f77e3..e8ae8c8f673 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -30,7 +30,7 @@ use OC\AppFramework\Middleware\MiddlewareDispatcher; // FIXME: loading pimpl correctly from 3rdparty repo require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; -require_once __DIR__ . "/classloader.php"; +//require_once __DIR__ . "/classloader.php"; class AppTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/classloader.php b/tests/lib/appframework/classloader.php deleted file mode 100644 index cd9f893df30..00000000000 --- a/tests/lib/appframework/classloader.php +++ /dev/null @@ -1,54 +0,0 @@ -. - * - */ - -// to execute without ownCloud, we need to create our own class loader -spl_autoload_register(function ($className){ - if (strpos($className, 'OC\\AppFramework') === 0) { - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../../../lib/' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } - - if (strpos($className, 'OCP\\') === 0) { - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../../../lib/public' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } - - // FIXME: this will most probably not work anymore - if (strpos($className, 'OCA\\') === 0) { - - $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - $relPath = __DIR__ . '/../..' . $path; - - if(file_exists($relPath)){ - require_once $relPath; - } - } -}); diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php index d8357c2a685..246371d249c 100644 --- a/tests/lib/appframework/controller/ControllerTest.php +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -25,12 +25,11 @@ namespace Test\AppFramework\Controller; use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\JSONResponse; -use OC\AppFramework\Http\TemplateResponse; use OC\AppFramework\Controller\Controller; +use OCP\AppFramework\Http\TemplateResponse; -require_once(__DIR__ . "/../classloader.php"); +//require_once __DIR__ . "/../classloader.php"; class ChildController extends Controller {}; diff --git a/tests/lib/appframework/dependencyinjection/DIContainerTest.php b/tests/lib/appframework/dependencyinjection/DIContainerTest.php index ce346f0a763..25fdd202839 100644 --- a/tests/lib/appframework/dependencyinjection/DIContainerTest.php +++ b/tests/lib/appframework/dependencyinjection/DIContainerTest.php @@ -29,7 +29,7 @@ namespace OC\AppFramework\DependencyInjection; use \OC\AppFramework\Http\Request; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class DIContainerTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/http/DispatcherTest.php b/tests/lib/appframework/http/DispatcherTest.php index 2e3db110504..849b0ca97a6 100644 --- a/tests/lib/appframework/http/DispatcherTest.php +++ b/tests/lib/appframework/http/DispatcherTest.php @@ -27,7 +27,7 @@ namespace OC\AppFramework\Http; use OC\AppFramework\Core\API; use OC\AppFramework\Middleware\MiddlewareDispatcher; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class DispatcherTest extends \PHPUnit_Framework_TestCase { @@ -69,7 +69,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { $this->http, $this->middlewareDispatcher); $this->response = $this->getMockBuilder( - '\OC\AppFramework\Http\Response') + '\OCP\AppFramework\Http\Response') ->disableOriginalConstructor() ->getMock(); @@ -207,7 +207,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { $out = 'yo'; $httpHeaders = 'Http'; $responseHeaders = array('hell' => 'yeah'); - $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); + $this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); $this->setExpectedException('\Exception'); $response = $this->dispatcher->dispatch($this->controller, diff --git a/tests/lib/appframework/http/DownloadResponseTest.php b/tests/lib/appframework/http/DownloadResponseTest.php index 103cfe7588c..64fe7992b6a 100644 --- a/tests/lib/appframework/http/DownloadResponseTest.php +++ b/tests/lib/appframework/http/DownloadResponseTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); class ChildDownloadResponse extends DownloadResponse {}; diff --git a/tests/lib/appframework/http/HttpTest.php b/tests/lib/appframework/http/HttpTest.php index 306bc3caf42..382d511b116 100644 --- a/tests/lib/appframework/http/HttpTest.php +++ b/tests/lib/appframework/http/HttpTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/JSONResponseTest.php b/tests/lib/appframework/http/JSONResponseTest.php index d15e08f6ce1..534c54cbcee 100644 --- a/tests/lib/appframework/http/JSONResponseTest.php +++ b/tests/lib/appframework/http/JSONResponseTest.php @@ -27,7 +27,9 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\JSONResponse; + +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/RedirectResponseTest.php b/tests/lib/appframework/http/RedirectResponseTest.php index a8577feed29..1946655b0fa 100644 --- a/tests/lib/appframework/http/RedirectResponseTest.php +++ b/tests/lib/appframework/http/RedirectResponseTest.php @@ -25,7 +25,7 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); +//require_once(__DIR__ . "/../classloader.php"); diff --git a/tests/lib/appframework/http/RequestTest.php b/tests/lib/appframework/http/RequestTest.php index c1f56c01636..0371c870cf2 100644 --- a/tests/lib/appframework/http/RequestTest.php +++ b/tests/lib/appframework/http/RequestTest.php @@ -9,8 +9,6 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); - class RequestTest extends \PHPUnit_Framework_TestCase { public function testRequestAccessors() { diff --git a/tests/lib/appframework/http/ResponseTest.php b/tests/lib/appframework/http/ResponseTest.php index 621ba66545f..7e09086f801 100644 --- a/tests/lib/appframework/http/ResponseTest.php +++ b/tests/lib/appframework/http/ResponseTest.php @@ -25,13 +25,14 @@ namespace OC\AppFramework\Http; -require_once(__DIR__ . "/../classloader.php"); - +use OCP\AppFramework\Http\Response; class ResponseTest extends \PHPUnit_Framework_TestCase { - + /** + * @var \OCP\AppFramework\Http\Response + */ private $childResponse; protected function setUp(){ diff --git a/tests/lib/appframework/http/TemplateResponseTest.php b/tests/lib/appframework/http/TemplateResponseTest.php index 30684725b72..3c6d29cd339 100644 --- a/tests/lib/appframework/http/TemplateResponseTest.php +++ b/tests/lib/appframework/http/TemplateResponseTest.php @@ -24,15 +24,19 @@ namespace OC\AppFramework\Http; -use OC\AppFramework\Core\API; - - -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\TemplateResponse; class TemplateResponseTest extends \PHPUnit_Framework_TestCase { + /** + * @var \OCP\AppFramework\Http\TemplateResponse + */ private $tpl; + + /** + * @var \OCP\AppFramework\IApi + */ private $api; protected function setUp() { diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php index bfa54a48ea3..d1b2fedee58 100644 --- a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -24,14 +24,10 @@ namespace OC\AppFramework; -use OC\AppFramework\Controller\Controller; use OC\AppFramework\Http\Request; -use OC\AppFramework\Http\Response; use OC\AppFramework\Middleware\Middleware; use OC\AppFramework\Middleware\MiddlewareDispatcher; - - -require_once(__DIR__ . "/../classloader.php"); +use OCP\AppFramework\Http\Response; // needed to test ordering diff --git a/tests/lib/appframework/middleware/MiddlewareTest.php b/tests/lib/appframework/middleware/MiddlewareTest.php index 1adce6b3d4f..5e2930ac6a3 100644 --- a/tests/lib/appframework/middleware/MiddlewareTest.php +++ b/tests/lib/appframework/middleware/MiddlewareTest.php @@ -28,14 +28,14 @@ use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\Middleware; -require_once(__DIR__ . "/../classloader.php"); - - class ChildMiddleware extends Middleware {}; class MiddlewareTest extends \PHPUnit_Framework_TestCase { + /** + * @var Middleware + */ private $middleware; private $controller; private $exception; @@ -50,12 +50,13 @@ class MiddlewareTest extends \PHPUnit_Framework_TestCase { $this->controller = $this->getMock('OC\AppFramework\Controller\Controller', array(), array($this->api, new Request())); $this->exception = new \Exception(); - $this->response = $this->getMock('OC\AppFramework\Http\Response'); + $this->response = $this->getMock('OCP\AppFramework\Http\Response'); } public function testBeforeController() { - $this->middleware->beforeController($this->controller, null, $this->exception); + $this->middleware->beforeController($this->controller, null); + $this->assertNull(null); } diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php index 90a19c9999d..3ed44282a7b 100644 --- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -27,11 +27,7 @@ namespace OC\AppFramework\Middleware\Security; use OC\AppFramework\Http\Http; use OC\AppFramework\Http\Request; use OC\AppFramework\Http\RedirectResponse; -use OC\AppFramework\Http\JSONResponse; -use OC\AppFramework\Middleware\Middleware; - - -require_once(__DIR__ . "/../../classloader.php"); +use OCP\AppFramework\Http\JSONResponse; class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/routing/RoutingTest.php b/tests/lib/appframework/routing/RoutingTest.php index 92ad461471d..a7aa922db12 100644 --- a/tests/lib/appframework/routing/RoutingTest.php +++ b/tests/lib/appframework/routing/RoutingTest.php @@ -5,7 +5,6 @@ namespace OC\AppFramework\Routing; use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\routing\RouteConfig; -require_once(__DIR__ . "/../classloader.php"); class RouteConfigTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php index bcdcf3de37b..c68812aa5c7 100644 --- a/tests/lib/appframework/utility/MethodAnnotationReaderTest.php +++ b/tests/lib/appframework/utility/MethodAnnotationReaderTest.php @@ -25,9 +25,6 @@ namespace OC\AppFramework\Utility; -require_once __DIR__ . "/../classloader.php"; - - class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { -- cgit v1.2.3 From aa979f5dff4234a3db9e6fb1ddc50335c04c194b Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 21 Aug 2013 00:44:39 +0200 Subject: cleanup of tests --- tests/lib/appframework/AppTest.php | 8 -------- .../middleware/MiddlewareDispatcherTest.php | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/lib/appframework/AppTest.php b/tests/lib/appframework/AppTest.php index e8ae8c8f673..80abaefc43b 100644 --- a/tests/lib/appframework/AppTest.php +++ b/tests/lib/appframework/AppTest.php @@ -24,14 +24,6 @@ namespace OC\AppFramework; -use OC\AppFramework\Http\Request; -use OC\AppFramework\Core\API; -use OC\AppFramework\Middleware\MiddlewareDispatcher; - -// FIXME: loading pimpl correctly from 3rdparty repo -require_once __DIR__ . '/../../../3rdparty/Pimple/Pimple.php'; -//require_once __DIR__ . "/classloader.php"; - class AppTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php index d1b2fedee58..43727846dcf 100644 --- a/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/appframework/middleware/MiddlewareDispatcherTest.php @@ -99,6 +99,15 @@ class TestMiddleware extends Middleware { class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { + public $exception; + public $response; + private $out; + private $method; + private $controller; + + /** + * @var MiddlewareDispatcher + */ private $dispatcher; @@ -107,7 +116,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $this->controller = $this->getControllerMock(); $this->method = 'method'; $this->response = new Response(); - $this->output = 'hi'; + $this->out = 'hi'; $this->exception = new \Exception(); } @@ -202,11 +211,11 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { public function testBeforeOutputCorrectArguments(){ $m1 = $this->getMiddleware(); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals($this->controller, $m1->controller); $this->assertEquals($this->method, $m1->methodName); - $this->assertEquals($this->output, $m1->output); + $this->assertEquals($this->out, $m1->output); } @@ -248,7 +257,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); @@ -268,7 +277,7 @@ class MiddlewareDispatcherTest extends \PHPUnit_Framework_TestCase { $this->dispatcher->registerMiddleware($m3); - $this->dispatcher->beforeOutput($this->controller, $this->method, $this->output); + $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); $this->assertEquals(2, $m1->beforeOutputOrder); $this->assertEquals(1, $m2->beforeOutputOrder); -- cgit v1.2.3 From fe86182dac387817258942a46905f2b801862d4d Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 17:46:33 +0200 Subject: OC_Cache namespace changes and add UserCache to server container. Refs #4863 --- lib/base.php | 4 +-- lib/cache.php | 8 +++-- lib/cache/broker.php | 4 ++- lib/cache/file.php | 13 +++---- lib/cache/fileglobal.php | 7 ++-- lib/cache/fileglobalgc.php | 5 +-- lib/cache/usercache.php | 77 +++++++++++++++++++++++++++++++++++++++++ lib/filechunking.php | 2 +- lib/public/icache.php | 55 +++++++++++++++++++++++++++++ lib/public/iservercontainer.php | 7 ++++ lib/server.php | 34 +++++++++++------- tests/lib/cache/file.php | 30 ++++++++-------- tests/lib/cache/usercache.php | 68 ++++++++++++++++++++++++++++++++++++ 13 files changed, 270 insertions(+), 44 deletions(-) create mode 100644 lib/cache/usercache.php create mode 100644 lib/public/icache.php create mode 100644 tests/lib/cache/usercache.php (limited to 'tests') diff --git a/lib/base.php b/lib/base.php index 1720a5fd7e1..520be11bc52 100644 --- a/lib/base.php +++ b/lib/base.php @@ -564,11 +564,11 @@ class OC { if (OC_Config::getValue('installed', false)) { //don't try to do this before we are properly setup // register cache cleanup jobs try { //if this is executed before the upgrade to the new backgroundjob system is completed it will throw an exception - \OCP\BackgroundJob::registerJob('OC_Cache_FileGlobalGC'); + \OCP\BackgroundJob::registerJob('OC\Cache\FileGlobalGC'); } catch (Exception $e) { } - OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener'); + OC_Hook::connect('OC_User', 'post_login', 'OC\Cache\File', 'loginListener'); } } diff --git a/lib/cache.php b/lib/cache.php index 48b9964ba9d..c99663a0ca5 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class OC_Cache { +namespace OC\Cache; + +class Cache { /** * @var OC_Cache $user_cache */ @@ -22,7 +24,7 @@ class OC_Cache { */ static public function getGlobalCache() { if (!self::$global_cache) { - self::$global_cache = new OC_Cache_FileGlobal(); + self::$global_cache = new FileGlobal(); } return self::$global_cache; } @@ -33,7 +35,7 @@ class OC_Cache { */ static public function getUserCache() { if (!self::$user_cache) { - self::$user_cache = new OC_Cache_File(); + self::$user_cache = new File(); } return self::$user_cache; } diff --git a/lib/cache/broker.php b/lib/cache/broker.php index a161dbfa3bb..b7f1b67a6d3 100644 --- a/lib/cache/broker.php +++ b/lib/cache/broker.php @@ -6,7 +6,9 @@ * See the COPYING-README file. */ -class OC_Cache_Broker { +namespace OC\Cache; + +class Broker { protected $fast_cache; protected $slow_cache; diff --git a/lib/cache/file.php b/lib/cache/file.php index 361138e4736..2ab914d17b8 100644 --- a/lib/cache/file.php +++ b/lib/cache/file.php @@ -6,24 +6,25 @@ * See the COPYING-README file. */ +namespace OC\Cache; -class OC_Cache_File{ +class File { protected $storage; protected function getStorage() { if (isset($this->storage)) { return $this->storage; } - if(OC_User::isLoggedIn()) { - \OC\Files\Filesystem::initMountPoints(OC_User::getUser()); + if(\OC_User::isLoggedIn()) { + \OC\Files\Filesystem::initMountPoints(\OC_User::getUser()); $subdir = 'cache'; - $view = new \OC\Files\View('/'.OC_User::getUser()); + $view = new \OC\Files\View('/' . \OC_User::getUser()); if(!$view->file_exists($subdir)) { $view->mkdir($subdir); } - $this->storage = new \OC\Files\View('/'.OC_User::getUser().'/'.$subdir); + $this->storage = new \OC\Files\View('/' . \OC_User::getUser().'/'.$subdir); return $this->storage; }else{ - OC_Log::write('core', 'Can\'t get cache storage, user not logged in', OC_Log::ERROR); + \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); return false; } } diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php index c0bd8e45f39..9ca17402933 100644 --- a/lib/cache/fileglobal.php +++ b/lib/cache/fileglobal.php @@ -6,8 +6,9 @@ * See the COPYING-README file. */ +namespace OC\Cache; -class OC_Cache_FileGlobal{ +class FileGlobal { static protected function getCacheDir() { $cache_dir = get_temp_dir().'/owncloud-'.OC_Util::getInstanceId().'/'; if (!is_dir($cache_dir)) { @@ -80,13 +81,13 @@ class OC_Cache_FileGlobal{ } static public function gc() { - $last_run = OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); + $last_run = \OC_AppConfig::getValue('core', 'global_cache_gc_lastrun', 0); $now = time(); if (($now - $last_run) < 300) { // only do cleanup every 5 minutes return; } - OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); + \OC_AppConfig::setValue('core', 'global_cache_gc_lastrun', $now); $cache_dir = self::getCacheDir(); if($cache_dir and is_dir($cache_dir)) { $dh=opendir($cache_dir); diff --git a/lib/cache/fileglobalgc.php b/lib/cache/fileglobalgc.php index a29c31f9063..399dd5e6f94 100644 --- a/lib/cache/fileglobalgc.php +++ b/lib/cache/fileglobalgc.php @@ -1,8 +1,9 @@ userCache = new File(); + } + + /** + * Get a value from the user cache + * + * @param string $key + * @return mixed + */ + public function get($key) { + return $this->userCache->get($key); + } + + /** + * Set a value in the user cache + * + * @param string $key + * @param mixed $value + * @param int $ttl Time To Live in seconds. Defaults to 60*60*24 + * @return bool + */ + public function set($key, $value, $ttl = 0) { + if (empty($key)) { + return false; + } + return $this->userCache->set($key, $value, $ttl); + } + + /** + * Check if a value is set in the user cache + * + * @param string $key + * @return bool + */ + public function hasKey($key) { + return $this->userCache->hasKey($key); + } + + /** + * Remove an item from the user cache + * + * @param string $key + * @return bool + */ + public function remove($key) { + return $this->userCache->remove($key); + } + + /** + * clear the user cache of all entries starting with a prefix + * @param string prefix (optional) + * @return bool + */ + public function clear($prefix = '') { + return $this->userCache->clear($prefix); + } +} diff --git a/lib/filechunking.php b/lib/filechunking.php index e6d69273a44..313a6ee87d2 100644 --- a/lib/filechunking.php +++ b/lib/filechunking.php @@ -29,7 +29,7 @@ class OC_FileChunking { protected function getCache() { if (!isset($this->cache)) { - $this->cache = new OC_Cache_File(); + $this->cache = new \OC\Cache\File(); } return $this->cache; } diff --git a/lib/public/icache.php b/lib/public/icache.php new file mode 100644 index 00000000000..202459f7c24 --- /dev/null +++ b/lib/public/icache.php @@ -0,0 +1,55 @@ +registerService('ContactsManager', function($c){ + $this->registerService('ContactsManager', function($c) { return new ContactsManager(); }); - $this->registerService('Request', function($c){ + $this->registerService('Request', function($c) { $params = array(); // we json decode the body only in case of content type json @@ -46,10 +46,10 @@ class Server extends SimpleContainer implements IServerContainer { ) ); }); - $this->registerService('PreviewManager', function($c){ + $this->registerService('PreviewManager', function($c) { return new PreviewManager(); }); - $this->registerService('RootFolder', function($c){ + $this->registerService('RootFolder', function($c) { // TODO: get user and user manager from container as well $user = \OC_User::getUser(); $user = \OC_User::getManager()->get($user); @@ -57,6 +57,9 @@ class Server extends SimpleContainer implements IServerContainer { $view = new View(); return new Root($manager, $view, $user); }); + $this->registerService('UserCache', function($c) { + return new UserCache(); + }); } /** @@ -67,14 +70,13 @@ class Server extends SimpleContainer implements IServerContainer { } /** - * The current request object holding all information about the request currently being processed - * is returned from this method. + * The current request object holding all information about the request + * currently being processed is returned from this method. * In case the current execution was not initiated by a web request null is returned * * @return \OCP\IRequest|null */ - function getRequest() - { + function getRequest() { return $this->query('Request'); } @@ -83,8 +85,7 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\IPreview */ - function getPreviewManager() - { + function getPreviewManager() { return $this->query('PreviewManager'); } @@ -93,8 +94,17 @@ class Server extends SimpleContainer implements IServerContainer { * * @return \OCP\Files\Folder */ - function getRootFolder() - { + function getRootFolder() { return $this->query('RootFolder'); } + + /** + * Returns an ICache instance + * + * @return \OCP\ICache + */ + function getCache() { + return $this->query('UserCache'); + } + } diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index 038cb21b257..3767c83fcb1 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -20,7 +20,9 @@ * */ -class Test_Cache_File extends Test_Cache { +namespace Test\Cache; + +class FileCache extends \Test_Cache { private $user; private $datadir; @@ -30,8 +32,8 @@ class Test_Cache_File extends Test_Cache { public function setUp() { //clear all proxies and hooks so we can do clean testing - OC_FileProxy::clearProxies(); - OC_Hook::clear('OC_Filesystem'); + \OC_FileProxy::clearProxies(); + \OC_Hook::clear('OC_Filesystem'); //disabled atm //enable only the encryption hook if needed @@ -44,27 +46,27 @@ class Test_Cache_File extends Test_Cache { $storage = new \OC\Files\Storage\Temporary(array()); \OC\Files\Filesystem::mount($storage,array(),'/'); $datadir = str_replace('local::', '', $storage->getId()); - $this->datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); - OC_Config::setValue('datadirectory', $datadir); + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + \OC_Config::setValue('datadirectory', $datadir); - OC_User::clearBackends(); - OC_User::useBackend(new OC_User_Dummy()); + \OC_User::clearBackends(); + \OC_User::useBackend(new \OC_User_Dummy()); //login - OC_User::createUser('test', 'test'); + \OC_User::createUser('test', 'test'); - $this->user=OC_User::getUser(); - OC_User::setUserId('test'); + $this->user = \OC_User::getUser(); + \OC_User::setUserId('test'); //set up the users dir - $rootView=new \OC\Files\View(''); + $rootView = new \OC\Files\View(''); $rootView->mkdir('/test'); - $this->instance=new OC_Cache_File(); + $this->instance=new \OC\Cache\File(); } public function tearDown() { - OC_User::setUserId($this->user); - OC_Config::setValue('datadirectory', $this->datadir); + \OC_User::setUserId($this->user); + \OC_Config::setValue('datadirectory', $this->datadir); } } diff --git a/tests/lib/cache/usercache.php b/tests/lib/cache/usercache.php new file mode 100644 index 00000000000..21b7f848ab6 --- /dev/null +++ b/tests/lib/cache/usercache.php @@ -0,0 +1,68 @@ +. +* +*/ + +namespace Test\Cache; + +class UserCache extends \Test_Cache { + private $user; + private $datadir; + + public function setUp() { + //clear all proxies and hooks so we can do clean testing + \OC_FileProxy::clearProxies(); + \OC_Hook::clear('OC_Filesystem'); + + //disabled atm + //enable only the encryption hook if needed + //if(OC_App::isEnabled('files_encryption')) { + // OC_FileProxy::register(new OC_FileProxy_Encryption()); + //} + + //set up temporary storage + \OC\Files\Filesystem::clearMounts(); + $storage = new \OC\Files\Storage\Temporary(array()); + \OC\Files\Filesystem::mount($storage,array(),'/'); + $datadir = str_replace('local::', '', $storage->getId()); + $this->datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + \OC_Config::setValue('datadirectory', $datadir); + + \OC_User::clearBackends(); + \OC_User::useBackend(new \OC_User_Dummy()); + + //login + \OC_User::createUser('test', 'test'); + + $this->user = \OC_User::getUser(); + \OC_User::setUserId('test'); + + //set up the users dir + $rootView=new \OC\Files\View(''); + $rootView->mkdir('/test'); + + $this->instance=new \OC\Cache\UserCache(); + } + + public function tearDown() { + \OC_User::setUserId($this->user); + \OC_Config::setValue('datadirectory', $this->datadir); + } +} -- cgit v1.2.3 From 8b4f4a79e22dc08cf7c13a91c926c229676d6522 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 17 Sep 2013 19:46:08 +0200 Subject: Still some session leftovers. --- lib/appframework/controller/controller.php | 10 ---------- tests/lib/appframework/controller/ControllerTest.php | 5 ----- 2 files changed, 15 deletions(-) (limited to 'tests') diff --git a/lib/appframework/controller/controller.php b/lib/appframework/controller/controller.php index a7498ba0e1e..0ea0a38cc09 100644 --- a/lib/appframework/controller/controller.php +++ b/lib/appframework/controller/controller.php @@ -106,16 +106,6 @@ abstract class Controller { } - /** - * Shortcut for getting session variables - * @param string $key the key that will be taken from the $_SESSION array - * @return array the value in the $_SESSION element - */ - public function session($key) { - return $this->request->getSession($key); - } - - /** * Shortcut for getting cookie variables * @param string $key the key that will be taken from the $_COOKIE array diff --git a/tests/lib/appframework/controller/ControllerTest.php b/tests/lib/appframework/controller/ControllerTest.php index 246371d249c..4441bddfca9 100644 --- a/tests/lib/appframework/controller/ControllerTest.php +++ b/tests/lib/appframework/controller/ControllerTest.php @@ -152,9 +152,4 @@ class ControllerTest extends \PHPUnit_Framework_TestCase { $this->assertEquals('daheim', $this->controller->env('PATH')); } - public function testGetSessionVariable(){ - $this->assertEquals('kein', $this->controller->session('sezession')); - } - - } -- cgit v1.2.3 From 1274d6116dc59a8238ad9d02d467260387fe2eac Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Wed, 18 Sep 2013 22:22:51 +0200 Subject: updating php docs --- lib/cache.php | 15 ++++++++++----- lib/cache/broker.php | 8 ++++++++ lib/cache/usercache.php | 4 ++-- lib/public/icache.php | 2 +- tests/lib/cache.php | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/lib/cache.php b/lib/cache.php index a4fa8be710c..a311f10a00f 100644 --- a/lib/cache.php +++ b/lib/cache.php @@ -10,17 +10,17 @@ namespace OC; class Cache { /** - * @var OC_Cache $user_cache + * @var Cache $user_cache */ static protected $user_cache; /** - * @var OC_Cache $global_cache + * @var Cache $global_cache */ static protected $global_cache; /** * get the global cache - * @return OC_Cache + * @return Cache */ static public function getGlobalCache() { if (!self::$global_cache) { @@ -31,7 +31,7 @@ class Cache { /** * get the user cache - * @return OC_Cache + * @return Cache */ static public function getUserCache() { if (!self::$user_cache) { @@ -87,7 +87,7 @@ class Cache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ static public function clear($prefix='') { @@ -95,6 +95,11 @@ class Cache { return $user_cache->clear($prefix); } + /** + * creates cache key based on the files given + * @param $files + * @return string + */ static public function generateCacheKeyFromFiles($files) { $key = ''; sort($files); diff --git a/lib/cache/broker.php b/lib/cache/broker.php index b7f1b67a6d3..9b7e837e1bc 100644 --- a/lib/cache/broker.php +++ b/lib/cache/broker.php @@ -9,7 +9,15 @@ namespace OC\Cache; class Broker { + + /** + * @var \OC\Cache + */ protected $fast_cache; + + /** + * @var \OC\Cache + */ protected $slow_cache; public function __construct($fast_cache, $slow_cache) { diff --git a/lib/cache/usercache.php b/lib/cache/usercache.php index aac3b39af33..baa8820700b 100644 --- a/lib/cache/usercache.php +++ b/lib/cache/usercache.php @@ -13,7 +13,7 @@ namespace OC\Cache; class UserCache implements \OCP\ICache { /** - * @var OC\Cache\File $userCache + * @var \OC\Cache\File $userCache */ protected $userCache; @@ -68,7 +68,7 @@ class UserCache implements \OCP\ICache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ public function clear($prefix = '') { diff --git a/lib/public/icache.php b/lib/public/icache.php index 202459f7c24..436ee71b2b9 100644 --- a/lib/public/icache.php +++ b/lib/public/icache.php @@ -48,7 +48,7 @@ interface ICache { /** * clear the user cache of all entries starting with a prefix - * @param string prefix (optional) + * @param string $prefix (optional) * @return bool */ public function clear($prefix = ''); diff --git a/tests/lib/cache.php b/tests/lib/cache.php index 3dcf39f7d60..8fefa25f65d 100644 --- a/tests/lib/cache.php +++ b/tests/lib/cache.php @@ -8,7 +8,7 @@ abstract class Test_Cache extends PHPUnit_Framework_TestCase { /** - * @var OC_Cache cache; + * @var \OC\Cache cache; */ protected $instance; -- cgit v1.2.3 From 45f73feb6967b878b2e39fc4413aca92f0dbaf9f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 18 Sep 2013 00:37:00 +0200 Subject: OC_VCategories=>OC\Tags. Public interface + getter in server container --- lib/public/iservercontainer.php | 7 + lib/public/itags.php | 173 +++++++++ lib/server.php | 16 +- lib/tags.php | 621 ++++++++++++++++++++++++++++++ lib/vcategories.php | 833 ---------------------------------------- tests/lib/tags.php | 133 +++++++ tests/lib/vcategories.php | 128 ------ 7 files changed, 948 insertions(+), 963 deletions(-) create mode 100644 lib/public/itags.php create mode 100644 lib/tags.php delete mode 100644 lib/vcategories.php create mode 100644 tests/lib/tags.php delete mode 100644 tests/lib/vcategories.php (limited to 'tests') diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 4478a4e8a6c..0df746a28ed 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -55,6 +55,13 @@ interface IServerContainer { */ function getPreviewManager(); + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager(); + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/public/itags.php b/lib/public/itags.php new file mode 100644 index 00000000000..047d4f5f40b --- /dev/null +++ b/lib/public/itags.php @@ -0,0 +1,173 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +namespace OCP; + +// FIXME: Where should I put this? Or should it be implemented as a Listener? +\OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Tags', 'post_deleteUser'); + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +interface ITags { + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()); + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty(); + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @returns array + */ + public function tags(); + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag); + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name); + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name); + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to); + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null); + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids); + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites(); + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid); + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid); + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag); + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag); + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names); + +} \ No newline at end of file diff --git a/lib/server.php b/lib/server.php index 804af6b0eac..b09d380b0e9 100644 --- a/lib/server.php +++ b/lib/server.php @@ -49,8 +49,11 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('PreviewManager', function($c) { return new PreviewManager(); }); - $this->registerService('RootFolder', function($c) { - // TODO: get user from container as well + $this->registerService('TagManager', function($c){ + return new Tags(); + }); + $this->registerService('RootFolder', function($c){ + // TODO: get user and user manager from container as well $user = \OC_User::getUser(); /** @var $c SimpleContainer */ $userManager = $c->query('UserManager'); @@ -139,6 +142,15 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('PreviewManager'); } + /** + * Returns the tag manager which can get and set tags for different object types + * + * @return \OCP\ITags + */ + function getTagManager() { + return $this->query('TagManager'); + } + /** * Returns the root folder of ownCloud's data directory * diff --git a/lib/tags.php b/lib/tags.php new file mode 100644 index 00000000000..4aafff8e1bb --- /dev/null +++ b/lib/tags.php @@ -0,0 +1,621 @@ + +* @copyright 2012 Bart Visscher bartv@thisnet.nl +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class Tags implements \OCP\ITags { + + /** + * Tags + */ + private $tags = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + */ + private static $relations = array(); + + private $type = null; + private $user = null; + + const TAG_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const TAG_FAVORITE = '_$!!$_'; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function loadTagsFor($type, $defaultTags=array()) { + $this->type = $type; + $this->tags = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $this->tags[$row['id']] = $row['category']; + } + } + + if(count($defaultTags) > 0 && count($this->tags) === 0) { + $this->addMulti($defaultTags, true); + } + \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), + \OCP\Util::DEBUG); + + return $this; + } + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty() { + $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + return ($result->numRows() === 0); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @return array + */ + public function tags() { + if(!count($this->tags)) { + return array(); + } + + $tags = array_values($this->tags); + uasort($tags, 'strnatcasecmp'); + $tagMap = array(); + + foreach($tags as $tag) { + if($tag !== self::TAG_FAVORITE) { + $tagMap[] = array( + 'id' => $this->array_searchi($tag, $this->tags), + 'name' => $tag + ); + } + } + return $tagMap; + + } + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function idsForTag($tag) { + $result = null; + if(is_numeric($tag)) { + $tagId = $tag; + } elseif(is_string($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } + + if($tagId === false) { + $l10n = \OC_L10N::get('core'); + throw new \Exception( + $l10n->t('Could not find category "%s"', $tag) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . '` WHERE `categoryid` = ?'; + + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($tagId)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $ids[] = (int)$row['objid']; + } + } + + return $ids; + } + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name) { + return $this->in_arrayi($name, $this->tags); + } + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name) { + $name = trim($name); + + if($this->hasTag($name)) { + \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); + return false; + } + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $id = \OCP\DB::insertid(self::TAG_TABLE); + \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); + $this->tags[$id] = $name; + return $id; + } + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to) { + $from = trim($from); + $to = trim($to); + $id = $this->array_searchi($from, $this->tags); + if($id === false) { + \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); + return false; + } + + $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' + . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($to, $this->user, $this->type, $id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $this->tags[$id] = $to; + return true; + } + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMulti($names, $sync=false, $id = null) { + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + $newones = array(); + foreach($names as $name) { + if(($this->in_arrayi( + $name, $this->tags) == false) && $name !== '') { + $newones[] = $name; + } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'tag' => $name); + } + } + $this->tags = array_merge($this->tags, $newones); + if($sync === true) { + $this->save(); + } + + return true; + } + + /** + * Save the list of tags and their object relations + */ + protected function save() { + if(is_array($this->tags)) { + foreach($this->tags as $tag) { + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $tag, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + // reload tags to get the proper ids. + $this->loadTagsFor($this->type); + // Loop through temporarily cached objectid/tagname pairs + // and save relations. + $tags = $this->tags; + // For some reason this is needed or array_search(i) will return 0..? + ksort($tags); + foreach(self::$relations as $relation) { + $tagId = $this->array_searchi($relation['tag'], $tags); + \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); + if($tagId) { + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $relation['objid'], + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } + self::$relations = array(); // reset + } else { + \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' + . print_r($this->tags, true), \OCP\Util::ERROR); + } + } + + /** + * Delete tags and tag/object relations for a user. + * + * For hooking up on post_deleteUser + * + * @param array + */ + public static function post_deleteUser($arguments) { + // Find all objectid/tagId pairs. + $result = null; + try { + $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'); + while( $row = $result->fetchRow()) { + try { + $stmt->execute(array($row['id'])); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + } + } + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids) { + if(count($ids) === 0) { + // job done ;) + return true; + } + $updates = $ids; + try { + $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; + $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; + $query .= 'AND `type`= ?'; + $updates[] = $this->type; + $stmt = OCP\DB::prepare($query); + $result = $stmt->execute($updates); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites() { + try { + return $this->idsForTag(self::TAG_FAVORITE); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid) { + if(!$this->hasCategory(self::TAG_FAVORITE)) { + $this->add(self::TAG_FAVORITE, true); + } + return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid) { + return $this->unTag($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + if(!$this->hasTag($tag)) { + $this->add($tag, true); + } + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $objid, + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + $stmt = \OCP\DB::prepare($sql); + $stmt->execute(array($objid, $tagId, $this->type)); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names) { + if(!is_array($names)) { + $names = array($names); + } + + $names = array_map('trim', $names); + + \OCP\Util::writeLog('core', __METHOD__ . ', before: ' + . print_r($this->tags, true), \OCP\Util::DEBUG); + foreach($names as $name) { + $id = null; + + if($this->hasTag($name)) { + $id = $this->array_searchi($name, $this->tags); + unset($this->tags[$id]); + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', + __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), + \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return array_search(strtolower($needle), array_map('strtolower', $haystack)); + } +} diff --git a/lib/vcategories.php b/lib/vcategories.php deleted file mode 100644 index a7e4c54be29..00000000000 --- a/lib/vcategories.php +++ /dev/null @@ -1,833 +0,0 @@ - -* @copyright 2012 Bart Visscher bartv@thisnet.nl -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library 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 library. If not, see . -* -*/ - -OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUser'); - -/** - * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. - * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Category names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a category 'family' for a type, and - * tries to add a category named 'Family' it will be silently ignored. - */ -class OC_VCategories { - - /** - * Categories - */ - private $categories = array(); - - /** - * Used for storing objectid/categoryname pairs while rescanning. - */ - private static $relations = array(); - - private $type = null; - private $user = null; - - const CATEGORY_TABLE = '*PREFIX*vcategory'; - const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - - const CATEGORY_FAVORITE = '_$!!$_'; - - const FORMAT_LIST = 0; - const FORMAT_MAP = 1; - - /** - * @brief Constructor. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos data the object will operate on. This - * parameter should normally be omitted but to make an app able to - * update categories for all users it is made possible to provide it. - * @param $defcategories An array of default categories to be used if none is stored. - */ - public function __construct($type, $user=null, $defcategories=array()) { - $this->type = $type; - $this->user = is_null($user) ? OC_User::getUser() : $user; - - $this->loadCategories(); - OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r($this->categories, true), - OCP\Util::DEBUG - ); - - if($defcategories && count($this->categories) === 0) { - $this->addMulti($defcategories, true); - } - } - - /** - * @brief Load categories from db. - */ - private function loadCategories() { - $this->categories = array(); - $result = null; - $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - // The keys are prefixed because array_search wouldn't work otherwise :-/ - $this->categories[$row['id']] = $row['category']; - } - } - OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true), - OCP\Util::DEBUG); - } - - - /** - * @brief Check if any categories are saved for this type and user. - * @returns boolean. - * @param $type The type identifier e.g. 'contact' or 'event'. - * @param $user The user whos categories will be checked. If not set current user will be used. - */ - public static function isEmpty($type, $user = null) { - $user = is_null($user) ? OC_User::getUser() : $user; - $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($user, $type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - return ($result->numRows() === 0); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - - /** - * @brief Get the categories for a specific user. - * @param - * @returns array containing the categories as strings. - */ - public function categories($format = null) { - if(!$this->categories) { - return array(); - } - $categories = array_values($this->categories); - uasort($categories, 'strnatcasecmp'); - if($format == self::FORMAT_MAP) { - $catmap = array(); - foreach($categories as $category) { - if($category !== self::CATEGORY_FAVORITE) { - $catmap[] = array( - 'id' => $this->array_searchi($category, $this->categories), - 'name' => $category - ); - } - } - return $catmap; - } - - // Don't add favorites to normal categories. - $favpos = array_search(self::CATEGORY_FAVORITE, $categories); - if($favpos !== false) { - return array_splice($categories, $favpos); - } else { - return $categories; - } - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @returns array An array of object ids or false on error. - */ - public function idsForCategory($category) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - - $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . '` WHERE `categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $ids[] = (int)$row['objid']; - } - } - - return $ids; - } - - /** - * Get the a list if items belonging to $category. - * - * Throws an exception if the category could not be found. - * - * @param string|integer $category Category id or name. - * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} - * @param int $limit - * @param int $offset - * - * This generic method queries a table assuming that the id - * field is called 'id' and the table name provided is in - * the form '*PREFIX*table_name'. - * - * If the category name cannot be resolved an exception is thrown. - * - * TODO: Maybe add the getting permissions for objects? - * - * @returns array containing the resulting items or false on error. - */ - public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { - $result = null; - if(is_numeric($category)) { - $catid = $category; - } elseif(is_string($category)) { - $category = trim($category); - $catid = $this->array_searchi($category, $this->categories); - } - OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); - if($catid === false) { - $l10n = OC_L10N::get('core'); - throw new Exception( - $l10n->t('Could not find category "%s"', $category) - ); - } - $fields = ''; - foreach($tableinfo['fields'] as $field) { - $fields .= '`' . $tableinfo['tablename'] . '`.`' . $field . '`,'; - } - $fields = substr($fields, 0, -1); - - $items = array(); - $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields - . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' - . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] - . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' - . self::RELATION_TABLE . '`.`categoryid` = ?'; - - try { - $stmt = OCP\DB::prepare($sql, $limit, $offset); - $result = $stmt->execute(array($catid)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $items[] = $row; - } - } - //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); - //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); - - return $items; - } - - /** - * @brief Checks whether a category is already saved. - * @param $name The name to check for. - * @returns bool - */ - public function hasCategory($name) { - return $this->in_arrayi($name, $this->categories); - } - - /** - * @brief Add a new category. - * @param $name A string with a name of the category - * @returns int the id of the added category or false if it already exists. - */ - public function add($name) { - $name = trim($name); - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); - if($this->hasCategory($name)) { - OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); - return false; - } - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $name, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $id = OCP\DB::insertid(self::CATEGORY_TABLE); - OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG); - $this->categories[$id] = $name; - return $id; - } - - /** - * @brief Rename category. - * @param string $from The name of the existing category - * @param string $to The new name of the category. - * @returns bool - */ - public function rename($from, $to) { - $from = trim($from); - $to = trim($to); - $id = $this->array_searchi($from, $this->categories); - if($id === false) { - OCP\Util::writeLog('core', __METHOD__.', category: ' . $from. ' does not exist', OCP\Util::DEBUG); - return false; - } - - $sql = 'UPDATE `' . self::CATEGORY_TABLE . '` SET `category` = ? ' - . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; - try { - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($to, $this->user, $this->type, $id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - $this->categories[$id] = $to; - return true; - } - - /** - * @brief Add a new category. - * @param $names A string with a name or an array of strings containing - * the name(s) of the categor(y|ies) to add. - * @param $sync bool When true, save the categories - * @param $id int Optional object id to add to this|these categor(y|ies) - * @returns bool Returns false on error. - */ - public function addMulti($names, $sync=false, $id = null) { - if(!is_array($names)) { - $names = array($names); - } - $names = array_map('trim', $names); - $newones = array(); - foreach($names as $name) { - if(($this->in_arrayi( - $name, $this->categories) == false) && $name != '') { - $newones[] = $name; - } - if(!is_null($id) ) { - // Insert $objectid, $categoryid pairs if not exist. - self::$relations[] = array('objid' => $id, 'category' => $name); - } - } - $this->categories = array_merge($this->categories, $newones); - if($sync === true) { - $this->save(); - } - - return true; - } - - /** - * @brief Extracts categories from a vobject and add the ones not already present. - * @param $vobject The instance of OC_VObject to load the categories from. - */ - public function loadFromVObject($id, $vobject, $sync=false) { - $this->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id); - } - - /** - * @brief Reset saved categories and rescan supplied vobjects for categories. - * @param $objects An array of vobjects (as text). - * To get the object array, do something like: - * // For Addressbook: - * $categories = new OC_VCategories('contacts'); - * $stmt = OC_DB::prepare( 'SELECT `carddata` FROM `*PREFIX*contacts_cards`' ); - * $result = $stmt->execute(); - * $objects = array(); - * if(!is_null($result)) { - * while( $row = $result->fetchRow()){ - * $objects[] = array($row['id'], $row['carddata']); - * } - * } - * $categories->rescan($objects); - */ - public function rescan($objects, $sync=true, $reset=true) { - - if($reset === true) { - $result = null; - // Find all objectid/categoryid pairs. - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - // And delete them. - if(!is_null($result)) { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ? AND `type`= ?'); - while( $row = $result->fetchRow()) { - $stmt->execute(array($row['id'], $this->type)); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'); - $result = $stmt->execute(array($this->user, $this->type)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - return; - } - $this->categories = array(); - } - // Parse all the VObjects - foreach($objects as $object) { - $vobject = OC_VObject::parse($object[1]); - if(!is_null($vobject)) { - // Load the categories - $this->loadFromVObject($object[0], $vobject, $sync); - } else { - OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' - . substr($object, 0, 100) . '(...)', OC_Log::DEBUG); - } - } - $this->save(); - } - - /** - * @brief Save the list with categories - */ - private function save() { - if(is_array($this->categories)) { - foreach($this->categories as $category) { - try { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $category, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - // reload categories to get the proper ids. - $this->loadCategories(); - // Loop through temporarily cached objectid/categoryname pairs - // and save relations. - $categories = $this->categories; - // For some reason this is needed or array_search(i) will return 0..? - ksort($categories); - foreach(self::$relations as $relation) { - $catid = $this->array_searchi($relation['category'], $categories); - OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); - if($catid) { - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $relation['objid'], - 'categoryid' => $catid, - 'type' => $this->type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } - self::$relations = array(); // reset - } else { - OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' - . print_r($this->categories, true), OC_Log::ERROR); - } - } - - /** - * @brief Delete categories and category/object relations for a user. - * For hooking up on post_deleteUser - * @param string $uid The user id for which entries should be purged. - */ - public static function post_deleteUser($arguments) { - // Find all objectid/categoryid pairs. - $result = null; - try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - - if(!is_null($result)) { - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'); - while( $row = $result->fetchRow()) { - try { - $stmt->execute(array($row['id'])); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - } - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - } - - /** - * @brief Delete category/object relations from the db - * @param array $ids The ids of the objects - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on error. - */ - public function purgeObjects(array $ids, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(count($ids) === 0) { - // job done ;) - return true; - } - $updates = $ids; - try { - $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; - $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; - $query .= 'AND `type`= ?'; - $updates[] = $type; - $stmt = OCP\DB::prepare($query); - $result = $stmt->execute($updates); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - return false; - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Get favorites for an object type - * - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns array An array of object ids. - */ - public function getFavorites($type = null) { - $type = is_null($type) ? $this->type : $type; - - try { - return $this->idsForCategory(self::CATEGORY_FAVORITE); - } catch(Exception $e) { - // No favorites - return array(); - } - } - - /** - * Add an object to favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function addToFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(!$this->hasCategory(self::CATEGORY_FAVORITE)) { - $this->add(self::CATEGORY_FAVORITE, true); - } - return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * Remove an object from favorites - * - * @param int $objid The id of the object - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromFavorites($objid, $type = null) { - $type = is_null($type) ? $this->type : $type; - return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type); - } - - /** - * @brief Creates a category/object relation. - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean Returns false on database error. - */ - public function addToCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - if(!$this->hasCategory($category)) { - $this->add($category, true); - } - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $objid, - 'categoryid' => $categoryid, - 'type' => $type, - )); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete single category/object relation from the db - * @param int $objid The id of the object - * @param int|string $category The id or name of the category - * @param string $type The type of object (event/contact/task/journal). - * Defaults to the type set in the instance - * @returns boolean - */ - public function removeFromCategory($objid, $category, $type = null) { - $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !is_numeric($category)) { - $category = trim($category); - $categoryid = $this->array_searchi($category, $this->categories); - } else { - $categoryid = $category; - } - - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, - OCP\Util::DEBUG); - $stmt = OCP\DB::prepare($sql); - $stmt->execute(array($objid, $categoryid, $type)); - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * @brief Delete categories from the db and from all the vobject supplied - * @param $names An array of categories to delete - * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. - */ - public function delete($names, array &$objects=null) { - if(!is_array($names)) { - $names = array($names); - } - - $names = array_map('trim', $names); - - OC_Log::write('core', __METHOD__ . ', before: ' - . print_r($this->categories, true), OC_Log::DEBUG); - foreach($names as $name) { - $id = null; - OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); - if($this->hasCategory($name)) { - $id = $this->array_searchi($name, $this->categories); - unset($this->categories[$id]); - } - try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' - . '`uid` = ? AND `type` = ? AND `category` = ?'); - $result = $stmt->execute(array($this->user, $this->type, $name)); - if (OC_DB::isError($result)) { - OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), OCP\Util::ERROR); - } - if(!is_null($id) && $id !== false) { - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'; - $stmt = OCP\DB::prepare($sql); - $result = $stmt->execute(array($id)); - if (OC_DB::isError($result)) { - OC_Log::write('core', - __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), - OC_Log::ERROR); - } - } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - OCP\Util::ERROR); - return false; - } - } - } - OC_Log::write('core', __METHOD__.', after: ' - . print_r($this->categories, true), OC_Log::DEBUG); - if(!is_null($objects)) { - foreach($objects as $key=>&$value) { - $vobject = OC_VObject::parse($value[1]); - if(!is_null($vobject)) { - $object = null; - $componentname = ''; - if (isset($vobject->VEVENT)) { - $object = $vobject->VEVENT; - $componentname = 'VEVENT'; - } else - if (isset($vobject->VTODO)) { - $object = $vobject->VTODO; - $componentname = 'VTODO'; - } else - if (isset($vobject->VJOURNAL)) { - $object = $vobject->VJOURNAL; - $componentname = 'VJOURNAL'; - } else { - $object = $vobject; - } - $categories = $object->getAsArray('CATEGORIES'); - foreach($names as $name) { - $idx = $this->array_searchi($name, $categories); - if($idx !== false) { - OC_Log::write('core', __METHOD__ - .', unsetting: ' - . $categories[$this->array_searchi($name, $categories)], - OC_Log::DEBUG); - unset($categories[$this->array_searchi($name, $categories)]); - } - } - - $object->setString('CATEGORIES', implode(',', $categories)); - if($vobject !== $object) { - $vobject[$componentname] = $object; - } - $value[1] = $vobject->serialize(); - $objects[$key] = $value; - } else { - OC_Log::write('core', __METHOD__ - .', unable to parse. ID: ' . $value[0] . ', ' - . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG); - } - } - } - } - - // case-insensitive in_array - private function in_arrayi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return in_array(strtolower($needle), array_map('strtolower', $haystack)); - } - - // case-insensitive array_search - private function array_searchi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return array_search(strtolower($needle), array_map('strtolower', $haystack)); - } -} diff --git a/tests/lib/tags.php b/tests/lib/tags.php new file mode 100644 index 00000000000..06baebc0af7 --- /dev/null +++ b/tests/lib/tags.php @@ -0,0 +1,133 @@ +. +* +*/ + +class Test_Tags extends PHPUnit_Framework_TestCase { + + protected $objectType; + protected $user; + protected $backupGlobals = FALSE; + + public function setUp() { + + OC_User::clearBackends(); + OC_User::useBackend('dummy'); + $this->user = uniqid('user_'); + $this->objectType = uniqid('type_'); + OC_User::createUser($this->user, 'pass'); + OC_User::setUserId($this->user); + + } + + public function tearDown() { + //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); + //$query->execute(array('test')); + } + + public function testInstantiateWithDefaults() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testAddTags() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $result = $tagMgr->add($tag); + $this->assertTrue((bool)$result); + } + + $this->assertFalse($tagMgr->add('Family')); + $this->assertFalse($tagMgr->add('fAMILY')); + + $this->assertEquals(4, count($tagMgr->tags())); + } + + public function testdeleteTags() { + $defaultTags = array('Friends', 'Family', 'Work', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertEquals(4, count($tagMgr->tags())); + + $tagMgr->delete('family'); + $this->assertEquals(3, count($tagMgr->tags())); + + $tagMgr->delete(array('Friends', 'Work', 'Other')); + $this->assertEquals(0, count($tagMgr->tags())); + + } + + public function testRenameTag() { + $defaultTags = array('Friends', 'Family', 'Wrok', 'Other'); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType, $defaultTags); + + $this->assertTrue($tagMgr->rename('Wrok', 'Work')); + $this->assertTrue($tagMgr->hasTag('Work')); + $this->assertFalse($tagMgr->hastag('Wrok')); + $this->assertFalse($tagMgr->rename('Wrok', 'Work')); + + } + + public function testTagAs() { + $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objids as $id) { + $tagMgr->tagAs($id, 'Family'); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + } + + /** + * @depends testTagAs + */ + public function testUnTag() { + $objIds = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + // Is this "legal"? + $this->testTagAs(); + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($objIds as $id) { + $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $tagMgr->unTag($id, 'Family'); + $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + } + + $this->assertEquals(1, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + } + +} diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php deleted file mode 100644 index df5f600f20d..00000000000 --- a/tests/lib/vcategories.php +++ /dev/null @@ -1,128 +0,0 @@ -. -* -*/ - -//require_once("../lib/template.php"); - -class Test_VCategories extends PHPUnit_Framework_TestCase { - - protected $objectType; - protected $user; - protected $backupGlobals = FALSE; - - public function setUp() { - - OC_User::clearBackends(); - OC_User::useBackend('dummy'); - $this->user = uniqid('user_'); - $this->objectType = uniqid('type_'); - OC_User::createUser($this->user, 'pass'); - OC_User::setUserId($this->user); - - } - - public function tearDown() { - //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); - //$query->execute(array('test')); - } - - public function testInstantiateWithDefaults() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testAddCategories() { - $categories = array('Friends', 'Family', 'Work', 'Other'); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($categories as $category) { - $result = $catmgr->add($category); - $this->assertTrue((bool)$result); - } - - $this->assertFalse($catmgr->add('Family')); - $this->assertFalse($catmgr->add('fAMILY')); - - $this->assertEquals(4, count($catmgr->categories())); - } - - public function testdeleteCategories() { - $defcategories = array('Friends', 'Family', 'Work', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - $this->assertEquals(4, count($catmgr->categories())); - - $catmgr->delete('family'); - $this->assertEquals(3, count($catmgr->categories())); - - $catmgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($catmgr->categories())); - - } - - public function testrenameCategory() { - $defcategories = array('Friends', 'Family', 'Wrok', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - - $this->assertTrue($catmgr->rename('Wrok', 'Work')); - $this->assertTrue($catmgr->hasCategory('Work')); - $this->assertFalse($catmgr->hasCategory('Wrok')); - $this->assertFalse($catmgr->rename('Wrok', 'Work')); - - } - - public function testAddToCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $catmgr->addToCategory($id, 'Family'); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(9, count($catmgr->idsForCategory('Family'))); - } - - /** - * @depends testAddToCategory - */ - public function testRemoveFromCategory() { - $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - - // Is this "legal"? - $this->testAddToCategory(); - $catmgr = new OC_VCategories($this->objectType, $this->user); - - foreach($objids as $id) { - $this->assertTrue(in_array($id, $catmgr->idsForCategory('Family'))); - $catmgr->removeFromCategory($id, 'Family'); - $this->assertFalse(in_array($id, $catmgr->idsForCategory('Family'))); - } - - $this->assertEquals(1, count($catmgr->categories())); - $this->assertEquals(0, count($catmgr->idsForCategory('Family'))); - } - -} -- cgit v1.2.3 From 1bbeb12e2e8acc47b94c23d6a17332fb45c2a97e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 11:27:13 +0200 Subject: Updated method names and added a few more tests. --- lib/public/itags.php | 6 +++--- lib/tags.php | 12 +++++------ tests/lib/tags.php | 59 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/lib/public/itags.php b/lib/public/itags.php index 047d4f5f40b..12643400548 100644 --- a/lib/public/itags.php +++ b/lib/public/itags.php @@ -65,7 +65,7 @@ interface ITags { * * @returns array */ - public function tags(); + public function getTags(); /** * Get the a list if items tagged with $tag. @@ -75,7 +75,7 @@ interface ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag); + public function getIdsForTag($tag); /** * Checks whether a tag is already saved. @@ -111,7 +111,7 @@ interface ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null); + public function addMultiple($names, $sync=false, $id = null); /** * Delete tag/object relations from the db diff --git a/lib/tags.php b/lib/tags.php index 3320d9ea1a8..2eaa603c1a3 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -96,7 +96,7 @@ class Tags implements \OCP\ITags { } if(count($defaultTags) > 0 && count($this->tags) === 0) { - $this->addMulti($defaultTags, true); + $this->addMultiple($defaultTags, true); } \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), \OCP\Util::DEBUG); @@ -119,7 +119,7 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); return false; } - return ($result->numRows() === 0); + return ((int)$result->numRows() === 0); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR); @@ -138,7 +138,7 @@ class Tags implements \OCP\ITags { * * @return array */ - public function tags() { + public function getTags() { if(!count($this->tags)) { return array(); } @@ -167,7 +167,7 @@ class Tags implements \OCP\ITags { * @param string|integer $tag Tag id or name. * @return array An array of object ids or false on error. */ - public function idsForTag($tag) { + public function getIdsForTag($tag) { $result = null; if(is_numeric($tag)) { $tagId = $tag; @@ -293,7 +293,7 @@ class Tags implements \OCP\ITags { * @param int|null $id int Optional object id to add to this|these tag(s) * @return bool Returns false on error. */ - public function addMulti($names, $sync=false, $id = null) { + public function addMultiple($names, $sync=false, $id = null) { if(!is_array($names)) { $names = array($names); } @@ -456,7 +456,7 @@ class Tags implements \OCP\ITags { */ public function getFavorites() { try { - return $this->idsForTag(self::TAG_FAVORITE); + return $this->getIdsForTag(self::TAG_FAVORITE); } catch(\Exception $e) { \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), \OCP\Util::ERROR); diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 06baebc0af7..16a03f5645a 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -48,7 +48,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); } public function testAddTags() { @@ -65,7 +65,37 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testAddMultiple() { + $tags = array('Friends', 'Family', 'Work', 'Other'); + + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + foreach($tags as $tag) { + $this->assertFalse($tagMgr->hasTag($tag)); + } + + $result = $tagMgr->addMultiple($tags); + $this->assertTrue((bool)$result); + + foreach($tags as $tag) { + $this->assertTrue($tagMgr->hasTag($tag)); + } + + $this->assertEquals(4, count($tagMgr->getTags())); + } + + public function testIsEmpty() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + + $this->assertEquals(0, count($tagMgr->getTags())); + $this->assertTrue($tagMgr->isEmpty()); + $tagMgr->add('Tag'); + $this->assertFalse($tagMgr->isEmpty()); } public function testdeleteTags() { @@ -73,13 +103,13 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr = new OC\Tags($this->user); $tagMgr->loadTagsFor($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->tags())); + $this->assertEquals(4, count($tagMgr->getTags())); $tagMgr->delete('family'); - $this->assertEquals(3, count($tagMgr->tags())); + $this->assertEquals(3, count($tagMgr->getTags())); $tagMgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($tagMgr->tags())); + $this->assertEquals(0, count($tagMgr->getTags())); } @@ -105,8 +135,8 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->tagAs($id, 'Family'); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(9, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(9, count($tagMgr->getIdsForTag('Family'))); } /** @@ -121,13 +151,20 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $tagMgr->loadTagsFor($this->objectType); foreach($objIds as $id) { - $this->assertTrue(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertTrue(in_array($id, $tagMgr->getIdsForTag('Family'))); $tagMgr->unTag($id, 'Family'); - $this->assertFalse(in_array($id, $tagMgr->idsForTag('Family'))); + $this->assertFalse(in_array($id, $tagMgr->getIdsForTag('Family'))); } - $this->assertEquals(1, count($tagMgr->tags())); - $this->assertEquals(0, count($tagMgr->idsForTag('Family'))); + $this->assertEquals(1, count($tagMgr->getTags())); + $this->assertEquals(0, count($tagMgr->getIdsForTag('Family'))); + } + + public function testFavorite() { + $tagMgr = new OC\Tags($this->user); + $tagMgr->loadTagsFor($this->objectType); + $this->assertTrue($tagMgr->addToFavorites(1)); + $this->assertTrue($tagMgr->removeFromFavorites(1)); } } -- cgit v1.2.3 From 8fab9eef28d2146c2c65f7e7f1aa826216915301 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 19 Sep 2013 13:55:45 +0200 Subject: Add another test. --- tests/lib/tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 16a03f5645a..92a96a14772 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -94,7 +94,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $tagMgr->add('Tag'); + $this->assertNotEquals(false, $tagMgr->add('Tag')); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From f022ea752ddd86feccaaf5f1f83f808fd6df5e20 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 23 Sep 2013 15:52:50 +0200 Subject: Moar tests. --- tests/lib/tags.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 92a96a14772..75db9f50f72 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -59,13 +59,14 @@ class Test_Tags extends PHPUnit_Framework_TestCase { foreach($tags as $tag) { $result = $tagMgr->add($tag); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertTrue((bool)$result); } $this->assertFalse($tagMgr->add('Family')); $this->assertFalse($tagMgr->add('fAMILY')); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Wrong number of added tags'); } public function testAddMultiple() { @@ -85,7 +86,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertTrue($tagMgr->hasTag($tag)); } - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertCount(4, $tagMgr->getTags(), 'Not all tags added'); } public function testIsEmpty() { @@ -94,7 +95,10 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->assertEquals(0, count($tagMgr->getTags())); $this->assertTrue($tagMgr->isEmpty()); - $this->assertNotEquals(false, $tagMgr->add('Tag')); + + $result = $tagMgr->add('Tag'); + $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); + $this->assertNotEquals(false, $result, 'add() returned false'); $this->assertFalse($tagMgr->isEmpty()); } -- cgit v1.2.3 From aaed871cee445633cb81f0aa230ba2f65c667803 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 24 Sep 2013 17:10:01 +0200 Subject: Add factory class for the server container. --- lib/public/iservercontainer.php | 3 +- lib/public/itagmanager.php | 48 +++++++++++++++++++++ lib/public/itags.php | 9 ---- lib/server.php | 3 +- lib/tagmanager.php | 68 ++++++++++++++++++++++++++++++ lib/tags.php | 28 +++++++++---- tests/lib/tags.php | 92 +++++++++++++++++++---------------------- 7 files changed, 182 insertions(+), 69 deletions(-) create mode 100644 lib/public/itagmanager.php create mode 100644 lib/tagmanager.php (limited to 'tests') diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 0df746a28ed..f37bdb10f8f 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -58,7 +58,8 @@ interface IServerContainer { /** * Returns the tag manager which can get and set tags for different object types * - * @return \OCP\ITags + * @see \OCP\ITagManager::load() + * @return \OCP\ITagManager */ function getTagManager(); diff --git a/lib/public/itagmanager.php b/lib/public/itagmanager.php new file mode 100644 index 00000000000..07e1d12fc0f --- /dev/null +++ b/lib/public/itagmanager.php @@ -0,0 +1,48 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OCP; + +interface ITagManager { + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()); + +} \ No newline at end of file diff --git a/lib/public/itags.php b/lib/public/itags.php index 12643400548..5b1ebd189da 100644 --- a/lib/public/itags.php +++ b/lib/public/itags.php @@ -38,15 +38,6 @@ namespace OCP; interface ITags { - /** - * Load tags from db. - * - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags - */ - public function loadTagsFor($type, $defaultTags=array()); - /** * Check if any tags are saved for this type and user. * diff --git a/lib/server.php b/lib/server.php index f3c79aa797f..c47f0e2b461 100644 --- a/lib/server.php +++ b/lib/server.php @@ -146,7 +146,8 @@ class Server extends SimpleContainer implements IServerContainer { /** * Returns the tag manager which can get and set tags for different object types * - * @return \OCP\ITags + * @see \OCP\ITagManager::load() + * @return \OCP\ITagManager */ function getTagManager() { return $this->query('TagManager'); diff --git a/lib/tagmanager.php b/lib/tagmanager.php new file mode 100644 index 00000000000..9a371a11253 --- /dev/null +++ b/lib/tagmanager.php @@ -0,0 +1,68 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class TagManager implements \OCP\ITagManager { + + /** + * User + * + * @var string + */ + private $user = null; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()) { + return new Tags($this->user, $type, $defaultTags); + } + +} \ No newline at end of file diff --git a/lib/tags.php b/lib/tags.php index ff9f35ebc9e..9fdb35a7d6e 100644 --- a/lib/tags.php +++ b/lib/tags.php @@ -38,15 +38,30 @@ class Tags implements \OCP\ITags { /** * Tags + * + * @var array */ private $tags = array(); /** * Used for storing objectid/categoryname pairs while rescanning. + * + * @var array */ private static $relations = array(); + /** + * Type + * + * @var string + */ private $type = null; + + /** + * User + * + * @var string + */ private $user = null; const TAG_TABLE = '*PREFIX*vcategory'; @@ -59,10 +74,10 @@ class Tags implements \OCP\ITags { * * @param string $user The user whos data the object will operate on. */ - public function __construct($user) { - + public function __construct($user, $type, $defaultTags = array()) { $this->user = $user; - + $this->type = $type; + $this->loadTags($defaultTags); } /** @@ -70,10 +85,8 @@ class Tags implements \OCP\ITags { * * @param string $type The type identifier e.g. 'contact' or 'event'. * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags */ - public function loadTagsFor($type, $defaultTags=array()) { - $this->type = $type; + protected function loadTags($defaultTags=array()) { $this->tags = array(); $result = null; $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' @@ -101,7 +114,6 @@ class Tags implements \OCP\ITags { \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), \OCP\Util::DEBUG); - return $this; } /** @@ -345,7 +357,7 @@ class Tags implements \OCP\ITags { } } // reload tags to get the proper ids. - $this->loadTagsFor($this->type); + $this->loadTags(); // Loop through temporarily cached objectid/tagname pairs // and save relations. $tags = $this->tags; diff --git a/tests/lib/tags.php b/tests/lib/tags.php index 75db9f50f72..97e3734cfda 100644 --- a/tests/lib/tags.php +++ b/tests/lib/tags.php @@ -34,6 +34,7 @@ class Test_Tags extends PHPUnit_Framework_TestCase { $this->objectType = uniqid('type_'); OC_User::createUser($this->user, 'pass'); OC_User::setUserId($this->user); + $this->tagMgr = new OC\TagManager($this->user); } @@ -45,102 +46,95 @@ class Test_Tags extends PHPUnit_Framework_TestCase { public function testInstantiateWithDefaults() { $defaultTags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertEquals(4, count($tagger->getTags())); } public function testAddTags() { $tags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($tags as $tag) { - $result = $tagMgr->add($tag); + $result = $tagger->add($tag); $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertTrue((bool)$result); } - $this->assertFalse($tagMgr->add('Family')); - $this->assertFalse($tagMgr->add('fAMILY')); + $this->assertFalse($tagger->add('Family')); + $this->assertFalse($tagger->add('fAMILY')); - $this->assertCount(4, $tagMgr->getTags(), 'Wrong number of added tags'); + $this->assertCount(4, $tagger->getTags(), 'Wrong number of added tags'); } public function testAddMultiple() { $tags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($tags as $tag) { - $this->assertFalse($tagMgr->hasTag($tag)); + $this->assertFalse($tagger->hasTag($tag)); } - $result = $tagMgr->addMultiple($tags); + $result = $tagger->addMultiple($tags); $this->assertTrue((bool)$result); foreach($tags as $tag) { - $this->assertTrue($tagMgr->hasTag($tag)); + $this->assertTrue($tagger->hasTag($tag)); } - $this->assertCount(4, $tagMgr->getTags(), 'Not all tags added'); + $this->assertCount(4, $tagger->getTags(), 'Not all tags added'); } public function testIsEmpty() { - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); - $this->assertEquals(0, count($tagMgr->getTags())); - $this->assertTrue($tagMgr->isEmpty()); + $this->assertEquals(0, count($tagger->getTags())); + $this->assertTrue($tagger->isEmpty()); - $result = $tagMgr->add('Tag'); + $result = $tagger->add('Tag'); $this->assertGreaterThan(0, $result, 'add() returned an ID <= 0'); $this->assertNotEquals(false, $result, 'add() returned false'); - $this->assertFalse($tagMgr->isEmpty()); + $this->assertFalse($tagger->isEmpty()); } public function testdeleteTags() { $defaultTags = array('Friends', 'Family', 'Work', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertEquals(4, count($tagMgr->getTags())); + $this->assertEquals(4, count($tagger->getTags())); - $tagMgr->delete('family'); - $this->assertEquals(3, count($tagMgr->getTags())); + $tagger->delete('family'); + $this->assertEquals(3, count($tagger->getTags())); - $tagMgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEquals(0, count($tagMgr->getTags())); + $tagger->delete(array('Friends', 'Work', 'Other')); + $this->assertEquals(0, count($tagger->getTags())); } public function testRenameTag() { $defaultTags = array('Friends', 'Family', 'Wrok', 'Other'); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType, $defaultTags); + $tagger = $this->tagMgr->load($this->objectType, $defaultTags); - $this->assertTrue($tagMgr->rename('Wrok', 'Work')); - $this->assertTrue($tagMgr->hasTag('Work')); - $this->assertFalse($tagMgr->hastag('Wrok')); - $this->assertFalse($tagMgr->rename('Wrok', 'Work')); + $this->assertTrue($tagger->rename('Wrok', 'Work')); + $this->assertTrue($tagger->hasTag('Work')); + $this->assertFalse($tagger->hastag('Wrok')); + $this->assertFalse($tagger->rename('Wrok', 'Work')); } public function testTagAs() { $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($objids as $id) { - $tagMgr->tagAs($id, 'Family'); + $tagger->tagAs($id, 'Family'); } - $this->assertEquals(1, count($tagMgr->getTags())); - $this->assertEquals(9, count($tagMgr->getIdsForTag('Family'))); + $this->assertEquals(1, count($tagger->getTags())); + $this->assertEquals(9, count($tagger->getIdsForTag('Family'))); } /** @@ -151,24 +145,22 @@ class Test_Tags extends PHPUnit_Framework_TestCase { // Is this "legal"? $this->testTagAs(); - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); + $tagger = $this->tagMgr->load($this->objectType); foreach($objIds as $id) { - $this->assertTrue(in_array($id, $tagMgr->getIdsForTag('Family'))); - $tagMgr->unTag($id, 'Family'); - $this->assertFalse(in_array($id, $tagMgr->getIdsForTag('Family'))); + $this->assertTrue(in_array($id, $tagger->getIdsForTag('Family'))); + $tagger->unTag($id, 'Family'); + $this->assertFalse(in_array($id, $tagger->getIdsForTag('Family'))); } - $this->assertEquals(1, count($tagMgr->getTags())); - $this->assertEquals(0, count($tagMgr->getIdsForTag('Family'))); + $this->assertEquals(1, count($tagger->getTags())); + $this->assertEquals(0, count($tagger->getIdsForTag('Family'))); } public function testFavorite() { - $tagMgr = new OC\Tags($this->user); - $tagMgr->loadTagsFor($this->objectType); - $this->assertTrue($tagMgr->addToFavorites(1)); - $this->assertTrue($tagMgr->removeFromFavorites(1)); + $tagger = $this->tagMgr->load($this->objectType); + $this->assertTrue($tagger->addToFavorites(1)); + $this->assertTrue($tagger->removeFromFavorites(1)); } } -- cgit v1.2.3