diff --git a/tests/Core/Controller/JsControllerTest.php b/tests/Core/Controller/JsControllerTest.php new file mode 100644 index 0000000000..febb785f60 --- /dev/null +++ b/tests/Core/Controller/JsControllerTest.php @@ -0,0 +1,110 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace Tests\Core\Controller; + +use OC\Core\Controller\JsController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Files\IAppData; +use OCP\Files\NotFoundException; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Files\SimpleFS\ISimpleFolder; +use OCP\IRequest; +use Test\TestCase; + +class JsControllerTest extends TestCase { + + /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */ + private $appData; + + /** @var JsController */ + private $controller; + + public function setUp() { + parent::setUp(); + + $this->appData = $this->createMock(IAppData::class); + + $timeFactory = $this->createMock(ITimeFactory::class); + $timeFactory->method('getTime') + ->willReturn(1337); + + $this->controller = new JsController( + 'core', + $this->createMock(IRequest::class), + $this->appData, + $timeFactory + ); + } + + public function testNoCssFolderForApp() { + $this->appData->method('getFolder') + ->with('myapp') + ->willThrowException(new NotFoundException()); + + $result = $this->controller->getJs('file.css', 'myapp'); + + $this->assertInstanceOf(NotFoundResponse::class, $result); + } + + + public function testNoCssFile() { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->method('getFolder') + ->with('myapp') + ->willReturn($folder); + + $folder->method('getFile') + ->willThrowException(new NotFoundException()); + + $result = $this->controller->getJs('file.css', 'myapp'); + + $this->assertInstanceOf(NotFoundResponse::class, $result); + } + + public function testGetFile() { + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $this->appData->method('getFolder') + ->with('myapp') + ->willReturn($folder); + + $folder->method('getFile') + ->with('file.js') + ->willReturn($file); + + $expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'application/javascript']); + $expected->cacheFor(86400); + $expires = new \DateTime(); + $expires->setTimestamp(1337); + $expires->add(new \DateInterval('PT24H')); + $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); + $expected->addHeader('Pragma', 'cache'); + + $result = $this->controller->getJs('file.js', 'myapp'); + $this->assertEquals($expected, $result); + } + +} diff --git a/tests/lib/Template/JSCombinerTest.php b/tests/lib/Template/JSCombinerTest.php new file mode 100644 index 0000000000..6e4ef5735d --- /dev/null +++ b/tests/lib/Template/JSCombinerTest.php @@ -0,0 +1,268 @@ +appData = $this->createMock(IAppData::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->config = $this->createMock(SystemConfig::class); + $this->depsCache = $this->createMock(ICache::class); + $this->jsCombiner = new JSCombiner( + $this->appData, + $this->urlGenerator, + $this->depsCache, + $this->config); + } + + public function testProcessUncachedFileNoAppDataFolder() { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->expects($this->once())->method('getFolder')->with('awesomeapp')->willThrowException(new NotFoundException()); + $this->appData->expects($this->once())->method('newFolder')->with('awesomeapp')->willReturn($folder); + $file = $this->createMock(ISimpleFile::class); + + $fileDeps = $this->createMock(ISimpleFile::class); + + $folder->method('getFile') + ->will($this->returnCallback(function($path) use ($file) { + if ($path === 'combine.js') { + return $file; + } else if ($path === 'combine.js.deps') { + throw new NotFoundException(); + } else { + $this->fail(); + } + })); + $folder->expects($this->once()) + ->method('newFile') + ->with('combine.js.deps') + ->willReturn($fileDeps); + + $actual = $this->jsCombiner->process(__DIR__, '/data/combine.json', 'awesomeapp'); + $this->assertTrue($actual); + } + + public function testProcessUncachedFile() { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->expects($this->once())->method('getFolder')->with('awesomeapp')->willReturn($folder); + $file = $this->createMock(ISimpleFile::class); + + $fileDeps = $this->createMock(ISimpleFile::class); + + $folder->method('getFile') + ->will($this->returnCallback(function($path) use ($file) { + if ($path === 'combine.js') { + return $file; + } else if ($path === 'combine.js.deps') { + throw new NotFoundException(); + } else { + $this->fail(); + } + })); + $folder->expects($this->once()) + ->method('newFile') + ->with('combine.js.deps') + ->willReturn($fileDeps); + + $actual = $this->jsCombiner->process(__DIR__, '/data/combine.json', 'awesomeapp'); + $this->assertTrue($actual); + } + + public function testProcessCachedFile() { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->expects($this->once())->method('getFolder')->with('awesomeapp')->willReturn($folder); + $file = $this->createMock(ISimpleFile::class); + + $fileDeps = $this->createMock(ISimpleFile::class); + + $fileDeps->expects($this->once())->method('getContent')->willReturn('{}'); + + $folder->method('getFile') + ->will($this->returnCallback(function($path) use ($file, $fileDeps) { + if ($path === 'combine.js') { + return $file; + } else if ($path === 'combine.js.deps') { + return $fileDeps; + } else { + $this->fail(); + } + })); + + $actual = $this->jsCombiner->process(__DIR__, '/data/combine.json', 'awesomeapp'); + $this->assertTrue($actual); + } + + public function testProcessCachedFileMemcache() { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->expects($this->once()) + ->method('getFolder') + ->with('awesomeapp') + ->willReturn($folder); + $folder->method('getName') + ->willReturn('awesomeapp'); + + $file = $this->createMock(ISimpleFile::class); + + $this->depsCache->method('get') + ->with('awesomeapp-combine.js.deps') + ->willReturn('{}'); + + $folder->method('getFile') + ->will($this->returnCallback(function($path) use ($file) { + if ($path === 'combine.js') { + return $file; + } else if ($path === 'combine.js.deps') { + $this->fail(); + } else { + $this->fail(); + } + })); + + $actual = $this->jsCombiner->process(__DIR__, '/data/combine.json', 'awesomeapp'); + $this->assertTrue($actual); + } + + public function testIsCachedNoDepsFile() { + $fileName = "combine.json"; + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + + $folder->method('getFile') + ->will($this->returnCallback(function($path) use ($file) { + if ($path === 'combine.js') { + return $file; + } else if ($path === 'combine.js.deps') { + throw new NotFoundException(); + } else { + $this->fail(); + } + })); + + $actual = self::invokePrivate($this->jsCombiner, 'isCached', [$fileName, $folder]); + $this->assertFalse($actual); + } + public function testCacheNoFile() { + $fileName = "combine.js"; + + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $depsFile = $this->createMock(ISimpleFile::class); + + $path = __DIR__ . '/data/'; + + $folder->expects($this->at(0))->method('getFile')->with($fileName)->willThrowException(new NotFoundException()); + $folder->expects($this->at(1))->method('newFile')->with($fileName)->willReturn($file); + $folder->expects($this->at(2))->method('getFile')->with($fileName . '.deps')->willThrowException(new NotFoundException()); + $folder->expects($this->at(3))->method('newFile')->with($fileName . '.deps')->willReturn($depsFile); + + $file->expects($this->once())->method('putContent'); + $depsFile->expects($this->once())->method('putContent'); + + $actual = self::invokePrivate($this->jsCombiner, 'cache', [$path, 'combine.json', $folder]); + $this->assertTrue($actual); + } + + public function testCache() { + $fileName = "combine.js"; + + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $depsFile = $this->createMock(ISimpleFile::class); + + $path = __DIR__ . '/data/'; + + $folder->expects($this->at(0))->method('getFile')->with($fileName)->willReturn($file); + $folder->expects($this->at(1))->method('getFile')->with($fileName . '.deps')->willReturn($depsFile); + + $file->expects($this->once())->method('putContent'); + $depsFile->expects($this->once())->method('putContent'); + + $actual = self::invokePrivate($this->jsCombiner, 'cache', [$path, 'combine.json', $folder]); + $this->assertTrue($actual); + } + + public function testCacheSuccess() { + $fileName = 'combine.js'; + + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $depsFile = $this->createMock(ISimpleFile::class); + + $path = __DIR__ . '/data/'; + + $folder->expects($this->at(0))->method('getFile')->with($fileName)->willReturn($file); + $folder->expects($this->at(1))->method('getFile')->with($fileName . '.deps')->willReturn($depsFile); + + $file->expects($this->at(0)) + ->method('putContent') + ->with('var a = \'hello\'; + + +var b = \'world\'; + + +'); + $depsFile->expects($this->at(0))->method('putContent')->with($this->callback( + function ($content) { + $deps = json_decode($content, true); + return array_key_exists(__DIR__ . '/data//1.js', $deps) + && array_key_exists(__DIR__ . '/data//2.js', $deps); + })); + + $actual = self::invokePrivate($this->jsCombiner, 'cache', [$path, 'combine.json', $folder]); + $this->assertTrue($actual); + } + + public function dataGetCachedSCSS() { + return [ + ['awesomeapp', 'core/js/foo.json', '/js/core/foo.js'], + ['files', 'apps/files/js/foo.json', '/js/files/foo.js'] + ]; + } + + /** + * @param $appName + * @param $fileName + * @param $result + * @dataProvider dataGetCachedSCSS + */ + public function testGetCachedSCSS($appName, $fileName, $result) { + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.Js.getJs', [ + 'fileName' => 'foo.js', + 'appName' => $appName + ]) + ->willReturn(\OC::$WEBROOT . $result); + + $actual = $this->jsCombiner->getCachedJS($appName, $fileName); + $this->assertEquals(substr($result, 1), $actual); + } + + +} diff --git a/tests/lib/Template/data/1.js b/tests/lib/Template/data/1.js new file mode 100644 index 0000000000..ab3d260180 --- /dev/null +++ b/tests/lib/Template/data/1.js @@ -0,0 +1 @@ +var a = 'hello'; diff --git a/tests/lib/Template/data/2.js b/tests/lib/Template/data/2.js new file mode 100644 index 0000000000..4fd3078d7a --- /dev/null +++ b/tests/lib/Template/data/2.js @@ -0,0 +1 @@ +var b = 'world'; diff --git a/tests/lib/Template/data/combine.json b/tests/lib/Template/data/combine.json new file mode 100644 index 0000000000..e727cbdba8 --- /dev/null +++ b/tests/lib/Template/data/combine.json @@ -0,0 +1,4 @@ +[ + "1.js", + "2.js" +]