lime /lib/LimeCli.php

Language PHP Lines 397
MD5 Hash 9990cab9a8648495915a14c8e1ac127c Estimated Cost $6,753 (why?)
Repository git://github.com/bschussek/lime.git View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
<?php

/*
 * This file is part of the Lime framework.
 *
 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
 * (c) Bernhard Schussek <bernhard.schussek@symfony-project.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

/**
 * Runs the Lime CLI commands.
 *
 * @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
 */
class LimeCli
{
  protected static $allowedOptions = array(
    'help',
    'init',
    'processes',
    'suffix',
    'color',
    'verbose',
    'serialize',
    'output',
    'test',
  );

  /**
   * Runs a command with the given CLI arguments.
   *
   * @param  array $arguments  The CLI arguments
   * @return integer           The return value of the command (0 if successful)
   */
  public function run(array $arguments)
  {
    try
    {
      list($options, $labels) = $this->parseArguments($arguments);

      if ($diff = array_diff(array_keys($options), self::$allowedOptions))
      {
        throw new Exception(sprintf('Unknown option(s): "%s"', implode('", "', $diff)));
      }

      if (isset($options['help']))
      {
        return $this->usage($options);
      }
      else if (isset($options['init']))
      {
        return $this->init($options);
      }
      else
      {
        return $this->test(array_slice($labels, 1), $options);
      }
    }
    catch (Exception $e)
    {
      echo "CLI: ".$e->getMessage()."\n";

      return 1;
    }
  }

  /**
   * Prints the usage information.
   *
   * @return integer  The return value of the command (0 if successful)
   */
  protected function usage(array $options)
  {
    echo <<<EOF
Command line utility for the Lime 2 test framework.

Usage:
  Execute all tests set up in lime.config.php:

    lime

  Execute the test with a specific name:

    lime --test=<name>

  The name is the test file name without the suffix configured in
  lime.config.php.

  Execute all tests in <label1> AND <label2>:

    lime <label1> <label2>...

  Execute all tests in <label1> OR <label2>:

    lime <label1> +<label2>...

  Execute all tests in <label1> EXCEPT those also in <label2>:

    lime <label1> -<label2>...


Options:
  --color                 Enforces colorization in the console output.
  --help                  This help
  --init                  Initializes the current working directory for
                          use with Lime 2. You should adapt the generated
                          lime.config.php to include your test files and
                          to set up labels.
  --output=<output>       Changes the output of the test. Can be one of
                          "raw", "xml", "suite" and "tap".
  --processes=<n>         Sets the number of processes to use.
  --serialize             Enables serialization of the output. Only works
                          with some output types (option --output).
  --test=<test>           Executes a single test. The test name is the file name
                          without the suffix configured in lime.config.php.
  --verbose               Enables verbose output. Only works with some
                          output types (option --output).

Examples:
  Execute MyClassTest:

    lime --test=MyClass

  Execute all tests that are in label "unit" and "model" at the same
  time, but that are not in label "slow":

    lime unit model -slow

  Execute all tests in label "unit" and all tests in label
  "functional":

    lime unit +functional

Configuration:
  The configuration file named lime.config.php is first searched in the
  current directory, then recursively in all parent directories. This
  means that you can launch lime also from subdirectories of your project.

  Included test files and test labels can be configured in the
  configuration file. See the user documentation for more information.


EOF;

    return 0;
  }

  /**
   * Initializes a project for use with Lime.
   *
   * @return integer  The return value of the command (0 if successful)
   */
  protected function init(array $options)
  {
    $absoluteLimeDir = realpath(dirname(__FILE__).'/..');
    $skeletonDir = $absoluteLimeDir.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'skeleton';
    $projectDir = realpath(getcwd());

    if (strpos($absoluteLimeDir, $projectDir.DIRECTORY_SEPARATOR) === 0)
    {
      $relativeLimeDir = substr($absoluteLimeDir, strlen($projectDir.DIRECTORY_SEPARATOR));
    }

    echo "Creating lime.config.php...";

    if (!file_exists($path = $projectDir.DIRECTORY_SEPARATOR.LimeConfiguration::FILENAME))
    {
      $content = file_get_contents($skeletonDir.DIRECTORY_SEPARATOR.LimeConfiguration::FILENAME);

      file_put_contents($path, str_replace("\n", PHP_EOL, $content));

    }
    else
    {
      echo " exists already!";
    }

    echo "\nCreating lime executable...";

    if (!file_exists($path = $projectDir.DIRECTORY_SEPARATOR.'lime'))
    {
      ob_start();
      include $skeletonDir.DIRECTORY_SEPARATOR.'lime';
      $content = ob_get_clean();

      file_put_contents($path, str_replace(array('[?php', "\n"), array('<?php', PHP_EOL), $content));
      chmod($path, 0777);
    }
    else
    {
      echo " exists already!";
    }

    echo <<<EOF

Initialized Lime project in $projectDir.

Please add your test files to lime.config.php.
You can find out more about Lime by running

    php lime --help


EOF;

    return 0;
  }

  /**
   * Tests a given set of labels.
   *
   * Packages may given with a leading "+" or "-". The tested files are:
   *
   *    * all files that are in all of the labels without leading "+" or "-"
   *    * all files that are in any label with a leading "+"
   *    * no files that are in any label with a leading "-"
   *
   * @param  array $labels  The label names
   * @return integer        The return value of the command (0 if successful)
   */
  protected function test(array $labels, array $options)
  {
    // don't load configuration in the constructor because then --init does
    // not work!
    $configuration = LimeConfiguration::read(getcwd());

    if ($configuration->getLegacyMode())
    {
      LimeAutoloader::enableLegacyMode();
    }

    if (isset($options['processes']))
    {
      $configuration->setProcesses($options['processes']);
    }

    if (isset($options['suffix']))
    {
      $configuration->setSuffix($options['suffix']);
    }

    if (isset($options['output']))
    {
      $configuration->setTestOutput($options['output']);
      $configuration->setSuiteOutput($options['output']);
    }

    if (isset($options['color']))
    {
      $configuration->setForceColors(true);
    }

    if (isset($options['verbose']))
    {
      $configuration->setVerbose(true);
    }

    if (isset($options['serialize']))
    {
      $configuration->setSerialize(true);
    }

    if (isset($options['test']))
    {
      $fileName = $options['test'];

      if (!is_readable($fileName))
      {
        $loader = new LimeLoader($configuration);
        $files = $loader->getFilesByName($options['test']);

        if (count($files) == 0)
        {
          throw new Exception("No tests are registered in the test suite! Please add your tests in lime.config.php.");
        }
        else if (count($files) > 1)
        {
          $paths = array();
          foreach ($files as $file)
          {
            $paths[] = $file->getPath();
          }

          throw new Exception(sprintf("The name \"%s\" is ambiguous:\n  - %s\nPlease launch the test with the full file path.", $labels[0], implode("\n  - ", $paths)));
        }

        $fileName = $files[0]->getPath();
      }
      else
      {
        $fileName = realpath($fileName);
      }

      $configuration->getTestOutput()->focus($fileName);

      try
      {
        if ($configuration->getAnnotationSupport())
        {
          $support = new LimeAnnotationSupport($fileName);

          $result = $support->execute();
        }
        else
        {
          $result = $this->includeTest($fileName);
        }

        // xUnit compatibility
        $class = basename($fileName, '.php');

        if (class_exists($class) && is_subclass_of($class, 'LimeTestCase'))
        {
          $test = new $class($configuration);
          return $test->run();
        }
        else
        {
          return $result;
        }
      }
      catch (Exception $e)
      {
        $configuration->getTestOutput()->error(LimeError::fromException($e));

        return 1;
      }
    }
    else
    {
      $loader = new LimeLoader($configuration);
      $harness = new LimeHarness($configuration, $loader);
      $files = $loader->getFilesByLabels($labels);

      if (count($files) == 0)
      {
        throw new Exception("No tests are registered in the test suite! Please add your tests in lime.config.php.");
      }

      return $harness->run($files) ? 0 : 1;
    }
  }

  protected function includeTest($__lime_path)
  {
  	LimeAnnotationSupport::setScriptPath($__lime_path);

  	$lexer = new LimeLexerVariables(array('Test', 'Before', 'After', 'BeforeAll', 'AfterAll'), array('Before'));

  	// make global variables _really_ global (in case someone uses "global" statements)
  	foreach ($lexer->parse(file_get_contents($__lime_path)) as $__lime_variable)
  	{
  	  $__lime_variable = substr($__lime_variable, 1); // strip '$'
  	  global $$__lime_variable;
  	}

  	return include $__lime_path;
  }

  /**
   * Parses the given CLI arguments and returns an array of options.
   *
   * @param  array $arguments
   * @return array
   */
  protected function parseArguments(array $arguments)
  {
    $options = array();
    $parameters = array();

    foreach ($arguments as $argument)
    {
      if (preg_match('/^--([a-zA-Z\-]+)=(.+)$/', $argument, $matches))
      {
        if (in_array($matches[2], array('true', 'false')))
        {
          $matches[2] = eval($matches[2]);
        }

        $options[$matches[1]] = $matches[2];
      }
      else if (preg_match('/^--([a-zA-Z\-]+)$/', $argument, $matches))
      {
        $options[$matches[1]] = true;
      }
      else
      {
        $parameters[] = $argument;
      }
    }

    return array($options, $parameters);
  }
}
Back to Top