Completed
Push — master ( 55a2d1...8b4cce )
by Daniel
18:24
created

ConfigManifestTest::testModuleRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 0
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core\Tests\Manifest;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Core\Manifest\ConfigManifest;
8
use SilverStripe\Dev\SapphireTest;
9
use ReflectionProperty;
10
use Zend_Cache_Core;
11
12
class ConfigManifestTest extends SapphireTest
13
{
14
    /**
15
     * This is a helper method for getting a new manifest
16
     *
17
     * @param string $name
18
     * @return mixed
19
     */
20
    protected function getConfigFixtureValue($name)
21
    {
22
        $manifest = new ConfigManifest(dirname(__FILE__).'/fixtures/configmanifest', true, true);
23
        return $manifest->get(__CLASS__, $name);
24
    }
25
26
    /**
27
     * This is a helper method for displaying a relevant message about a parsing failure
28
     */
29
    protected function getParsedAsMessage($path)
30
    {
31
        return sprintf('Reference path "%s" failed to parse correctly', $path);
32
    }
33
34
    /**
35
     * A helper method to return a mock of the cache in order to test expectations and reduce dependency
36
     *
37
     * @return Zend_Cache_Core
38
     */
39
    protected function getCacheMock()
40
    {
41
        return $this->getMock(
42
            'Zend_Cache_Core',
43
            array('load', 'save'),
44
            array(),
45
            '',
46
            false
47
        );
48
    }
49
50
    /**
51
     * A helper method to return a mock of the manifest in order to test expectations and reduce dependency
52
     *
53
     * @param  $methods
54
     * @return ConfigManifest
55
     */
56
    protected function getManifestMock($methods)
57
    {
58
        return $this->getMock(
59
            ConfigManifest::class,
60
            $methods,
61
            array(), // no constructor arguments
62
            '', // default
63
            false // don't call the constructor
64
        );
65
    }
66
67
    /**
68
     * Test the caching functionality when we are forcing regeneration
69
     *
70
     * 1. Test that regenerate is called in the default case and that cache->load isn't
71
     * 2. Test that save is called correctly after the regeneration
72
     */
73
    public function testCachingForceRegeneration()
74
    {
75
        // Test that regenerate is called correctly.
76
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
77
78
        $manifest->expects($this->once()) // regenerate should be called once
79
            ->method('regenerate')
80
            ->with($this->equalTo(true)); // includeTests = true
81
82
        // Set up a cache where we expect load to never be called
83
        $cache = $this->getCacheMock();
84
        $cache->expects($this->never())
85
            ->method('load');
86
87
        $manifest->expects($this->any())
88
            ->method('getCache')
89
            ->will($this->returnValue($cache));
90
91
        $manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, true);
92
93
        // Test that save is called correctly
94
        $manifest = $this->getManifestMock(array('getCache'));
95
96
        $cache = $this->getCacheMock();
97
        $cache->expects($this->atLeastOnce())
98
            ->method('save');
99
100
        $manifest->expects($this->any())
101
            ->method('getCache')
102
            ->will($this->returnValue($cache));
103
104
        $manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, true);
105
    }
106
107
    /**
108
     * Test the caching functionality when we are not forcing regeneration
109
     *
110
     * 1. Test that load is called
111
     * 2. Test the regenerate is called when the cache is unprimed
112
     * 3. Test that when there is a value in the cache regenerate isn't called
113
     */
114
    public function testCachingNotForceRegeneration()
115
    {
116
        // Test that load is called
117
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
118
119
        // Load should be called twice
120
        $cache = $this->getCacheMock();
121
        $cache->expects($this->exactly(2))
122
            ->method('load');
123
124
        $manifest->expects($this->any())
125
            ->method('getCache')
126
            ->will($this->returnValue($cache));
127
128
        $manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, false);
129
130
131
        // Now test that regenerate is called because the cache is unprimed
132
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
133
134
        $cache = $this->getCacheMock();
135
        $cache->expects($this->exactly(2))
136
            ->method('load')
137
            ->will($this->onConsecutiveCalls(false, false));
138
139
        $manifest->expects($this->any())
140
            ->method('getCache')
141
            ->will($this->returnValue($cache));
142
143
        $manifest->expects($this->once())
144
            ->method('regenerate')
145
            ->with($this->equalTo(false)); //includeTests = false
146
147
        $manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', false, false);
148
149
        // Now test that when there is a value in the cache that regenerate isn't called
150
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
151
152
        $cache = $this->getCacheMock();
153
        $cache->expects($this->exactly(2))
154
            ->method('load')
155
            ->will($this->onConsecutiveCalls(array(), array()));
156
157
        $manifest->expects($this->any())
158
            ->method('getCache')
159
            ->will($this->returnValue($cache));
160
161
        $manifest->expects($this->never())
162
            ->method('regenerate');
163
164
        $manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', false, false);
165
    }
166
167
    /**
168
     * Test cache regeneration if all or some of the cache files are missing
169
     *
170
     * 1. Test regeneration if all cache files are missing
171
     * 2. Test regeneration if 'variant_key_spec' cache file is missing
172
     * 3. Test regeneration if 'php_config_sources' cache file is missing
173
     */
174
    public function testAutomaticCacheRegeneration()
175
    {
176
        $base = dirname(__FILE__) . '/fixtures/configmanifest';
177
178
        // Test regeneration if all cache files are missing
179
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
180
181
        $manifest->expects($this->once())// regenerate should be called once
182
                 ->method('regenerate')
183
                 ->with($this->equalTo(false)); // includeTests = false
184
185
        // Set up a cache where we expect load to never be called
186
        $cache = $this->getCacheMock();
187
        $cache->expects($this->exactly(2))
188
              ->will($this->returnValue(false))
189
              ->method('load');
190
191
        $manifest->expects($this->any())
192
                 ->method('getCache')
193
                 ->will($this->returnValue($cache));
194
195
        $manifest->__construct($base);
196
197
        // Test regeneration if 'variant_key_spec' cache file is missing
198
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
199
200
        $manifest->expects($this->once())// regenerate should be called once
201
                 ->method('regenerate')
202
                 ->with($this->equalTo(false)); // includeTests = false
203
204
205
        $cache = $this->getCacheMock();
206
        $cache->expects($this->exactly(2))
207
            ->method('load')
208
            ->will($this->returnCallback(function ($parameter) {
209
                if (strpos($parameter, 'variant_key_spec') !== false) {
210
                    return false;
211
                }
212
                return array();
213
            }));
214
215
        $manifest->expects($this->any())
216
                 ->method('getCache')
217
                 ->will($this->returnValue($cache));
218
219
        $manifest->__construct($base);
220
221
        // Test regeneration if 'php_config_sources' cache file is missing
222
        $manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
223
224
        $manifest->expects($this->once())// regenerate should be called once
225
                 ->method('regenerate')
226
                 ->with($this->equalTo(false)); // includeTests = false
227
228
        $cache = $this->getCacheMock();
229
        $cache->expects($this->exactly(2))
230
            ->method('load')
231
            ->will($this->returnCallback(function ($parameter) {
232
                if (strpos($parameter, 'php_config_sources') !== false) {
233
                    return false;
234
                }
235
                return array();
236
            }));
237
238
        $manifest->expects($this->any())
239
                 ->method('getCache')
240
                 ->will($this->returnValue($cache));
241
242
        $manifest->__construct($base);
243
    }
244
245
    /**
246
     * This test checks the processing of before and after reference paths (module-name/filename#fragment)
247
     * This method uses fixture/configmanifest/mysite/_config/addyamlconfigfile.yml as a fixture
248
     */
249
    public function testAddYAMLConfigFileReferencePathParsing()
250
    {
251
        // Use a mock to avoid testing unrelated functionality
252
        $manifest = $this->getManifestMock(array('addModule'));
253
254
        // This tests that the addModule method is called with the correct value
255
        $manifest->expects($this->once())
256
            ->method('addModule')
257
            ->with($this->equalTo(dirname(__FILE__).'/fixtures/configmanifest/mysite'));
258
259
        // Call the method to be tested
260
        $manifest->addYAMLConfigFile(
261
            'addyamlconfigfile.yml',
262
            dirname(__FILE__).'/fixtures/configmanifest/mysite/_config/addyamlconfigfile.yml',
263
            false
264
        );
265
266
        // There is no getter for yamlConfigFragments
267
        $property = new ReflectionProperty('SilverStripe\\Core\\Manifest\\ConfigManifest', 'yamlConfigFragments');
268
        $property->setAccessible(true);
269
270
        // Get the result back from the parsing
271
        $result = $property->getValue($manifest);
272
273
        $this->assertEquals(
274
            array(
275
                array(
276
                    'module' => 'mysite',
277
                    'file' => 'testfile',
278
                    'name' => 'fragment',
279
                ),
280
            ),
281
            @$result[0]['after'],
282
            $this->getParsedAsMessage('mysite/testfile#fragment')
283
        );
284
285
        $this->assertEquals(
286
            array(
287
                array(
288
                    'module' => 'test-module',
289
                    'file' => 'testfile',
290
                    'name' => 'fragment',
291
                ),
292
            ),
293
            @$result[1]['after'],
294
            $this->getParsedAsMessage('test-module/testfile#fragment')
295
        );
296
297
        $this->assertEquals(
298
            array(
299
                array(
300
                    'module' => '*',
301
                    'file' => '*',
302
                    'name' => '*',
303
                ),
304
            ),
305
            @$result[2]['after'],
306
            $this->getParsedAsMessage('*')
307
        );
308
309
        $this->assertEquals(
310
            array(
311
                array(
312
                    'module' => '*',
313
                    'file' => 'testfile',
314
                    'name' => '*'
315
                ),
316
            ),
317
            @$result[3]['after'],
318
            $this->getParsedAsMessage('*/testfile')
319
        );
320
321
        $this->assertEquals(
322
            array(
323
                array(
324
                    'module' => '*',
325
                    'file' => '*',
326
                    'name' => 'fragment'
327
                ),
328
            ),
329
            @$result[4]['after'],
330
            $this->getParsedAsMessage('*/*#fragment')
331
        );
332
333
        $this->assertEquals(
334
            array(
335
                array(
336
                    'module' => '*',
337
                    'file' => '*',
338
                    'name' => 'fragment'
339
                ),
340
            ),
341
            @$result[5]['after'],
342
            $this->getParsedAsMessage('#fragment')
343
        );
344
345
        $this->assertEquals(
346
            array(
347
                array(
348
                    'module' => 'test-module',
349
                    'file' => '*',
350
                    'name' => 'fragment'
351
                ),
352
            ),
353
            @$result[6]['after'],
354
            $this->getParsedAsMessage('test-module#fragment')
355
        );
356
357
        $this->assertEquals(
358
            array(
359
                array(
360
                    'module' => 'test-module',
361
                    'file' => '*',
362
                    'name' => '*'
363
                ),
364
            ),
365
            @$result[7]['after'],
366
            $this->getParsedAsMessage('test-module')
367
        );
368
369
        $this->assertEquals(
370
            array(
371
                array(
372
                    'module' => 'test-module',
373
                    'file' => '*',
374
                    'name' => '*'
375
                ),
376
            ),
377
            @$result[8]['after'],
378
            $this->getParsedAsMessage('test-module/*')
379
        );
380
381
        $this->assertEquals(
382
            array(
383
                array(
384
                    'module' => 'test-module',
385
                    'file' => '*',
386
                    'name' => '*'
387
                ),
388
            ),
389
            @$result[9]['after'],
390
            $this->getParsedAsMessage('test-module/*/#*')
391
        );
392
    }
393
394
    public function testClassRules()
395
    {
396
        $config = $this->getConfigFixtureValue('Class');
397
398
        $this->assertEquals(
399
            'Yes',
400
            @$config['DirectorExists'],
401
            'Only rule correctly detects existing class'
402
        );
403
404
        $this->assertEquals(
405
            'No',
406
            @$config['NoSuchClassExists'],
407
            'Except rule correctly detects missing class'
408
        );
409
    }
410
411
    public function testModuleRules()
412
    {
413
        $config = $this->getConfigFixtureValue('Module');
414
415
        $this->assertEquals(
416
            'Yes',
417
            @$config['MysiteExists'],
418
            'Only rule correctly detects existing module'
419
        );
420
421
        $this->assertEquals(
422
            'No',
423
            @$config['NoSuchModuleExists'],
424
            'Except rule correctly detects missing module'
425
        );
426
    }
427
428
    public function testEnvVarSetRules()
0 ignored issues
show
Coding Style introduced by
testEnvVarSetRules uses the super-global variable $_ENV which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
429
    {
430
        $_ENV['ENVVARSET_FOO'] = 1;
431
        $config = $this->getConfigFixtureValue('EnvVarSet');
432
433
        $this->assertEquals(
434
            'Yes',
435
            @$config['FooSet'],
436
            'Only rule correctly detects set environment variable'
437
        );
438
439
        $this->assertEquals(
440
            'No',
441
            @$config['BarSet'],
442
            'Except rule correctly detects unset environment variable'
443
        );
444
    }
445
446
    public function testConstantDefinedRules()
447
    {
448
        define('CONSTANTDEFINED_FOO', 1);
449
        $config = $this->getConfigFixtureValue('ConstantDefined');
450
451
        $this->assertEquals(
452
            'Yes',
453
            @$config['FooDefined'],
454
            'Only rule correctly detects defined constant'
455
        );
456
457
        $this->assertEquals(
458
            'No',
459
            @$config['BarDefined'],
460
            'Except rule correctly detects undefined constant'
461
        );
462
    }
463
464
    public function testEnvOrConstantMatchesValueRules()
0 ignored issues
show
Coding Style introduced by
testEnvOrConstantMatchesValueRules uses the super-global variable $_ENV which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
465
    {
466
        $_ENV['ENVORCONSTANTMATCHESVALUE_FOO'] = 'Foo';
467
        define('ENVORCONSTANTMATCHESVALUE_BAR', 'Bar');
468
        $config = $this->getConfigFixtureValue('EnvOrConstantMatchesValue');
469
470
        $this->assertEquals(
471
            'Yes',
472
            @$config['FooIsFoo'],
473
            'Only rule correctly detects environment variable matches specified value'
474
        );
475
476
        $this->assertEquals(
477
            'Yes',
478
            @$config['BarIsBar'],
479
            'Only rule correctly detects constant matches specified value'
480
        );
481
482
        $this->assertEquals(
483
            'No',
484
            @$config['FooIsQux'],
485
            'Except rule correctly detects environment variable that doesn\'t match specified value'
486
        );
487
488
        $this->assertEquals(
489
            'No',
490
            @$config['BarIsQux'],
491
            'Except rule correctly detects environment variable that doesn\'t match specified value'
492
        );
493
494
        $this->assertEquals(
495
            'No',
496
            @$config['BazIsBaz'],
497
            'Except rule correctly detects undefined variable'
498
        );
499
    }
500
501
    public function testEnvironmentRules()
502
    {
503
        foreach (array('dev', 'test', 'live') as $env) {
504
            Config::nest();
505
506
            Config::inst()->update('SilverStripe\\Control\\Director', 'environment_type', $env);
507
            $config = $this->getConfigFixtureValue('Environment');
508
509
            foreach (array('dev', 'test', 'live') as $check) {
510
                $this->assertEquals(
511
                    $env == $check ? $check : 'not'.$check,
512
                    @$config[ucfirst($check).'Environment'],
513
                    'Only & except rules correctly detect environment'
514
                );
515
            }
516
517
            Config::unnest();
518
        }
519
    }
520
521
    public function testDynamicEnvironmentRules()
522
    {
523
        // First, make sure environment_type is live
524
        Director::config()->update('environment_type', 'live');
525
        $this->assertEquals('live', Director::config()->get('environment_type'));
526
527
        // Then, load in a new manifest, which includes a _config.php that sets environment_type to dev
528
        $manifest = new ConfigManifest(dirname(__FILE__).'/fixtures/configmanifest_dynamicenv', true, true);
529
        Config::inst()->pushConfigYamlManifest($manifest);
530
531
        // Make sure that stuck
532
        $this->assertEquals('dev', Director::config()->get('environment_type'));
533
534
        // And that the dynamic rule was calculated correctly
535
        $this->assertEquals('dev', Config::inst()->get(__CLASS__, 'DynamicEnvironment'));
536
    }
537
538
    public function testMultipleRules()
0 ignored issues
show
Coding Style introduced by
testMultipleRules uses the super-global variable $_ENV which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
539
    {
540
        $_ENV['MULTIPLERULES_ENVVARIABLESET'] = 1;
541
        define('MULTIPLERULES_DEFINEDCONSTANT', 'defined');
542
        $config = $this->getConfigFixtureValue('MultipleRules');
543
544
        $this->assertFalse(
545
            isset($config['TwoOnlyFail']),
546
            'Fragment is not included if one of the Only rules fails.'
547
        );
548
549
        $this->assertTrue(
550
            isset($config['TwoOnlySucceed']),
551
            'Fragment is included if both Only rules succeed.'
552
        );
553
554
        $this->assertTrue(
555
            isset($config['TwoExceptSucceed']),
556
            'Fragment is included if one of the Except rules matches.'
557
        );
558
559
        $this->assertFalse(
560
            isset($config['TwoExceptFail']),
561
            'Fragment is not included if both of the Except rules fail.'
562
        );
563
564
        $this->assertFalse(
565
            isset($config['TwoBlocksFail']),
566
            'Fragment is not included if one block fails.'
567
        );
568
569
        $this->assertTrue(
570
            isset($config['TwoBlocksSucceed']),
571
            'Fragment is included if both blocks succeed.'
572
        );
573
    }
574
575
    public function testRelativeOrder()
576
    {
577
        $accessor = new ConfigManifestTest\ConfigManifestAccess(BASE_PATH, true, false);
578
579
        // A fragment with a fully wildcard before rule
580
        $beforeWildcarded = array(
581
            'module' => 'foo', 'file' => 'alpha', 'name' => '1',
582
            'before' => array(array('module' => '*', 'file' => '*', 'name' => '*'))
583
        );
584
        // A fragment with a fully wildcard before rule and a fully explicit after rule
585
        $beforeWildcardedAfterExplicit = array_merge(
586
            $beforeWildcarded,
587
            array(
588
            'after' => array(array('module' => 'bar', 'file' => 'beta', 'name' => '2'))
589
            )
590
        );
591
        // A fragment with a fully wildcard before rule and two fully explicit after rules
592
        $beforeWildcardedAfterTwoExplicitRules = array_merge(
593
            $beforeWildcarded,
594
            array(
595
            'after' => array(
596
                array('module' => 'bar', 'file' => 'beta', 'name' => '2'),
597
                array('module' => 'baz', 'file' => 'gamma', 'name' => '3')
598
            )
599
            )
600
        );
601
        // A fragment with a fully wildcard before rule and a partially explicit after rule
602
        $beforeWildcardedAfterPartialWildcarded = array_merge(
603
            $beforeWildcarded,
604
            array(
605
            'after' => array(array('module' => 'bar', 'file' => 'beta', 'name' => '*'))
606
            )
607
        );
608
609
        // Wildcard should match any module
610
        $this->assertEquals(
611
            $accessor->relativeOrder(
612
                $beforeWildcarded,
613
                array('module' => 'qux', 'file' => 'delta', 'name' => '4')
614
            ),
615
            'before'
616
        );
617
618
        // Wildcard should match any module even if there is an opposing rule, if opposing rule doesn't match
619
        $this->assertEquals(
620
            $accessor->relativeOrder(
621
                $beforeWildcardedAfterExplicit,
622
                array('module' => 'qux', 'file' => 'delta', 'name' => '4')
623
            ),
624
            'before'
625
        );
626
627
        // Wildcard should match any module even if there is an opposing rule, if opposing rule doesn't match, no
628
        // matter how many opposing rules
629
        $this->assertEquals(
630
            $accessor->relativeOrder(
631
                $beforeWildcardedAfterExplicit,
632
                array('module' => 'qux', 'file' => 'delta', 'name' => '4')
633
            ),
634
            'before'
635
        );
636
637
        // Wildcard should match any module even if there is an opposing rule, if opposing rule doesn't match
638
        // (even if some portions do)
639
        $this->assertEquals(
640
            $accessor->relativeOrder(
641
                $beforeWildcardedAfterExplicit,
642
                array('module' => 'bar', 'file' => 'beta', 'name' => 'nomatchy')
643
            ),
644
            'before'
645
        );
646
647
        // When opposing rule matches, wildcard should be ignored
648
        $this->assertEquals(
649
            $accessor->relativeOrder(
650
                $beforeWildcardedAfterExplicit,
651
                array('module' => 'bar', 'file' => 'beta', 'name' => '2')
652
            ),
653
            'after'
654
        );
655
656
        // When any one of mutiple opposing rule exists, wildcard should be ignored
657
        $this->assertEquals(
658
            $accessor->relativeOrder(
659
                $beforeWildcardedAfterTwoExplicitRules,
660
                array('module' => 'bar', 'file' => 'beta', 'name' => '2')
661
            ),
662
            'after'
663
        );
664
665
        $this->assertEquals(
666
            $accessor->relativeOrder(
667
                $beforeWildcardedAfterTwoExplicitRules,
668
                array('module' => 'baz', 'file' => 'gamma', 'name' => '3')
669
            ),
670
            'after'
671
        );
672
673
        // When two opposed wildcard rules, and more specific one doesn't match, other should win
674
        $this->assertEquals(
675
            $accessor->relativeOrder(
676
                $beforeWildcardedAfterPartialWildcarded,
677
                array('module' => 'qux', 'file' => 'delta', 'name' => '4')
678
            ),
679
            'before'
680
        );
681
682
        // When two opposed wildcard rules, and more specific one does match, more specific one should win
683
        $this->assertEquals(
684
            $accessor->relativeOrder(
685
                $beforeWildcardedAfterPartialWildcarded,
686
                array('module' => 'bar', 'file' => 'beta', 'name' => 'wildcardmatchy')
687
            ),
688
            'after'
689
        );
690
    }
691
}
692