Просмотр исходного кода

working on configuration unit test generator as described in #16

El RIDO 11 лет назад
Родитель
Сommit
1c4d1aa6b6
5 измененных файлов с 476 добавлено и 4 удалено
  1. 4 0
      .gitattributes
  2. 4 4
      lib/zerobin.php
  3. 341 0
      tst/configGenerator.php
  4. 126 0
      tst/configuration.php
  5. 1 0
      tst/phpunit.xml

+ 4 - 0
.gitattributes

@@ -0,0 +1,4 @@
+doc/* export-ignore
+tst/* export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore

+ 4 - 4
lib/zerobin.php

@@ -121,15 +121,15 @@ class zerobin
     {
         foreach (array('cfg', 'lib') as $dir)
         {
-            if (!is_file(PATH . $dir . '/.htaccess')) file_put_contents(
-                PATH . $dir . '/.htaccess',
+            if (!is_file(PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess')) file_put_contents(
+                PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess',
                 'Allow from none' . PHP_EOL .
                 'Deny from all'. PHP_EOL,
                 LOCK_EX
             );
         }
 
-        $this->_conf = parse_ini_file(PATH . 'cfg/conf.ini', true);
+        $this->_conf = parse_ini_file(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', true);
         foreach (array('main', 'model') as $section) {
             if (!array_key_exists($section, $this->_conf)) die(
                 "ZeroBin requires configuration section [$section] to be present in configuration file."
@@ -339,7 +339,7 @@ class zerobin
 
             // Generate the "delete" token.
             // The token is the hmac of the pasteid signed with the server salt.
-            // The paste can be delete by calling http://myserver.com/zerobin/?pasteid=<pasteid>&deletetoken=<deletetoken>
+            // The paste can be delete by calling http://example.com/zerobin/?pasteid=<pasteid>&deletetoken=<deletetoken>
             $deletetoken = hash_hmac('sha1', $dataid, serversalt::get());
 
             // 0 = no error

+ 341 - 0
tst/configGenerator.php

@@ -0,0 +1,341 @@
+#!/usr/bin/env php
+<?php
+/**
+ * generates a config unit test class
+ *
+ * This generator is meant to test all possible configuration combinations
+ * without having to write endless amounts of code manually.
+ *
+ * DANGER: Too many options/settings and too high max iteration setting may trigger
+ *         a fork bomb. Please save your work before executing this script.
+ */
+
+include 'bootstrap.php';
+
+$options = array(
+    'main/opendiscussion' => array(
+        array(
+            'setting' => true,
+            'tests' => array(
+                array(
+                    'type' => 'NotTag',
+                    'args' => array(
+                        array(
+                            'id' => 'opendiscussion',
+                            'attributes' => array(
+                                'disabled' => 'disabled',
+                            ),
+                        ),
+                        '$content',
+                        'outputs enabled discussion correctly'
+                    ),
+                ),
+            ),
+            'affects' => array('view')
+        ), array(
+            'setting' => false,
+            'tests' => array(
+                array(
+                    'type' => 'Tag',
+                    'args' => array(
+                        array(
+                            'id' => 'opendiscussion',
+                            'attributes' => array(
+                                'disabled' => 'disabled',
+                            ),
+                        ),
+                        '$content',
+                        'outputs disabled discussion correctly'
+                    ),
+                ),
+            ),
+            'affects' => array('view')
+        ),
+    ),
+    'main/syntaxhighlighting' => array(
+        array(
+            'setting' => true,
+            'tests' => array(
+                array(
+                    'type' => 'Tag',
+                    'args' => array(
+                        array(
+                            'tag' => 'link',
+                            'attributes' => array(
+                                'type' => 'text/css',
+                                'rel' => 'stylesheet',
+                                'href' => 'regexp:#css/prettify/prettify.css#',
+                            ),
+                        ),
+                        '$content',
+                        'outputs stylesheet correctly',
+                    ),
+                ), array(
+                    'type' => 'Tag',
+                    'args' => array(
+                        array(
+                            'tag' => 'script',
+                            'attributes' => array(
+                                'type' => 'text/javascript',
+                                'src' => 'regexp:#js/prettify.js#'
+                            ),
+                        ),
+                        '$content',
+                        'outputs javascript correctly',
+                    ),
+                ),
+            ),
+            'affects' => array('view'),
+        ), array(
+            'setting' => false,
+            'tests' => array(
+                array(
+                    'type' => 'NotTag',
+                    'args' => array(
+                        array(
+                            'tag' => 'link',
+                            'attributes' => array(
+                                'type' => 'text/css',
+                                'rel' => 'stylesheet',
+                                'href' => 'regexp:#css/prettify/prettify.css#',
+                            ),
+                        ),
+                        '$content',
+                        'removes stylesheet correctly',
+                    ),
+                ), array(
+                    'type' => 'NotTag',
+                    'args' => array(
+                        array(
+                            'tag' => 'script',
+                            'attributes' => array(
+                                'type' => 'text/javascript',
+                                'src' => 'regexp:#js/prettify.js#',
+                            ),
+                        ),
+                        '$content',
+                        'removes javascript correctly',
+                    ),
+                ),
+            ),
+            'affects' => array('view'),
+        ),
+    ),
+);
+
+// endless loop protection, since we're working with a recursive function, creating factorial configurations
+define('MAX_ITERATIONS', 1000);
+
+// generate all possible combinations of configurations: (option * settings)!
+$i = 0;
+$configurations = array(array('options' => array(), 'tests' => array(), 'affects' => array()));
+$configurations = getConfigurations($options, $configurations, $i);
+
+$defaultOptions = parse_ini_file(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', true);
+
+$code = <<<'EOT'
+<?php
+/**
+ * DO NOT EDIT: This file is automatically generated by configGenerator.php
+ */
+class configTest extends PHPUnit_Framework_TestCase
+{
+    private static $pasteid = '501f02e9eeb8bcec';
+
+    private static $paste = array(
+        'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
+        'meta' => array(
+            'postdate' => 1344803344,
+            'opendiscussion' => true,
+        ),
+    );
+
+    private $_model;
+
+    private $_conf;
+
+    public function setUp()
+    {
+        /* Setup Routine */
+        $this->_conf = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
+        if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
+            rename($this->_conf, $this->_conf . '.bak');
+
+        $this->_model = zerobin_data::getInstance(array('dir' => PATH . 'data'));
+        serversalt::setPath(PATH . 'data');
+        $this->reset();
+    }
+
+    public function tearDown()
+    {
+        /* Tear Down Routine */
+        rename($this->_conf . '.bak', $this->_conf);
+}
+
+    public function reset($configuration = array())
+    {
+        $_POST = array();
+        $_GET = array();
+        $_SERVER = array();
+        if ($this->_model->exists(self::$pasteid))
+            $this->_model->delete(self::$pasteid);
+
+        // generate configuration file
+        if (count($configuration)) {
+            @unlink($this->_conf);
+            $c = fopen($this->_conf, 'a');
+            foreach ($configuration as $section => $options) {
+                fwrite($c, "[$section]" . PHP_EOL);
+                foreach($options as $option => $setting) {
+                    if (is_string($setting)) {
+                        $setting = '"' . $setting . '"';
+                    } else {
+                        $setting = var_export($setting, true);
+                    }
+                    fwrite($c, "$option = $setting" . PHP_EOL);
+                }
+                fwrite($c, PHP_EOL);
+            }
+            fclose($c);
+        }
+    }
+
+EOT;
+
+foreach ($configurations as $key => $conf) {
+    $options = var_export_min(array_replace_recursive($defaultOptions, $conf['options']), true);
+    foreach ($conf['affects'] as $step) {
+        $step = ucfirst($step);
+        switch ($step) {
+            case 'Create':
+                // @todo
+                continue;
+                break;
+            case 'Read':
+                // @todo
+                continue;
+                break;
+            case 'Delete':
+                // @todo
+                continue;
+                break;
+            // view
+            default:
+                $code .= <<<EOT
+    /**
+     * @runInSeparateProcess
+     */
+    public function test$step$key()
+    {
+        \$this->reset($options);
+        ob_start();
+        new zerobin;
+        \$content = ob_get_contents();
+
+
+EOT;
+        }
+
+        foreach ($conf['tests'] as $tests) {
+            foreach ($tests as $test) {
+                $args = array();
+                foreach ($test['args'] as $arg) {
+                    if ($arg == '$content') {
+                        $args[] = $arg;
+                    } else {
+                        $args[] = var_export_min($arg, true);
+                    }
+                }
+                $type = $test['type'];
+                $args = implode(', ', $args);
+                $code .= <<<EOT
+        \$this->assert$type($args);
+
+EOT;
+            }
+        }
+        $code .= <<<'EOT'
+    }
+
+
+EOT;
+    }
+}
+
+$code .= '}' . PHP_EOL;
+
+file_put_contents('configuration.php', $code);
+
+// recursive factorial function
+function getConfigurations(&$options, &$configurations, &$i) {
+    if (++$i > MAX_ITERATIONS) {
+        echo "max iterations reached, stopping", PHP_EOL;
+        return $configurations;
+    }
+    echo "getConfigurations: iteration $i", PHP_EOL;
+    $continue = list($path, $settings) = each($options);
+    if ($continue === false) {
+        return $configurations;
+    }
+    list($section, $option) = explode('/', $path);
+    for ($c = 0, $max = count($configurations); $c < $max; ++$c) {
+        if (!array_key_exists($section, $configurations[$c]['options'])) {
+            $configurations[$c]['options'][$section] = array();
+        }
+        if (count($settings) == 0) {
+            throw new Exception("Check your \$options: option $option has no settings!");
+        }
+        // set the first setting in the original configuration
+        $setting = current($settings);
+        addSetting($configurations[$c], $setting, $section, $option, $i);
+
+        // create clones for each of the other settings
+        while ($setting = next($settings)) {
+            $clone = $configurations[$c];
+            $configurations[] = addSetting($clone, $setting, $section, $option, $i);
+        }
+        reset($settings);
+    }
+    return getConfigurations($options, $configurations, $i);
+}
+
+function addSetting(&$configuration, &$setting, &$section, &$option, &$i) {
+    if (++$i > MAX_ITERATIONS) {
+        echo "max iterations reached, stopping", PHP_EOL;
+        return $configuration;
+    }
+    echo "addSetting: iteration $i", PHP_EOL;
+    if (
+        array_key_exists($option, $configuration['options'][$section]) &&
+        $configuration['options'][$section][$option] === $setting['setting']
+    ) {
+        $val = var_export_min($setting['setting'], true);
+        throw new Exception("Endless loop or error in options detected: option '$option' already exists with setting '$val' in one of the configurations!");
+    }
+    $configuration['options'][$section][$option] = $setting['setting'];
+    $configuration['tests'][$option] = $setting['tests'];
+    foreach ($setting['affects'] as $affects) {
+        if (!in_array($affects, $configuration['affects'])) {
+            $configuration['affects'][] = $affects;
+        }
+    }
+    return $configuration;
+}
+
+// by linus@flowingcreativity.net via php.net
+function var_export_min($var, $return = false) {
+    if (is_array($var)) {
+        $toImplode = array();
+        foreach ($var as $key => $value) {
+            $toImplode[] = var_export($key, true).' => '.var_export_min($value, true);
+        }
+        $code = 'array('.implode(', ', $toImplode).')';
+        if ($return) {
+            return $code;
+        } else {
+            echo $code;
+        }
+    } else {
+        return var_export($var, $return);
+    }
+}

+ 126 - 0
tst/configuration.php

@@ -0,0 +1,126 @@
+<?php
+/**
+ * DO NOT EDIT: This file is automatically generated by configGenerator.php
+ */
+class configTest extends PHPUnit_Framework_TestCase
+{
+    private static $pasteid = '501f02e9eeb8bcec';
+
+    private static $paste = array(
+        'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
+        'meta' => array(
+            'postdate' => 1344803344,
+            'opendiscussion' => true,
+        ),
+    );
+
+    private $_model;
+
+    private $_conf;
+
+    public function setUp()
+    {
+        /* Setup Routine */
+        $this->_conf = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
+        if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
+            rename($this->_conf, $this->_conf . '.bak');
+
+        $this->_model = zerobin_data::getInstance(array('dir' => PATH . 'data'));
+        serversalt::setPath(PATH . 'data');
+        $this->reset();
+    }
+
+    public function tearDown()
+    {
+        /* Tear Down Routine */
+        rename($this->_conf . '.bak', $this->_conf);
+}
+
+    public function reset($configuration = array())
+    {
+        $_POST = array();
+        $_GET = array();
+        $_SERVER = array();
+        if ($this->_model->exists(self::$pasteid))
+            $this->_model->delete(self::$pasteid);
+
+        // generate configuration file
+        if (count($configuration)) {
+            @unlink($this->_conf);
+            $c = fopen($this->_conf, 'a');
+            foreach ($configuration as $section => $options) {
+                fwrite($c, "[$section]" . PHP_EOL);
+                foreach($options as $option => $setting) {
+                    if (is_string($setting)) {
+                        $setting = '"' . $setting . '"';
+                    } else {
+                        $setting = var_export($setting, true);
+                    }
+                    fwrite($c, "$option = $setting" . PHP_EOL);
+                }
+                fwrite($c, PHP_EOL);
+            }
+            fclose($c);
+        }
+    }
+    /**
+     * @runInSeparateProcess
+     */
+    public function testView0()
+    {
+        $this->reset(array('main' => array('opendiscussion' => true, 'syntaxhighlighting' => true, 'burnafterreadingselected' => '', 'sizelimit' => '2097152', 'template' => 'bootstrap', 'base64version' => '2.1.9'), 'expire' => array('default' => '1month'), 'expire_options' => array('5min' => '300', '10min' => '600', '1hour' => '3600', '1day' => '86400', '1week' => '604800', '1month' => '2592000', '1year' => '31536000', 'never' => '0'), 'expire_labels' => array('5min' => '5 minutes', '10min' => '10 minutes', '1hour' => '1 hour', '1day' => '1 day', '1week' => '1 week', '1month' => '1 month', '1year' => '1 year', 'never' => 'Never'), 'traffic' => array('limit' => '10', 'dir' => '../data'), 'model' => array('class' => 'zerobin_data'), 'model_options' => array('dir' => '../data')));
+        ob_start();
+        new zerobin;
+        $content = ob_get_contents();
+
+        $this->assertNotTag(array('id' => 'opendiscussion', 'attributes' => array('disabled' => 'disabled')), $content, 'outputs enabled discussion correctly');
+        $this->assertTag(array('tag' => 'link', 'attributes' => array('type' => 'text/css', 'rel' => 'stylesheet', 'href' => 'regexp:#css/prettify/prettify.css#')), $content, 'outputs stylesheet correctly');
+        $this->assertTag(array('tag' => 'script', 'attributes' => array('type' => 'text/javascript', 'src' => 'regexp:#js/prettify.js#')), $content, 'outputs javascript correctly');
+    }
+
+    /**
+     * @runInSeparateProcess
+     */
+    public function testView1()
+    {
+        $this->reset(array('main' => array('opendiscussion' => false, 'syntaxhighlighting' => true, 'burnafterreadingselected' => '', 'sizelimit' => '2097152', 'template' => 'bootstrap', 'base64version' => '2.1.9'), 'expire' => array('default' => '1month'), 'expire_options' => array('5min' => '300', '10min' => '600', '1hour' => '3600', '1day' => '86400', '1week' => '604800', '1month' => '2592000', '1year' => '31536000', 'never' => '0'), 'expire_labels' => array('5min' => '5 minutes', '10min' => '10 minutes', '1hour' => '1 hour', '1day' => '1 day', '1week' => '1 week', '1month' => '1 month', '1year' => '1 year', 'never' => 'Never'), 'traffic' => array('limit' => '10', 'dir' => '../data'), 'model' => array('class' => 'zerobin_data'), 'model_options' => array('dir' => '../data')));
+        ob_start();
+        new zerobin;
+        $content = ob_get_contents();
+
+        $this->assertTag(array('id' => 'opendiscussion', 'attributes' => array('disabled' => 'disabled')), $content, 'outputs disabled discussion correctly');
+        $this->assertTag(array('tag' => 'link', 'attributes' => array('type' => 'text/css', 'rel' => 'stylesheet', 'href' => 'regexp:#css/prettify/prettify.css#')), $content, 'outputs stylesheet correctly');
+        $this->assertTag(array('tag' => 'script', 'attributes' => array('type' => 'text/javascript', 'src' => 'regexp:#js/prettify.js#')), $content, 'outputs javascript correctly');
+    }
+
+    /**
+     * @runInSeparateProcess
+     */
+    public function testView2()
+    {
+        $this->reset(array('main' => array('opendiscussion' => true, 'syntaxhighlighting' => false, 'burnafterreadingselected' => '', 'sizelimit' => '2097152', 'template' => 'bootstrap', 'base64version' => '2.1.9'), 'expire' => array('default' => '1month'), 'expire_options' => array('5min' => '300', '10min' => '600', '1hour' => '3600', '1day' => '86400', '1week' => '604800', '1month' => '2592000', '1year' => '31536000', 'never' => '0'), 'expire_labels' => array('5min' => '5 minutes', '10min' => '10 minutes', '1hour' => '1 hour', '1day' => '1 day', '1week' => '1 week', '1month' => '1 month', '1year' => '1 year', 'never' => 'Never'), 'traffic' => array('limit' => '10', 'dir' => '../data'), 'model' => array('class' => 'zerobin_data'), 'model_options' => array('dir' => '../data')));
+        ob_start();
+        new zerobin;
+        $content = ob_get_contents();
+
+        $this->assertNotTag(array('id' => 'opendiscussion', 'attributes' => array('disabled' => 'disabled')), $content, 'outputs enabled discussion correctly');
+        $this->assertNotTag(array('tag' => 'link', 'attributes' => array('type' => 'text/css', 'rel' => 'stylesheet', 'href' => 'regexp:#css/prettify/prettify.css#')), $content, 'removes stylesheet correctly');
+        $this->assertNotTag(array('tag' => 'script', 'attributes' => array('type' => 'text/javascript', 'src' => 'regexp:#js/prettify.js#')), $content, 'removes javascript correctly');
+    }
+
+    /**
+     * @runInSeparateProcess
+     */
+    public function testView3()
+    {
+        $this->reset(array('main' => array('opendiscussion' => false, 'syntaxhighlighting' => false, 'burnafterreadingselected' => '', 'sizelimit' => '2097152', 'template' => 'bootstrap', 'base64version' => '2.1.9'), 'expire' => array('default' => '1month'), 'expire_options' => array('5min' => '300', '10min' => '600', '1hour' => '3600', '1day' => '86400', '1week' => '604800', '1month' => '2592000', '1year' => '31536000', 'never' => '0'), 'expire_labels' => array('5min' => '5 minutes', '10min' => '10 minutes', '1hour' => '1 hour', '1day' => '1 day', '1week' => '1 week', '1month' => '1 month', '1year' => '1 year', 'never' => 'Never'), 'traffic' => array('limit' => '10', 'dir' => '../data'), 'model' => array('class' => 'zerobin_data'), 'model_options' => array('dir' => '../data')));
+        ob_start();
+        new zerobin;
+        $content = ob_get_contents();
+
+        $this->assertTag(array('id' => 'opendiscussion', 'attributes' => array('disabled' => 'disabled')), $content, 'outputs disabled discussion correctly');
+        $this->assertNotTag(array('tag' => 'link', 'attributes' => array('type' => 'text/css', 'rel' => 'stylesheet', 'href' => 'regexp:#css/prettify/prettify.css#')), $content, 'removes stylesheet correctly');
+        $this->assertNotTag(array('tag' => 'script', 'attributes' => array('type' => 'text/javascript', 'src' => 'regexp:#js/prettify.js#')), $content, 'removes javascript correctly');
+    }
+
+}

+ 1 - 0
tst/phpunit.xml

@@ -1,6 +1,7 @@
 <phpunit bootstrap="bootstrap.php" colors="true">
 	<testsuite name="ZeroBin Test Suite">
 		<directory suffix=".php">./</directory>
+		<exclude>configGenerator.php</exclude>
 	</testsuite>
 	<filter>
 		<whitelist>