<NME> init.php
<BEF> ADDFILE
<MSG> move test files into root folder and start work on writing tests

<DFF> @@ -0,0 +1,3 @@
+<?php
+
+$app['extensions']->register(new MockLocalExtension($app));
\ No newline at end of file

{'commit': 'diff --git a/tests/Bolt/Tests/ApplicationTest.php b/tests/ApplicationTest.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/ApplicationTest.php\nrename to tests/ApplicationTest.php\ndiff --git a/tests/BoltUnitTest.php b/tests/BoltUnitTest.php\nnew file mode 100644\nindex 000000000..cf2713382\n--- /dev/null\n+++ b/tests/BoltUnitTest.php\n@@ -0,0 +1,77 @@\n+<?php\n+namespace Bolt\\Tests;\n+\n+use Bolt\\Application;\n+use Symfony\\Component\\HttpFoundation\\Request;\n+use Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockFileSessionStorage;\n+use Symfony\\Component\\HttpFoundation\\File\\UploadedFile;\n+use Bolt\\Configuration as Config;\n+use Eloquent\\Pathogen\\FileSystem\\Factory\\PlatformFileSystemPathFactory;\n+use Bolt\\Configuration\\ResourceManager;\n+\n+/**\n+ * Abstract Class that other unit tests can extend, provides generic methods for Bolt tests.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ **/\n+\n+\n+abstract class BoltUnitTest extends \\PHPUnit_Framework_TestCase\n+{\n+\n+\n+    protected function getApp()\n+    {\n+        $bolt = $this->makeApp();\n+        $bolt->initialize();\n+        return $bolt;\n+    }\n+    \n+    protected function makeApp()\n+    {\n+        $sessionMock = $this->getMockBuilder(\'Symfony\\Component\\HttpFoundation\\Session\\Session\')\n+        ->setMethods(array(\'clear\'))\n+        ->setConstructorArgs(array(new MockFileSessionStorage()))\n+        ->getMock();\n+\n+        $config = new ResourceManager(\n+            new \\Pimple(\n+                array(\n+                    \'rootpath\' => TEST_ROOT,\n+                    \'pathmanager\' => new PlatformFileSystemPathFactory()\n+                )\n+            )\n+        );\n+        $config->compat();\n+\n+        $bolt = new Application(array(\'resources\' => $config));\n+        $bolt[\'config\']->set(\n+            \'general/database\',\n+            array(\n+                \'driver\' => \'sqlite\',\n+                \'databasename\' => \'test\',\n+                \'username\' => \'test\',\n+                \'memory\' => true\n+            )\n+        );\n+\n+        $bolt[\'session\'] = $sessionMock;\n+        $bolt[\'resources\']->setPath(\'files\', __DIR__ . \'/files\');\n+        return $bolt;\n+    }\n+\n+    protected function rmdir($dir)\n+    {\n+        $iterator = new \\RecursiveIteratorIterator(\n+            new \\RecursiveDirectoryIterator($dir, \\FilesystemIterator::SKIP_DOTS),\n+            \\RecursiveIteratorIterator::CHILD_FIRST\n+        );\n+        foreach ($iterator as $file) {\n+            if ($file->isDir()) {\n+                rmdir($file->getPathname());\n+            } else {\n+                unlink($file->getPathname());\n+            }\n+        }\n+    }\n+}\ndiff --git a/tests/Bolt/Tests/CacheTest.php b/tests/CacheTest.php\nsimilarity index 98%\nrename from tests/Bolt/Tests/CacheTest.php\nrename to tests/CacheTest.php\nindex 30c25f209..5a6a8fe5a 100644\n--- a/tests/Bolt/Tests/CacheTest.php\n+++ b/tests/CacheTest.php\n@@ -90,7 +90,7 @@ class CacheTest extends \\PHPUnit_Framework_TestCase\n     {\n         $cacheDirLocation = $this->cache->getDirectory();\n         $filesystem = new Filesystem();\n-        $relative = $filesystem->makePathRelative($cacheDirLocation, realpath(__DIR__ . \'/../../../src\'));\n+        $relative = $filesystem->makePathRelative($cacheDirLocation, realpath(__DIR__ . \'/../src\'));\n         $newCache = new Cache($relative);\n         $this->assertEquals($cacheDirLocation, $newCache->getDirectory());\n     }\ndiff --git a/tests/Configuration/ComposerConfigurationTest.php b/tests/Configuration/ComposerConfigurationTest.php\nnew file mode 100644\nindex 000000000..a2eeeb243\n--- /dev/null\n+++ b/tests/Configuration/ComposerConfigurationTest.php\n@@ -0,0 +1,43 @@\n+<?php\n+namespace Bolt\\Tests\\Configuration;\n+\n+use Bolt\\Application;\n+use Bolt\\Configuration\\Composer;\n+use Bolt\\Configuration\\ComposerChecks;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class ComposerConfigurationTest extends \\PHPUnit_Framework_TestCase\n+{\n+\n+    public function setup()\n+    {\n+\n+    }\n+\n+    public function tearDown()\n+    {\n+    }\n+\n+    \n+    public function testComposerCustomConfig()\n+    {\n+        $config = new Composer(TEST_ROOT);\n+        $app = new Application(array(\'resources\' => $config));\n+        $this->assertEquals(\'/bolt-public/\', $config->getUrl(\'app\'));\n+    }\n+    \n+    public function testComposerVerification()\n+    {\n+        $config = new Composer(TEST_ROOT);\n+        $verifier = new ComposerChecks($config);\n+        $config->setVerifier($verifier);\n+        $config->verify(); \n+    }\n+\n+   \n+}\ndiff --git a/tests/Configuration/ConfigVerificationTest.php b/tests/Configuration/ConfigVerificationTest.php\nnew file mode 100644\nindex 000000000..169290085\n--- /dev/null\n+++ b/tests/Configuration/ConfigVerificationTest.php\n@@ -0,0 +1,28 @@\n+<?php\n+namespace Bolt\\Tests\\Configuration;\n+\n+use Bolt\\Application;\n+use Bolt\\Configuration\\Standard;\n+use Bolt\\Configuration\\LowlevelChecks;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class ConfigVerificationTest extends \\PHPUnit_Framework_TestCase\n+{\n+\n+    \n+    public function testInitWithVerifier()\n+    {\n+        $config = new Standard(getcwd());\n+        $verifier = new LowlevelChecks($config);\n+        $config->setVerifier($verifier);\n+        $config->verify();        \n+        \n+    }\n+\n+   \n+}\ndiff --git a/tests/Bolt/Tests/ResourceManagerTest.php b/tests/Configuration/ResourceManagerTest.php\nsimilarity index 85%\nrename from tests/Bolt/Tests/ResourceManagerTest.php\nrename to tests/Configuration/ResourceManagerTest.php\nindex 563bd501d..df04aae73 100644\n--- a/tests/Bolt/Tests/ResourceManagerTest.php\n+++ b/tests/Configuration/ResourceManagerTest.php\n@@ -1,11 +1,12 @@\n <?php\n-namespace Bolt\\Tests;\n+namespace Bolt\\Tests\\Configuration;\n \n use Bolt\\Application;\n use Bolt\\Configuration\\ResourceManager;\n use Bolt\\Configuration\\Composer;\n+use Bolt\\Configuration\\Standard;\n use Symfony\\Component\\HttpFoundation\\Request;\n-use Eloquent\\Pathogen\\FileSystem\\PlatformFileSystemPath;\n+use Eloquent\\Pathogen\\FileSystem\\PlatformFileSystemPath as Path;\n use Eloquent\\Pathogen\\FileSystem\\Factory\\PlatformFileSystemPathFactory;\n \n /**\n@@ -36,7 +37,7 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n             )\n         );\n         $config = new ResourceManager($container);\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT), \\PHPUnit_Framework_Assert::readAttribute($config, \'root\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT), \\PHPUnit_Framework_Assert::readAttribute($config, \'root\'));\n     }\n \n     public function testDefaultPaths()\n@@ -49,13 +50,13 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n                 )\n             )\n         );\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT), $config->getPath(\'rootpath\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/app\'), $config->getPath(\'apppath\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/extensions\'), $config->getPath(\'extensions\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/files\'), $config->getPath(\'filespath\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/.\'), $config->getPath(\'web\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/app/cache\'), $config->getPath(\'cache\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/app/config\'), $config->getPath(\'config\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT), $config->getPath(\'rootpath\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/app\'), $config->getPath(\'apppath\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/extensions\'), $config->getPath(\'extensions\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/files\'), $config->getPath(\'filespath\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/.\'), $config->getPath(\'web\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/app/cache\'), $config->getPath(\'cache\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/app/config\'), $config->getPath(\'config\'));\n      }\n \n     /**\n@@ -97,9 +98,9 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n                 )\n             )\n         );\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT), $config->getPath(\'root\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/app\'), $config->getPath(\'app\'));\n-        $this->assertEquals(PlatformFileSystemPath::fromString(TEST_ROOT . \'/files\'), $config->getPath(\'files\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT), $config->getPath(\'root\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/app\'), $config->getPath(\'app\'));\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/files\'), $config->getPath(\'files\'));\n     }\n \n     public function testDefaultUrls()\n@@ -165,7 +166,7 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n         $this->assertEquals($config->getPaths(), $app[\'resources\']->getPaths());\n \n         // Test that the Application has initialised the resources, injecting in config values.\n-        $this->assertContains(PlatformFileSystemPath::fromString(TEST_ROOT . \'/theme\')->string(), $config->getPath(\'theme\'));\n+        $this->assertContains(Path::fromString(TEST_ROOT . \'/theme\')->string(), $config->getPath(\'theme\'));\n         $this->assertNotEmpty($config->getUrl(\'canonical\'));\n     }\n \n@@ -246,13 +247,6 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n         $this->assertEquals(\'https://bolt.dev/bolt/test/location\', $config->getUrl(\'canonical\'));\n     }\n \n-    public function testComposerCustomConfig()\n-    {\n-        $config = new Composer(TEST_ROOT);\n-        $config->compat();\n-        $app = new Application(array(\'resources\' => $config));\n-        $this->assertEquals(\'/bolt-public/\', $config->getUrl(\'app\'));\n-    }\n \n     public function testNonRootDirectory()\n     {\n@@ -366,4 +360,16 @@ class ResourceManagerTest extends \\PHPUnit_Framework_TestCase\n         $rel = $config->findRelativePath(TEST_ROOT, TEST_ROOT . \'/A/B\');\n         $this->assertEquals(\'A/B/\', $rel);\n     }\n+    \n+    public function testSetThemePath()\n+    {\n+        $config = new Standard(TEST_ROOT);\n+        $theme = array(\'theme\'=>\'test\');\n+        $config->setThemePath($theme);\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/theme/test\'), $config->getPath(\'theme\'));\n+        $theme = array(\'theme\'=>\'test\', \'theme_path\'=>\'/testpath\');\n+        $config->setThemePath($theme);\n+        $this->assertEquals(Path::fromString(TEST_ROOT . \'/testpath/test\'), $config->getPath(\'theme\'));\n+    }\n+    \n }\ndiff --git a/tests/Configuration/StandardConfigurationTest.php b/tests/Configuration/StandardConfigurationTest.php\nnew file mode 100644\nindex 000000000..0d3baf7ad\n--- /dev/null\n+++ b/tests/Configuration/StandardConfigurationTest.php\n@@ -0,0 +1,27 @@\n+<?php\n+namespace Bolt\\Tests\\Configuration;\n+\n+use Bolt\\Application;\n+use Bolt\\Configuration\\Standard;\n+use Composer\\Autoload\\ClassLoader;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class StandardConfigurationTest extends \\PHPUnit_Framework_TestCase\n+{\n+\n+    \n+    public function testInitWithClassloader()\n+    {\n+        $loader = require __DIR__."/../../vendor/autoload.php";\n+        $config = new Standard($loader);\n+        $app = new Application(array(\'resources\' => $config));\n+        $this->assertEquals(\'/app/\', $config->getUrl(\'app\'));\n+    }\n+\n+   \n+}\ndiff --git a/tests/Bolt/Tests/DeepDiffTest.php b/tests/DeepDiffTest.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/DeepDiffTest.php\nrename to tests/DeepDiffTest.php\ndiff --git a/tests/Extensions/ExtensionsProviderTest.php b/tests/Extensions/ExtensionsProviderTest.php\nnew file mode 100644\nindex 000000000..ee5cbc6fa\n--- /dev/null\n+++ b/tests/Extensions/ExtensionsProviderTest.php\n@@ -0,0 +1,487 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions;\n+\n+use Bolt\\Application;\n+use Bolt\\Configuration\\Standard;\n+use Bolt\\Extensions;\n+use Bolt\\Tests\\BoltUnitTest;\n+use Bolt\\Extensions\\Snippets\\Location as SnippetLocation;\n+\n+\n+/**\n+ * Class to test correct operation and locations of extensions.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class ExtensionsProviderTest extends BoltUnitTest\n+{\n+    \n+    public $template = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedCss = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="testfile.css" media="screen">\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedLateCss = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+<link rel="stylesheet" href="testfile.css" media="screen">\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedJs = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+<script src="testfile.js"></script>\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedLateJs = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+<script src="testfile.js"></script>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedStartOfHead = <<< EOM\n+<html>\n+<head>\n+<meta name="test-snippet" />\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedEndOfHead = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+<meta name="test-snippet" />\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedStartOfBody = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+<p class="test-snippet"></p>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedEndOfHtml = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+<p class="test-snippet"></p>\n+</html>\n+EOM;\n+\n+    public $expectedBeforeCss = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<meta name="test-snippet" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedAfterCss = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+<meta name="test-snippet" />\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+\n+    public $expectedAfterMeta = <<< EOM\n+<html>\n+<head>\n+<meta charset="utf-8" />\n+<meta name="test-snippet" />\n+<link rel="stylesheet" href="existing.css" media="screen">\n+</head>\n+<body>\n+</body>\n+</html>\n+EOM;\n+    \n+    \n+    public function testExtensionRegister()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\Extension($app));\n+        $this->assertTrue(isset($app[\'extensions\']));\n+        $this->assertTrue($app[\'extensions\']->isEnabled(\'testext\'));\n+        $app[\'extensions\']->register(new Mock\\Extension($app));\n+    }\n+    \n+    public function testBadExtension()\n+    {\n+        $app = $this->getApp();\n+        $app[\'log\'] = new Mock\\Logger;\n+        $app[\'extensions\']->register(new Mock\\BadExtension($app));        \n+        $this->assertEquals(\'[EXT] Initialisation failed for badextension: BadExtension\', $app[\'log\']->lastLog());\n+        \n+    }\n+    \n+    public function testBadExtensionConfig()\n+    {\n+        $app = $this->getApp();\n+        $app[\'log\'] = new Mock\\Logger;\n+        $app[\'extensions\']->register(new Mock\\BadExtensionConfig($app));\n+        $this->assertEquals(\n+            \'[EXT] YAML config failed to load for badextensionconfig: BadExtensionConfig\', \n+            $app[\'log\']->lastLog()\n+        );\n+    }\n+    \n+    public function testBadExtensionSnippets()\n+    {\n+        $app = $this->getApp();\n+        $app[\'log\'] = new Mock\\Logger;\n+        $app[\'extensions\']->register(new Mock\\BadExtensionSnippets($app));\n+        $this->assertEquals(\n+            \'[EXT] Snippet loading failed for badextensionsnippets: BadExtensionSnippets\', \n+            $app[\'log\']->lastLog()\n+        );\n+    }\n+    \n+    public function testAddCss()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addCss(\'testfile.css\');\n+        $assets = $app[\'extensions\']->getAssets();\n+        $this->assertEquals(1, count($assets[\'css\']));  \n+    }\n+    \n+    public function testAddJs()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addJavascript(\'testfile.js\');\n+        $assets = $app[\'extensions\']->getAssets();\n+        $this->assertEquals(1, count($assets[\'js\']));  \n+    }\n+    \n+    public function testEmptyProcessAssets()\n+    {\n+        $app = $this->getApp();\n+        $html = $app[\'extensions\']->processAssets("html");\n+        $this->assertEquals("html", $html);\n+    }\n+    \n+    public function testJsProcessAssets()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addJavascript(\'testfile.js\');\n+        $html = $app[\'extensions\']->processAssets($this->template);\n+        $this->assertEquals($this->html($this->expectedJs), $this->html($html));\n+    }\n+    \n+    public function testLateJs()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addJavascript(\'testfile.js\', true);\n+        $html = $app[\'extensions\']->processAssets($this->template);\n+        $this->assertEquals($this->html($this->expectedLateJs),  $this->html($html)  );\n+\n+    }\n+    \n+    public function testCssProcessAssets()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addCss(\'testfile.css\');\n+        $html = $app[\'extensions\']->processAssets($this->template);\n+        $this->assertEquals($this->html($this->expectedCss), $this->html($html));\n+\n+    }\n+    \n+    public function testLateCss()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addCss(\'testfile.css\', true);\n+        $html = $app[\'extensions\']->processAssets($this->template);\n+        $this->assertEquals($this->html($this->expectedLateCss), $this->html($html));\n+    }\n+    \n+    \n+    // This method normalises the html so that differeing whitespace doesn\'t effect the strings.\n+    protected function html($string) {\n+        $doc = new \\DOMDocument();\n+        $doc->loadHTML($string, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);\n+        $doc->preserveWhitespace = false;\n+        $html = $doc->saveHTML();\n+        $html = str_replace("\\t", "", $html);\n+        $html = str_replace("\\n", "", $html);\n+        return $html;\n+    }\n+    \n+    \n+    public function testLocalload()\n+    {\n+        $app = $this->makeApp();\n+        $app[\'resources\']->setPath(\'extensions\', __DIR__."/resources");\n+        $app->initialize();\n+        $this->assertTrue($app[\'extensions\']->isEnabled(\'testlocal\'));\n+    }\n+    \n+    \n+    public function testSnippet()\n+    {\n+        $app = $this->getApp();\n+        \n+        // Test snippet inserts at top of <head>\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::START_OF_HEAD, \'<meta name="test-snippet" />\');\n+        \n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedStartOfHead), $this->html($html));\n+        \n+        \n+        // Test snippet inserts at end of <head>\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::END_OF_HEAD, \'<meta name="test-snippet" />\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedEndOfHead), $this->html($html));\n+        \n+        \n+        // Test snippet inserts at end of body\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::START_OF_BODY, \'<p class="test-snippet"></p>\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedStartOfBody), $this->html($html));\n+        \n+        // Test snippet inserts at end of </html>\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::END_OF_HTML, \'<p class="test-snippet"></p>\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedEndOfHtml), $this->html($html));\n+        \n+        \n+        // Test snippet inserts before existing css\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::BEFORE_CSS, \'<meta name="test-snippet" />\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedBeforeCss), $this->html($html));\n+        \n+        \n+        // Test snippet inserts after existing css\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::AFTER_CSS, \'<meta name="test-snippet" />\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedAfterCss), $this->html($html));\n+        \n+        \n+        // Test snippet inserts after existing meta tags\n+        $app[\'extensions\']->clearSnippetQueue();\n+        $app[\'extensions\']->insertSnippet(SnippetLocation::AFTER_META, \'<meta name="test-snippet" />\');\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedAfterMeta), $this->html($html));\n+        \n+    }\n+    \n+    public function testSnippetsWithCallback()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\SnippetCallbackExtension($app));\n+        \n+        // Test snippet inserts at top of <head>\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedStartOfHead), $this->html($html));\n+    }\n+    \n+    public function testSnippetsWithGlobalCallback()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->insertSnippet(\n+            SnippetLocation::AFTER_META, \n+            \'\\Bolt\\Tests\\Extensions\\globalSnippet\', \n+            \'core\', \n+            "\\n"\n+        );\n+        \n+        // Test snippet inserts at top of <head>\n+        $html = $app[\'extensions\']->processSnippetQueue("<html></html>");\n+        $this->assertEquals("<html></html><br />".PHP_EOL.PHP_EOL, $html);\n+    }\n+    \n+    \n+    public function testExtensionSnippets()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\Extension($app));\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertEquals($this->html($this->expectedEndOfHead), $this->html($html));\n+    }\n+    \n+    public function testAddJquery()\n+    {\n+        $app = $this->makeApp();\n+        $app[\'config\']->set(\'general/add_jquery\', true);\n+        $app->initialize();\n+        $app[\'extensions\']->register(new Mock\\Extension($app));\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertContains("js/jquery", $html);\n+        \n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\Extension($app));\n+        $app[\'extensions\']->addJquery();\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertContains("js/jquery", $html);\n+        $app[\'extensions\']->disableJquery();\n+        $html = $app[\'extensions\']->processSnippetQueue($this->template);\n+        $this->assertNotContains("js/jquery", $html);\n+    }\n+    \n+    public function testSnippetsWorkWithBadHtml()\n+    {\n+        $locations = array(\n+            SnippetLocation::START_OF_HEAD,\n+            SnippetLocation::START_OF_BODY,\n+            SnippetLocation::END_OF_BODY,\n+            SnippetLocation::END_OF_HTML,\n+            SnippetLocation::AFTER_META,\n+            SnippetLocation::AFTER_CSS,\n+            SnippetLocation::BEFORE_CSS,\n+            SnippetLocation::BEFORE_JS,\n+            SnippetLocation::AFTER_CSS\n+        );\n+        foreach ($locations as $location) {\n+            $app = $this->getApp();\n+            $template = "<invalid></invalid>";\n+            $snip = \'<meta name="test-snippet" />\';\n+            $app[\'extensions\']->insertSnippet($location, $snip);\n+            $html = $app[\'extensions\']->processSnippetQueue($template);\n+            $this->assertEquals($template.$snip.PHP_EOL, $html);\n+        }\n+\n+        \n+    }\n+    \n+    \n+    public function testAddMenuOption()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->addMenuOption(\'My Test\', \'mytest\');\n+        $this->assertTrue($app[\'extensions\']->hasMenuOptions());\n+        $this->assertEquals(1, count($app[\'extensions\']->getMenuOptions()));\n+    }\n+    \n+    public function testInsertWidget()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->insertWidget(\'test\', SnippetLocation::START_OF_BODY, "", "testext", "", false);\n+        $this->expectOutputString("<section><div class=\'widget\' id=\'widget-dacf7046\' data-key=\'dacf7046\'></div></section>");\n+        $app[\'extensions\']->renderWidgetHolder(\'test\', SnippetLocation::START_OF_BODY);\n+        \n+    }\n+    \n+    public function testInvalidWidget()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->insertWidget(\'test\', SnippetLocation::START_OF_BODY, "", "testext", "", false);\n+        $result = $app[\'extensions\']->renderWidget(\'fakekey\');\n+        $this->assertEquals("Invalid key \'fakekey\'. No widget found.", $result);\n+    }\n+    \n+    public function testWidgetWithCallback()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\SnippetCallbackExtension($app));\n+        \n+        $app[\'extensions\']->insertWidget(\'test\', SnippetLocation::START_OF_BODY, "snippetCallBack", "snippetcallback", "", false);\n+        $html = $app[\'extensions\']->renderWidget(\'c8a4f7f7\');\n+        $this->assertEquals(\'<meta name="test-snippet" />\', $html);\n+    }\n+    \n+    \n+    public function testWidgetWithGlobalCallback()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\SnippetCallbackExtension($app));\n+        \n+        $app[\'extensions\']->insertWidget(\n+            \'testglobal\', \n+            SnippetLocation::START_OF_BODY, \n+            "\\Bolt\\Tests\\Extensions\\globalWidget", \n+            "snippetcallback", \n+            "", \n+            false\n+        );\n+        $html = $app[\'extensions\']->renderWidget(\'7e2b9a48\');\n+        $this->assertEquals(\'<meta name="test-widget" />\', $html);\n+    }\n+    \n+    public function testTwigExtensions()\n+    {\n+        $app = $this->getApp();\n+        $app[\'extensions\']->register(new Mock\\ExtensionWithTwig($app));\n+    }\n+\n+   \n+}\n+\n+\n+function globalSnippet($app, $string)\n+{\n+    return nl2br($string);\n+}\n+\n+function globalWidget()\n+{\n+    return \'<meta name="test-widget" />\';\n+}\n+\ndiff --git a/tests/Extensions/Mock/BadExtension.php b/tests/Extensions/Mock/BadExtension.php\nnew file mode 100644\nindex 000000000..fea2588ca\n--- /dev/null\n+++ b/tests/Extensions/Mock/BadExtension.php\n@@ -0,0 +1,35 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class BadExtension extends Extension\n+{\n+\n+    \n+    public function initialize() \n+    {\n+        throw new \\Exception("BadExtension", 1);\n+        \n+    }\n+    \n+    public function getSnippets()\n+    {\n+        throw new \\Exception("BadExtensionSnippets", 1);\n+    }\n+\n+    \n+    public function getName()\n+    {\n+        return "badextension";\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/BadExtensionConfig.php b/tests/Extensions/Mock/BadExtensionConfig.php\nnew file mode 100644\nindex 000000000..246017937\n--- /dev/null\n+++ b/tests/Extensions/Mock/BadExtensionConfig.php\n@@ -0,0 +1,27 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class BadExtensionConfig extends Extension\n+{\n+\n+    public function getConfig()\n+    {\n+        throw new \\Exception("BadExtensionConfig", 1);\n+    }\n+    \n+    public function getName()\n+    {\n+        return "badextensionconfig";\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/BadExtensionSnippets.php b/tests/Extensions/Mock/BadExtensionSnippets.php\nnew file mode 100644\nindex 000000000..7baed1e39\n--- /dev/null\n+++ b/tests/Extensions/Mock/BadExtensionSnippets.php\n@@ -0,0 +1,28 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class BadExtensionSnippets extends Extension\n+{\n+\n+    public function getSnippets()\n+    {\n+        throw new \\Exception("BadExtensionSnippets", 1);\n+    }\n+\n+    \n+    public function getName()\n+    {\n+        return "badextensionsnippets";\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/Extension.php b/tests/Extensions/Mock/Extension.php\nnew file mode 100644\nindex 000000000..60bdcb30c\n--- /dev/null\n+++ b/tests/Extensions/Mock/Extension.php\n@@ -0,0 +1,49 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+use Bolt\\Extensions\\Snippets\\Location as SnippetLocation;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class Extension implements ExtensionInterface\n+{\n+\n+\n+    public function __construct(Application $app) \n+    {\n+        $this->app = $app;\n+    }\n+    \n+    public function initialize() \n+    {\n+        \n+    }\n+    \n+    public function getConfig()\n+    {\n+        \n+    }\n+    \n+    public function getSnippets()\n+    {\n+        return array(array(SnippetLocation::END_OF_HEAD, \'<meta name="test-snippet" />\'));\n+    }\n+    \n+    public function getExtensionConfig()\n+    {\n+        \n+    }\n+    \n+    public function getName()\n+    {\n+        return "testext";\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/ExtensionWithTwig.php b/tests/Extensions/Mock/ExtensionWithTwig.php\nnew file mode 100644\nindex 000000000..e8151e8da\n--- /dev/null\n+++ b/tests/Extensions/Mock/ExtensionWithTwig.php\n@@ -0,0 +1,28 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class ExtensionWithTwig extends Extension\n+{\n+\n+    \n+    public function getName()\n+    {\n+        return "extensionwithtwig";\n+    }\n+    \n+    public function getTwigExtensions()\n+    {\n+        return array();\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/Logger.php b/tests/Extensions/Mock/Logger.php\nnew file mode 100644\nindex 000000000..06e594d76\n--- /dev/null\n+++ b/tests/Extensions/Mock/Logger.php\n@@ -0,0 +1,31 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class Logger\n+{\n+    \n+    public $logs = array();\n+\n+    \n+    public function add($log, $level) \n+    {\n+        $this->logs[] =  $log;   \n+    }\n+\n+    \n+    public function lastLog()\n+    {\n+        return array_pop($this->logs);\n+    }\n+\n+   \n+}\ndiff --git a/tests/Extensions/Mock/SnippetCallbackExtension.php b/tests/Extensions/Mock/SnippetCallbackExtension.php\nnew file mode 100644\nindex 000000000..74007a9a6\n--- /dev/null\n+++ b/tests/Extensions/Mock/SnippetCallbackExtension.php\n@@ -0,0 +1,42 @@\n+<?php\n+namespace Bolt\\Tests\\Extensions\\Mock;\n+\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+use Bolt\\Extensions\\Snippets\\Location as SnippetLocation;\n+\n+/**\n+ * Class to test correct operation and locations of composer configuration.\n+ *\n+ * @author Ross Riley <riley.ross@gmail.com>\n+ *\n+ */\n+class SnippetCallbackExtension extends Extension\n+{\n+\n+    public function getSnippets()\n+    {\n+        return array(array(SnippetLocation::START_OF_HEAD, \'snippetCallBack\' ));\n+    }\n+    \n+    public function getName()\n+    {\n+        return "snippetcallback";\n+    }\n+\n+    public function snippetCallBack()\n+    {\n+        return \'<meta name="test-snippet" />\';\n+    }\n+    \n+    public function parseSnippet($callback, $var1 = "", $var2 = "", $var3 = "")\n+    {\n+        return call_user_func(array($this, $callback), $var1, $var2, $var3);\n+    }\n+    \n+    public function parseWidget($callback, $var1 = "", $var2 = "", $var3 = "")\n+    {\n+        return call_user_func(array($this, $callback), $var1, $var2, $var3);\n+    }\n+   \n+}\ndiff --git a/tests/Extensions/resources/local/testvendor/testext/Extension.php b/tests/Extensions/resources/local/testvendor/testext/Extension.php\nnew file mode 100644\nindex 000000000..4856c184c\n--- /dev/null\n+++ b/tests/Extensions/resources/local/testvendor/testext/Extension.php\n@@ -0,0 +1,39 @@\n+<?php\n+use Bolt\\Extensions\\ExtensionInterface;\n+use Bolt\\Application;\n+\n+class MockLocalExtension implements ExtensionInterface\n+{\n+    \n+    public function __construct(Application $app) \n+    {\n+        $this->app = $app;\n+    }\n+    \n+    public function getName()\n+    {\n+        return "testlocal";\n+    }\n+    \n+    \n+    \n+    public function initialize() \n+    {\n+        \n+    }\n+    \n+    public function getConfig()\n+    {\n+        \n+    }\n+    \n+    public function getSnippets()\n+    {\n+        \n+    }\n+    \n+    public function getExtensionConfig()\n+    {\n+        \n+    }\n+}\n\\ No newline at end of file\ndiff --git a/tests/Extensions/resources/local/testvendor/testext/init.php b/tests/Extensions/resources/local/testvendor/testext/init.php\nnew file mode 100644\nindex 000000000..27ddc590b\n--- /dev/null\n+++ b/tests/Extensions/resources/local/testvendor/testext/init.php\n@@ -0,0 +1,3 @@\n+<?php\n+\n+$app[\'extensions\']->register(new MockLocalExtension($app));\n\\ No newline at end of file\ndiff --git a/tests/Bolt/Tests/FilesystemProviderTest.php b/tests/FilesystemProviderTest.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/FilesystemProviderTest.php\nrename to tests/FilesystemProviderTest.php\ndiff --git a/tests/Bolt/Tests/FooObject.php b/tests/FooObject.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/FooObject.php\nrename to tests/FooObject.php\ndiff --git a/tests/Bolt/Tests/PermissionParserTest.php b/tests/PermissionParserTest.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/PermissionParserTest.php\nrename to tests/PermissionParserTest.php\ndiff --git a/tests/Bolt/Tests/UploadControllerTest.php b/tests/UploadControllerTest.php\nsimilarity index 100%\nrename from tests/Bolt/Tests/UploadControllerTest.php\nrename to tests/UploadControllerTest.php\ndiff --git a/tests/Bolt/Tests/resources/generic-logo-evil.exe b/tests/resources/generic-logo-evil.exe\nsimilarity index 100%\nrename from tests/Bolt/Tests/resources/generic-logo-evil.exe\nrename to tests/resources/generic-logo-evil.exe\ndiff --git a/tests/Bolt/Tests/resources/generic-logo.png b/tests/resources/generic-logo.png\nsimilarity index 100%\nrename from tests/Bolt/Tests/resources/generic-logo.png\nrename to tests/resources/generic-logo.png\n', 'commit_subject': 'move test files into root folder and start work on writing tests', 'repo_name': 'bolt/bolt', 'committer': {'name': 'Ross Riley', 'email': 'eebce68ab99567722cee5644714a63dca807990d@gmail.com', 'time_sec': '1421480192', 'tz_offset': '0', 'date': {'seconds': '1421480192'}}, 'commit_tree': '29de52661178eef208eaec6cef225227329523b3', 'commit_message': 'move test files into root folder and start work on writing tests\n', 'language_name': 'Shell', 'license': 'mit', 'hunks': "@@ -0,0 +1,3 @@\n+<?php\n+\n+$app['extensions']->register(new MockLocalExtension($app));\n\\ No newline at end of file\n", 'addition_count': 3, 'deletion_count': 0, 'src_file': '/dev/null', 'tgt_file': 'b/tests/Extensions/resources/local/testvendor/testext/init.php', 'file_extension': '.php', 'before_file': 'ADDFILE', 'message': 'move test files into root folder and start work on writing tests\n', 'author_name': 'Ross Riley', 'lang': 'php'}