GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — hotfix/2.3.5 ( 6cc8bd )
by Stuart
10:01 queued 10s
created

Story::getStoryCodeFor()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 4

Duplication

Lines 17
Ratio 100 %
Metric Value
dl 17
loc 17
rs 9.4286
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
3
/**
4
 * Copyright (c) 2011-present Mediasift Ltd
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 *   * Redistributions of source code must retain the above copyright
12
 *     notice, this list of conditions and the following disclaimer.
13
 *
14
 *   * Redistributions in binary form must reproduce the above copyright
15
 *     notice, this list of conditions and the following disclaimer in
16
 *     the documentation and/or other materials provided with the
17
 *     distribution.
18
 *
19
 *   * Neither the names of the copyright holders nor the names of his
20
 *     contributors may be used to endorse or promote products derived
21
 *     from this software without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 * POSSIBILITY OF SUCH DAMAGE.
35
 *
36
 * @category  Libraries
37
 * @package   Storyplayer/PlayerLib
38
 * @author    Stuart Herbert <[email protected]>
39
 * @copyright 2011-present Mediasift Ltd www.datasift.com
40
 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
41
 * @link      http://datasift.github.io/storyplayer
42
 */
43
44
namespace DataSift\Storyplayer\PlayerLib;
45
46
use Exception;
47
48
/**
49
 * Object that represents a single story
50
 *
51
 * @category  Libraries
52
 * @package   Storyplayer/StoryLib
53
 * @author    Stuart Herbert <[email protected]>
54
 * @copyright 2011-present Mediasift Ltd www.datasift.com
55
 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
56
 * @link      http://datasift.github.io/storyplayer
57
 */
58
class Story
59
{
60
    /**
61
     * the category that this story belongs to
62
     * @var string
63
     */
64
    protected $category;
65
66
    /**
67
     * the group that this story belongs to
68
     * @var array<string>
69
     */
70
    protected $group;
71
72
    /**
73
     * the name of this story
74
     * @var string
75
     */
76
    protected $name;
77
78
    /**
79
     * the function that provides hints about how this story changes
80
     * the state of the system or user
81
     *
82
     * @var callable
83
     */
84
    protected $hintsCallback;
85
86
    /**
87
     * the function that checks to see if the test should run at all,
88
     * or should be skipped
89
     *
90
     * @var array
91
     */
92
    protected $testCanRunCheckCallback = array();
93
94
    /**
95
     * the function that provides any story-specific setup work
96
     *
97
     * @var array
98
     */
99
    protected $testSetupCallback = array();
100
101
    /**
102
     * the function that provides any story-specific teardown action
103
     * @var array
104
     */
105
    protected $testTeardownCallback = array();
106
107
    /**
108
     * the function that provides any story-specific setup work that
109
     * happens before each phase of the test
110
     * @var array
111
     */
112
    protected $perPhaseSetupCallback = array();
113
114
    /**
115
     * the function that provides any story-specific teardown work that
116
     * happens at the end of each phase of the test
117
     * @var array
118
     */
119
    protected $perPhaseTeardownCallback = array();
120
121
    /**
122
     * the function that provides any story-specific setup work that
123
     * happens when we start a device
124
     * @var array
125
     */
126
    protected $deviceSetupCallback = array();
127
128
    /**
129
     * the function that provides any story-specific teardown work that
130
     * happens just before we stop a device
131
     * @var array
132
     */
133
    protected $deviceTeardownCallback = array();
134
135
    /**
136
     * the function that provides information about how this story has
137
     * changed the state of the system or user
138
     *
139
     * @var array
140
     */
141
    protected $roleChangesCallback = array();
142
143
    /**
144
     * the callback that dynamically determines in advance whether the
145
     * story actions should succeed or fail
146
     *
147
     * @var array
148
     */
149
    protected $preTestPredictionCallback = array();
150
151
    /**
152
     * the callback that dynamically determines afterwards whether or not
153
     * the story actions actually did succeed
154
     *
155
     * @var array
156
     */
157
    protected $reportTestResultsCallback = array();
158
159
    /**
160
     * the callback used to remember the state of the system *before*
161
     * the action occurs
162
     *
163
     * @var array
164
     */
165
    protected $preTestInspectionCallback = array();
166
167
    /**
168
     * the callback used to see if the action *did* change the state of
169
     * the system under test
170
     *
171
     * @var array
172
     */
173
    protected $postTestInspectionCallback = array();
174
175
    /**
176
     * the actions that execute the story on behalf of the user
177
     *
178
     * this is an array of callbacks.  Each callback is a single set of
179
     * actions to execute the story.  Each callback is an alternative way
180
     * to execute the story.  Each callback is meant to be equivalent; ie
181
     * they achieve the same thing, just in different ways.
182
     *
183
     * If any of the callbacks has different outcomes, then they belong
184
     * in separate user stories. NO EXCEPTIONS. This is a fundamental
185
     * assumption of Storyplayer; ignore it, and Storyplayer's no use to
186
     * you!
187
     *
188
     * @var array
189
     */
190
    protected $actionsCallbacks = array();
191
192
    /**
193
     * a list of the StoryTemplates that this story is based on. can be
194
     * empty
195
     *
196
     * @var array
197
     */
198
    protected $storyTemplates = array();
199
200
    /**
201
     * the parameters that get passed into virtual machines et al, and
202
     * which can be overridden on the command-line
203
     *
204
     * @var array
205
     */
206
    protected $params = array();
207
208
    /**
209
     * the environments that a story states it runs on
210
     *
211
     * by default, a story is allowed to run on all environments, *but*
212
     * if an environment's config sets 'mustBeWhitelisted' to TRUE, then
213
     * the story is only allowed to run on that environment if the story
214
     * declares itself safe to run
215
     *
216
     * we believe that this is the safest approach to handling those
217
     * stories that simply aren't safe to run absolutely everywhere
218
     */
219
    protected $whitelistedEnvironments = array();
220
221
    /**
222
     * the raw parser tree of this story, and of any templates that we
223
     * use
224
     *
225
     * @var array
226
     */
227
    protected $parserTrees = array();
228
229
    /**
230
     * the file that contains the story
231
     *
232
     * @var string
233
     */
234
    protected $storyFilename = '';
235
236
    /**
237
     * a list of the roles that the test environment must have defined,
238
     * otherwise we cannot run
239
     *
240
     * @var array
241
     */
242
    protected $requiredTestEnvRoles = array();
243
244
    /**
245
     * does the story want the test device kept open between phases?
246
     *
247
     * @var boolean
248
     */
249
    protected $persistDevice = false;
250
251
    /**
252
     * which version of Storyplayer is this test written for?
253
     *
254
     * you HAVE to set this in your story, otherwise we will skip your
255
     * story
256
     *
257
     * @var integer
258
     */
259
    protected $compatibleVersion = 1;
260
261
    /**
262
     * what happened to this story?
263
     * @var \DataSift\Storyplayer\PlayerLib\Story_Result
264
     */
265
    protected $storyResult = null;
266
267
    // ====================================================================
268
    //
269
    // Metadata about the story itself
270
    //
271
    // --------------------------------------------------------------------
272
273
    /**
274
     * which group of tests does this story belong to?
275
     *
276
     * @param  array|string $groupName
277
     *         the group to use
278
     * @return Story
279
     *         $this for fluent interface
280
     */
281
    public function inGroup($groupName)
282
    {
283
        if (!is_array($groupName)) {
284
            $parts = explode(" > ", $groupName);
285
            $groupName = $parts;
286
        }
287
        $this->setGroup($groupName);
288
289
        return $this;
290
    }
291
292
    /**
293
     * @return Story
294
     */
295
    public function called($userStoryText)
296
    {
297
        $this->setName($userStoryText);
298
299
        return $this;
300
    }
301
302
    /**
303
     * Get the category that this story belongs to
304
     *
305
     * Systems under test can grow to encompass hundreds, if not thousands
306
     * of user stories.  To make this manageable at scale, we break down
307
     * each user story like this:
308
     *
309
     * Name    : Starts as a free user with 10 USD in credit
310
     * Category: Billing User Stories
311
     * Group   : User States
312
     *
313
     * The 'name' is the summary text of the user story itself, which
314
     * should be no longer than a single sentence, please.
315
     *
316
     * The 'category' is the general group that the user story belongs to.
317
     * These are the top-level groups, such as 'Registration', 'Billing'
318
     * and so forth.
319
     *
320
     * The 'group' is the specific group _inside_ the category that the
321
     * user story belongs to.  The groups are specific to the category.
322
     *
323
     * @return string the category that this story belongs to
324
     */
325
    public function getCategory()
326
    {
327
        return $this->category;
328
    }
329
330
    /**
331
     * Set the category that this story belongs to
332
     *
333
     * Systems under test can grow to encompass hundreds, if not thousands
334
     * of user stories.  To make this manageable at scale, we break down
335
     * each user story like this:
336
     *
337
     * Name    : Starts as a free user with 10 USD in credit
338
     * Category: Billing User Stories
339
     * Group   : User States
340
     *
341
     * The 'name' is the summary text of the user story itself, which
342
     * should be no longer than a single sentence, please.
343
     *
344
     * The 'category' is the general group that the user story belongs to.
345
     * These are the top-level groups, such as 'Registration', 'Billing'
346
     * and so forth.
347
     *
348
     * The 'group' is the specific group _inside_ the category that the
349
     * user story belongs to.  The groups are specific to the category.
350
     *
351
     * @param  string $newCategory the category that this story belongs to
352
     * @return Story  $this
353
     */
354
    public function setCategory($newCategory)
355
    {
356
        $this->category = $newCategory;
357
        return $this;
358
    }
359
360
    /**
361
     * Get the group that this story belongs to
362
     *
363
     * Systems under test can grow to encompass hundreds, if not thousands
364
     * of user stories.  To make this manageable at scale, we break down
365
     * each user story like this:
366
     *
367
     * Name    : Starts as a free user with 10 USD in credit
368
     * Category: Billing User Stories
369
     * Group   : User States
370
     *
371
     * The 'name' is the summary text of the user story itself, which
372
     * should be no longer than a single sentence, please.
373
     *
374
     * The 'category' is the general group that the user story belongs to.
375
     * These are the top-level groups, such as 'Registration', 'Billing'
376
     * and so forth.
377
     *
378
     * The 'group' is the specific group _inside_ the category that the
379
     * user story belongs to.  The groups are specific to the category.
380
     *
381
     * @return array<string> the group that this story belongs to
382
     */
383
    public function getGroup()
384
    {
385
        return $this->group;
386
    }
387
388
    /**
389
     * return the story's group as a printable string
390
     *
391
     * @return string
392
     */
393
    public function getGroupAsString()
394
    {
395
        return implode(" > ", $this->group);
396
    }
397
398
    /**
399
     * Set the group that this story belongs to
400
     *
401
     * Systems under test can grow to encompass hundreds, if not thousands
402
     * of user stories.  To make this manageable at scale, we break down
403
     * each user story like this:
404
     *
405
     * Name    : Starts as a free user with 10 USD in credit
406
     * Category: Billing User Stories
407
     * Group   : User States
408
     *
409
     * The 'name' is the summary text of the user story itself, which
410
     * should be no longer than a single sentence, please.
411
     *
412
     * The 'category' is the general group that the user story belongs to.
413
     * These are the top-level groups, such as 'Registration', 'Billing'
414
     * and so forth.
415
     *
416
     * The 'group' is the specific group _inside_ the category that the
417
     * user story belongs to.  The groups are specific to the category.
418
     *
419
     * @param  array<string> $newGroup
420
     * @return Story  $this
421
     */
422
    public function setGroup($newGroup)
423
    {
424
        $this->group = $newGroup;
425
        return $this;
426
    }
427
428
    /**
429
     * Get the name of this story
430
     *
431
     * Systems under test can grow to encompass hundreds, if not thousands
432
     * of user stories.  To make this manageable at scale, we break down
433
     * each user story like this:
434
     *
435
     * Name    : Starts as a free user with 10 USD in credit
436
     * Category: Billing User Stories
437
     * Group   : User States
438
     *
439
     * The 'name' is the summary text of the user story itself, which
440
     * should be no longer than a single sentence, please.
441
     *
442
     * The 'category' is the general group that the user story belongs to.
443
     * These are the top-level groups, such as 'Registration', 'Billing'
444
     * and so forth.
445
     *
446
     * The 'group' is the specific group _inside_ the category that the
447
     * user story belongs to.  The groups are specific to the category.
448
     *
449
     * @return string the name of this story
450
     */
451
    public function getName()
452
    {
453
        return $this->name;
454
    }
455
456
    /**
457
     * Set the name of this story
458
     *
459
     * Systems under test can grow to encompass hundreds, if not thousands
460
     * of user stories.  To make this manageable at scale, we break down
461
     * each user story like this:
462
     *
463
     * Name    : Starts as a free user with 10 USD in credit
464
     * Category: Billing User Stories
465
     * Group   : User States
466
     *
467
     * The 'name' is the summary text of the user story itself, which
468
     * should be no longer than a single sentence, please.
469
     *
470
     * The 'category' is the general group that the user story belongs to.
471
     * These are the top-level groups, such as 'Registration', 'Billing'
472
     * and so forth.
473
     *
474
     * The 'group' is the specific group _inside_ the category that the
475
     * user story belongs to.  The groups are specific to the category.
476
     *
477
     * @param  string $newName the name of this story
478
     * @return Story  $this
479
     */
480
    public function setName($newName)
481
    {
482
        $this->name = $newName;
483
        return $this;
484
    }
485
486
    /**
487
     * Set the parameters for this story
488
     *
489
     * Parameters are a way of passing settings between Stories and
490
     * StoryTemplates.
491
     *
492
     * Order of precedence:
493
     *
494
     * 1) Story
495
     * 2) StoryTemplates (in 'basedOn()' order)
496
     *    (templates cannot override each other)
497
     *
498
     * @param array $defaults
499
     *        a list of the parameters for this story
500
     */
501
    public function setParams($defaults)
502
    {
503
        $this->params = $defaults;
504
        return $this;
505
    }
506
507
    /**
508
     * @return array
509
     */
510
    public function getParams()
511
    {
512
        // our return value
513
        $return = array();
514
515
        // populate it with the parameters from the templates
516
        foreach ($this->storyTemplates as $template) {
517
            // get any params from the template
518
            $params = $template->getParams();
519
520
            // any params already set have precedence
521
            foreach ($params as $key => $value) {
522
                // do we have a clash?
523
                if (!isset($return[$key])) {
524
                    $return[$key] = $value;
525
                }
526
            }
527
        }
528
529
        // now, merge in our own params
530
        //
531
        // our params always take precedence over the params set
532
        // in the template(s)
533
        $return = array_merge($this->params, $return);
534
535
        // all done
536
        return $return;
537
    }
538
539
    /**
540
     * @return void
541
     */
542
    public function determineStoryFilename()
543
    {
544
        $trace = debug_backtrace();
545
        $this->storyFilename = $trace[1]['file'];
546
    }
547
548
    /**
549
     * @return string
550
     */
551
    public function getStoryFilename()
552
    {
553
        return $this->storyFilename;
554
    }
555
556
    // ====================================================================
557
    //
558
    // Metadata for which states the story is valid for
559
    //
560
    // --------------------------------------------------------------------
561
562
    public function addValidRole($role)
0 ignored issues
show
Unused Code introduced by
The parameter $role is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
563
    {
564
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
565
    }
566
567
    /**
568
     * Synonym for addValidRole()
569
     *
570
     * @see Story::addValidRole
571
     */
572
    public function andValidRole($role)
0 ignored issues
show
Unused Code introduced by
The parameter $role is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
573
    {
574
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
575
    }
576
577
    public function hasRole($roleName)
0 ignored issues
show
Unused Code introduced by
The parameter $roleName is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
578
    {
579
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
580
    }
581
582
    // ====================================================================
583
    //
584
    // Support for changing roles after a test has succeeded
585
    //
586
    // --------------------------------------------------------------------
587
588
    /**
589
     * get the role changes callback
590
     */
591
    public function getRoleChanges()
592
    {
593
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
594
    }
595
596
    /**
597
     * has the role changes callback been set?
598
     */
599
    public function hasRoleChanges()
600
    {
601
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
602
    }
603
604
    public function setRoleChanges($newCallback)
0 ignored issues
show
Unused Code introduced by
The parameter $newCallback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
605
    {
606
        throw new E4xx_DeprecatedFeature('user roles in stories have been removed from Storyplayer v2.');
607
    }
608
609
    // ====================================================================
610
    //
611
    // Information about story templates
612
    //
613
    // --------------------------------------------------------------------
614
615
    /**
616
     * set up any templated methods from a predefined class
617
     *
618
     * @return Story
619
     */
620
    public function basedOn(StoryTemplate $tmpl)
621
    {
622
        // tell the template which story it is being used with
623
        $tmpl->setStory($this);
624
625
        $tmpl->hasTestCanRunCheck()         && $this->addTestCanRunCheck($tmpl->getTestCanRunCheck());
626
        $tmpl->hasTestSetup()               && $this->addTestSetup($tmpl->getTestSetup());
627
        $tmpl->hasTestTeardown()            && $this->addTestTeardown($tmpl->getTestTeardown());
628
        $tmpl->hasPerPhaseSetup()           && $this->addPerPhaseSetup($tmpl->getPerPhaseSetup());
629
        $tmpl->hasPerPhaseTeardown()        && $this->addPerPhaseTeardown($tmpl->getPerPhaseTeardown());
630
        $tmpl->hasDeviceSetup()             && $this->addDeviceSetup($tmpl->getDeviceSetup());
631
        $tmpl->hasDeviceTeardown()          && $this->addDeviceTeardown($tmpl->getDeviceTeardown());
632
        $tmpl->hasHints()                   && $this->addHints($tmpl->getHints());
633
        $tmpl->hasPreTestPrediction()       && $this->addPreTestPrediction($tmpl->getPreTestPrediction());
634
        $tmpl->hasPreTestInspection()       && $this->addPreTestInspection($tmpl->getPreTestInspection());
635
        $tmpl->hasAction()                  && $this->addAction($tmpl->getAction());
636
        $tmpl->hasPostTestInspection()      && $this->addPostTestInspection($tmpl->getPostTestInspection());
637
638
        // remember this template for future use
639
        $this->storyTemplates[] = $tmpl;
640
641
        // Return $this for a fluent interface
642
        return $this;
643
    }
644
645
    /**
646
     * get a list of the templates that this story is based on, in order
647
     * or precedence
648
     *
649
     * can be empty
650
     *
651
     * @return array<StoryTemplate>
652
     */
653
    public function getStoryTemplates()
654
    {
655
        return $this->storyTemplates;
656
    }
657
658
    // ==================================================================
659
    //
660
    // Information about dependencies
661
    //
662
    // ------------------------------------------------------------------
663
664
    /**
665
     * @return int
666
     */
667
    public function getRequiredStoryplayerVersion()
668
    {
669
        return $this->compatibleVersion;
670
    }
671
672
    /**
673
     * @return Story
674
     */
675
    public function requiresStoryplayerVersion($version)
676
    {
677
        $this->compatibleVersion = $version;
678
        return $this;
679
    }
680
681
    // ====================================================================
682
    //
683
    // Information about environments
684
    //
685
    // --------------------------------------------------------------------
686
687
    /**
688
     * @return Story
689
     */
690
    public function runsOn($envName)
691
    {
692
        $this->whitelistedEnvironments[$envName] = true;
693
        return $this;
694
    }
695
696
    /**
697
     * @return Story
698
     */
699
    public function andOn($envName)
700
    {
701
        $this->whitelistedEnvironments[$envName] = true;
702
        return $this;
703
    }
704
705
    /**
706
     * @return array
707
     */
708
    public function getWhitelistedEnvironments()
709
    {
710
        return $this->whitelistedEnvironments;
711
    }
712
713
    /**
714
     * @return void
715
     */
716
    public function requiresTestEnvironmentWithRoles($roles)
717
    {
718
        $this->requiredTestEnvRoles = $roles;
719
    }
720
721
    /**
722
     * @return array
723
     */
724
    public function getRequiredTestEnvironmentRoles()
725
    {
726
        return $this->requiredTestEnvRoles;
727
    }
728
729
    // ==================================================================
730
    //
731
    // Device support
732
    //
733
    // ------------------------------------------------------------------
734
735
    /**
736
     * does this story want to keep the web browser open between phases?
737
     *
738
     * @return boolean
739
     */
740
    public function getPersistDevice()
741
    {
742
        return $this->persistDevice;
743
    }
744
745
    /**
746
     * tell Storyplayer to keep the web browser open between test phases
747
     *
748
     * by default, we close the browser after every phase, to make sure
749
     * that the next phase always starts with a browser in a known state
750
     */
751
    public function setPersistDevice()
752
    {
753
        $this->persistDevice = true;
754
        return $this;
755
    }
756
757
    // ====================================================================
758
    //
759
    // Information about how check if the test should run at all
760
    //
761
    // --------------------------------------------------------------------
762
763
    /**
764
     * get the callback which allows the story to be skipped
765
     *
766
     * @return array
767
     */
768
    public function getTestCanRunCheck()
769
    {
770
        return $this->testCanRunCheckCallback;
771
    }
772
773
    /**
774
     * do we have a 'check story can run' callback?
775
     *
776
     * @return boolean true if the callback exists
777
     */
778
    public function hasTestCanRunCheck()
779
    {
780
        return count($this->testCanRunCheckCallback) > 0;
781
    }
782
783
    /**
784
     * @return void
785
     */
786
    public function addTestCanRunCheck($newCallback)
787
    {
788
        $this->testCanRunCheckCallback[] = $newCallback;
789
    }
790
791
    // ====================================================================
792
    //
793
    // Information about how to setup and teardown the test environment
794
    //
795
    // This is a feature from Storyplayer v1 that we've dropped in v2
796
    //
797
    // --------------------------------------------------------------------
798
799
    public function setTestEnvironmentSetup($newCallback)
0 ignored issues
show
Unused Code introduced by
The parameter $newCallback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
800
    {
801
        throw new E4xx_DeprecatedFeature('TestEnvironmentSetup phase was removed from Storyplayer v2.');
802
    }
803
804
    public function addTestEnvironmentSetup($newCallback)
0 ignored issues
show
Unused Code introduced by
The parameter $newCallback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
805
    {
806
        throw new E4xx_DeprecatedFeature('TestEnvironmentSetup phase was removed from Storyplayer v2.');
807
    }
808
809
    public function setTestEnvironmentTeardown($newCallback)
0 ignored issues
show
Unused Code introduced by
The parameter $newCallback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
810
    {
811
        throw new E4xx_DeprecatedFeature('TestEnvironmentSetup phase was removed from Storyplayer v2.');
812
    }
813
814
    public function addTestEnvironmentTeardown($newCallback)
0 ignored issues
show
Unused Code introduced by
The parameter $newCallback is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
815
    {
816
        throw new E4xx_DeprecatedFeature('TestEnvironmentSetup phase was removed from Storyplayer v2.');
817
    }
818
819
    // ====================================================================
820
    //
821
    // Information about how to setup and teardown the test
822
    //
823
    // --------------------------------------------------------------------
824
825
    /**
826
     * get the callback for per-story setup work
827
     *
828
     * @return array
829
     */
830
    public function getTestSetup()
831
    {
832
        return $this->testSetupCallback;
833
    }
834
835
    /**
836
     * do we have a pre-story setup callback?
837
     *
838
     * @return boolean true if there is a pre-story setup callback
839
     */
840
    public function hasTestSetup()
841
    {
842
        return count($this->testSetupCallback) > 0;
843
    }
844
845
    public function addTestSetup($newCallback)
846
    {
847
        $this->testSetupCallback[] = $newCallback;
848
    }
849
850
    /**
851
     * get the callback for post-story teardown work
852
     *
853
     * @return array
854
     */
855
    public function getTestTeardown()
856
    {
857
        return $this->testTeardownCallback;
858
    }
859
860
    /**
861
     * do we have a post-story teardown callback?
862
     *
863
     * @return boolean true if there is a post-story teardown callback
864
     */
865
    public function hasTestTeardown()
866
    {
867
        return count($this->testTeardownCallback) > 0;
868
    }
869
870
    /**
871
     * @return void
872
     */
873
    public function addTestTeardown($newCallback)
874
    {
875
        $this->testTeardownCallback[] = $newCallback;
876
    }
877
878
    // ====================================================================
879
    //
880
    // Actions to happen before and after every phase of the test
881
    //
882
    // --------------------------------------------------------------------
883
884
    /**
885
     * get the callback for per-phase setup work
886
     *
887
     * @return array
888
     */
889
    public function getPerPhaseSetup()
890
    {
891
        return $this->perPhaseSetupCallback;
892
    }
893
894
    /**
895
     * do we have a per-phase setup callback?
896
     *
897
     * @return boolean true if there is a per-phase setup callback
898
     */
899
    public function hasPerPhaseSetup()
900
    {
901
        return count($this->perPhaseSetupCallback) > 0;
902
    }
903
904
    /**
905
     * @return void
906
     */
907
    public function addPerPhaseSetup($newCallback)
908
    {
909
        $this->perPhaseSetupCallback[] = $newCallback;
910
    }
911
912
    /**
913
     * get the callback for per-phase teardown work
914
     *
915
     * @return array
916
     */
917
    public function getPerPhaseTeardown()
918
    {
919
        return $this->perPhaseTeardownCallback;
920
    }
921
922
    /**
923
     * do we have a per-phase teardown callback?
924
     *
925
     * @return boolean true if there is a per-phase teardown callback
926
     */
927
    public function hasPerPhaseTeardown()
928
    {
929
        return count($this->perPhaseTeardownCallback) > 0;
930
    }
931
932
    /**
933
     * @return void
934
     */
935
    public function addPerPhaseTeardown($newCallback)
936
    {
937
        $this->perPhaseTeardownCallback[] = $newCallback;
938
    }
939
940
    // ====================================================================
941
    //
942
    // Actions to happen when starting and stopping test devices
943
    //
944
    // --------------------------------------------------------------------
945
946
    /**
947
     * get the callback for device setup work
948
     *
949
     * @return array
950
     */
951
    public function getDeviceSetup()
952
    {
953
        return $this->deviceSetupCallback;
954
    }
955
956
    /**
957
     * do we have a device setup callback?
958
     *
959
     * @return boolean true if there is a device setup callback
960
     */
961
    public function hasDeviceSetup()
962
    {
963
        return count($this->deviceSetupCallback) > 0;
964
    }
965
966
    /**
967
     * @return void
968
     */
969
    public function addDeviceSetup($newCallback)
970
    {
971
        $this->deviceSetupCallback[] = $newCallback;
972
    }
973
974
    /**
975
     * get the callback for device teardown work
976
     *
977
     * @return array
978
     */
979
    public function getDeviceTeardown()
980
    {
981
        return $this->deviceTeardownCallback;
982
    }
983
984
    /**
985
     * do we have a device teardown callback?
986
     *
987
     * @return boolean true if there is a device teardown callback
988
     */
989
    public function hasDeviceTeardown()
990
    {
991
        return count($this->deviceTeardownCallback) > 0;
992
    }
993
994
    /**
995
     * @return void
996
     */
997
    public function addDeviceTeardown($newCallback)
998
    {
999
        $this->deviceTeardownCallback[] = $newCallback;
1000
    }
1001
1002
    // ====================================================================
1003
    //
1004
    // Information about how the story changes the system
1005
    //
1006
    // --------------------------------------------------------------------
1007
1008
    /**
1009
     * get the hints callback
1010
     *
1011
     * @return callable
1012
     */
1013
    public function getHints()
1014
    {
1015
        return $this->hintsCallback;
1016
    }
1017
1018
    /**
1019
     * have any hints been set?
1020
     *
1021
     * @return boolean true if the callback has been set
1022
     */
1023
    public function hasHints()
1024
    {
1025
        return count($this->hintsCallback) > 0;
1026
    }
1027
1028
    /**
1029
     * @return void
1030
     */
1031
    public function setHints($newCallback)
1032
    {
1033
        $this->hintsCallback = array($newCallback);
1034
    }
1035
1036
    /**
1037
     * @return void
1038
     */
1039
    public function addHints($newCallback)
1040
    {
1041
        $this->hintsCallback[] = $newCallback;
1042
    }
1043
1044
    // ====================================================================
1045
    //
1046
    // Before and after tests
1047
    //
1048
    // --------------------------------------------------------------------
1049
1050
    /**
1051
     * get the callback to use to perform the preflight checks
1052
     *
1053
     * @return array
1054
     */
1055
    public function getPreTestPrediction()
1056
    {
1057
        return $this->preTestPredictionCallback;
1058
    }
1059
1060
    /**
1061
     * do we have a callback
1062
     * @return boolean [description]
1063
     */
1064
    public function hasPreTestPrediction()
1065
    {
1066
        return count($this->preTestPredictionCallback) > 0;
1067
    }
1068
1069
    /**
1070
     * @return void
1071
     */
1072
    public function addPreTestPrediction($newCallback)
1073
    {
1074
        $this->preTestPredictionCallback[] = $newCallback;
1075
    }
1076
1077
    // ====================================================================
1078
    //
1079
    // Checkpoint the relevant system state before actions occur
1080
    //
1081
    // --------------------------------------------------------------------
1082
1083
    /**
1084
     * get the callback to use to perform the preflight checkpoint
1085
     *
1086
     * @return array
1087
     */
1088
    public function getPreTestInspection()
1089
    {
1090
        return $this->preTestInspectionCallback;
1091
    }
1092
1093
    /**
1094
     * do we have a callback
1095
     * @return boolean [description]
1096
     */
1097
    public function hasPreTestInspection()
1098
    {
1099
        return count($this->preTestInspectionCallback) > 0;
1100
    }
1101
1102
    /**
1103
     * @return void
1104
     */
1105
    public function addPreTestInspection($newCallback)
1106
    {
1107
        $this->preTestInspectionCallback[] = $newCallback;
1108
    }
1109
1110
    // ====================================================================
1111
    //
1112
    // Add in the actions that make the story come to life
1113
    //
1114
    // --------------------------------------------------------------------
1115
1116
    /**
1117
     * @return void
1118
     */
1119
    public function addAction($newCallback)
1120
    {
1121
        $this->actionsCallbacks[] = $newCallback;
1122
    }
1123
1124
    /**
1125
     * @return void
1126
     */
1127
    public function addActions($newCallback)
1128
    {
1129
        $this->actionsCallbacks[] = $newCallback;
1130
    }
1131
1132
    /**
1133
     * pick one action at random, and return it to the caller
1134
     *
1135
     * @return callable
1136
     */
1137
    public function getOneAction()
1138
    {
1139
        // do we have any callbacks to pick from?
1140
        if (count($this->actionsCallbacks) == 0)
1141
        {
1142
            throw new E5xx_NoStoryActions($this->getName());
1143
        }
1144
1145
        // pick one story
1146
        $i = rand(0, count($this->actionsCallbacks) - 1);
1147
1148
        // return it to the caller
1149
        return $this->actionsCallbacks[$i];
1150
    }
1151
1152
    /**
1153
     * does this story have any actions?
1154
     *
1155
     * @return boolean true if this story has any actions
1156
     */
1157
    public function hasActions()
1158
    {
1159
        return (count($this->actionsCallbacks) > 0);
1160
    }
1161
1162
    // ====================================================================
1163
    //
1164
    // Determine whether the test passed or failed
1165
    //
1166
    // --------------------------------------------------------------------
1167
1168
    /**
1169
     * get the callback to use to work out the test results
1170
     *
1171
     * @return array
1172
     */
1173
    public function getPostTestInspection()
1174
    {
1175
        return $this->postTestInspectionCallback;
1176
    }
1177
1178
    /**
1179
     * @return bool
1180
     */
1181
    public function hasPostTestInspection()
1182
    {
1183
        return count($this->postTestInspectionCallback) > 0;
1184
    }
1185
1186
    /**
1187
     * @return void
1188
     */
1189
    public function addPostTestInspection($newCallback)
1190
    {
1191
        $this->postTestInspectionCallback[] = $newCallback;
1192
    }
1193
1194
    // ====================================================================
1195
    //
1196
    // Our default behaviour when the story object is instantiated
1197
    //
1198
    // --------------------------------------------------------------------
1199
1200
    /**
1201
     * @return void
1202
     */
1203
    public function setDefaultCallbacks()
1204
    {
1205
        // 1: test setup
1206
        if (!$this->hasTestSetup()) {
1207
            $this->addTestSetup(function(StoryTeller $st) {
1208
                $st->usingReporting()->reportNotRequired();
1209
            });
1210
        }
1211
1212
        // 2: pre-test prediction
1213
        if (!$this->hasPreTestPrediction()) {
1214
            $this->addPreTestPrediction(function(StoryTeller $st) {
1215
                $st->usingReporting()->reportShouldAlwaysSucceed();
1216
            });
1217
        }
1218
1219
        // 3: pre-test inspection
1220
        if (!$this->hasPreTestInspection()) {
1221
            $this->addPreTestInspection(function(StoryTeller $st) {
1222
                $st->usingReporting()->reportNotRequired();
1223
            });
1224
        }
1225
1226
        // 4: test action
1227
        //
1228
        // we set no default for this, because we do not want the action
1229
        // to be chosen by StoryPlayer
1230
        //
1231
        // (StoryPlayer chooses one action at random from the set of
1232
        // supplied actions)
1233
1234
        // 5: post-test inspection
1235
        //
1236
        // we set no default for this, because each story must provide
1237
        // this
1238
1239
        // 6: test tear down
1240
        if (!$this->hasTestTeardown()) {
1241
            $this->addTestTeardown(function(StoryTeller $st) {
1242
                $st->usingReporting()->reportNotRequired();
1243
            });
1244
        }
1245
1246
        // all done
1247
    }
1248
1249
    // ====================================================================
1250
    //
1251
    // Serialisation and other format convertors
1252
    //
1253
    // --------------------------------------------------------------------
1254
1255
    /**
1256
     * return a string representation of the story, for things like logging
1257
     * @return string
1258
     */
1259
    public function __toString()
1260
    {
1261
        return $this->getCategory() . ' :: ' . $this->getGroupAsString() . ' :: ' . $this->getName();
1262
    }
1263
1264
    // ==================================================================
1265
    //
1266
    // Dealing with the story result
1267
    //
1268
    // ------------------------------------------------------------------
1269
1270
    /**
1271
     * @return Story_Result
1272
     */
1273
    public function getResult()
1274
    {
1275
        if (!isset($this->storyResult)) {
1276
            $this->storyResult = new Story_Result($this);
1277
        }
1278
1279
        return $this->storyResult;
1280
    }
1281
}
1282