AutotocTest::testContentField()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 20
rs 9.4285
cc 1
eloc 10
nc 1
nop 0
1
<?php
2
3
namespace eNTiDi\Autotoc\Tests;
4
5
use eNTiDi\Autotoc\Autotoc;
6
use eNTiDi\Autotoc\Tests\TestObject;
7
use SilverStripe\Core\Config\Config;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\View\ArrayData;
10
11
class AutotocTest extends SapphireTest
12
{
13
    public function setUp()
14
    {
15
        parent::setUp();
16
17
        // Enable the Autotoc extension on TestObject
18
        TestObject::add_extension('eNTiDi\Autotoc\Autotoc');
19
    }
20
21
    public function testBodyAutotoc()
22
    {
23
        $obj = new TestObject;
24
        $this->assertEquals(' data-spy="scroll" data-target=".toc"', $obj->getBodyAutotoc());
25
    }
26
27
    public function testContentField()
28
    {
29
        $obj = new TestObject;
30
        $obj->Content = '<p>Content</p>';
31
        $obj->Test2   = '<p>Test2</p>';
32
33
        // Check the default content field is Content
34
        $this->assertEquals('<p>Content</p>', $obj->OriginalContentField);
35
36
        // Try to change the content field
37
        $obj->config()->update('content_field', 'Test2');
38
        $this->assertEquals('<p>Test2</p>', $obj->OriginalContentField);
39
40
        // Change it again
41
        $obj->config()->update('content_field', 'Unexistent');
42
        $this->assertEquals('', $obj->OriginalContentField);
43
44
        // Restore original value
45
        $obj->config()->update('content_field', 'Content');
46
    }
47
48
    public function testGetAutotoc()
49
    {
50
        $obj = new TestObject;
51
        $toc = $obj->getAutotoc();
52
        $this->assertNull($toc);
53
54
        $obj->Content = file_get_contents(__DIR__.'/test1');
55
        $obj->Test2   = file_get_contents(__DIR__.'/test2');
56
57
        // Old TOC should still be cached
58
        $toc = $obj->getAutotoc();
59
        $this->assertNull($toc);
60
61
        $obj->clearAutotoc();
62
63
        $toc = $obj->getAutotoc();
64
        $this->assertTrue($toc instanceof ArrayData);
65
        $this->assertEquals(5, $toc->Children->count());
66
        $this->assertStringEqualsFile(__DIR__.'/test1', $obj->OriginalContentField);
67
        $this->assertStringEqualsFile(__DIR__.'/html2', $obj->ContentField);
68
        $this->assertStringEqualsFile(__DIR__.'/html2', $obj->Content);
69
70
        // Change the content field
71
        $obj->config()->update('content_field', 'Test2');
72
        $obj->clearAutotoc();
73
74
        $toc = $obj->getAutotoc();
75
        $this->assertNull($toc);
76
        $this->assertStringEqualsFile(__DIR__.'/test2', $obj->OriginalContentField);
77
        $this->assertStringEqualsFile(__DIR__.'/test2', $obj->ContentField);
78
    }
79
80
    public function testAugmentCallback()
81
    {
82
        $obj = new TestObject;
83
        $obj->Content = file_get_contents(__DIR__.'/test1');
84
        $obj->Test2   = file_get_contents(__DIR__.'/test2');
85
86
        // Change the augmenter at class level
87
        Config::inst()->update(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface SilverStripe\Config\Coll...nfigCollectionInterface as the method update() does only exist in the following implementations of said interface: SilverStripe\Config\Coll...s\DeltaConfigCollection, SilverStripe\Config\Coll...\MemoryConfigCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
88
            get_class($obj),
89
            'augment_callback',
90
            'eNTiDi\Autotoc\Tocifier::prependAnchor'
91
        );
92
        $obj->clearAutotoc();
93
94
        $toc = $obj->getAutotoc();
95
        $this->assertEquals(5, $toc->Children->count());
96
        $this->assertStringEqualsFile(__DIR__.'/html1', $obj->Content);
97
98
        // Change the augmenter at install level: should have higher
99
        // precedence
100
        $obj->config()->update(
101
            'augment_callback',
102
            'eNTiDi\Autotoc\Tocifier::setId'
103
        );
104
        $obj->clearAutotoc();
105
106
        $toc = $obj->getAutotoc();
107
        $this->assertEquals(5, $toc->Children->count());
108
        $this->assertStringEqualsFile(__DIR__.'/html2', $obj->Content);
109
    }
110
111
    public function testOverriding()
112
    {
113
        $html = file_get_contents(__DIR__.'/test1');
114
115
        // The content field is not expected to be changed dynamically:
116
        // we need to set it *before* creating the test instance
117
        Config::inst()->update(TestObject::class, 'content_field', 'Something');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface SilverStripe\Config\Coll...nfigCollectionInterface as the method update() does only exist in the following implementations of said interface: SilverStripe\Config\Coll...s\DeltaConfigCollection, SilverStripe\Config\Coll...\MemoryConfigCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
118
        $obj = new TestObject;
119
        $obj->Content = $html;
120
        $obj->Test2   = $html;
121
        $this->assertEquals($html, $obj->Content);
122
        $this->assertEquals($html, $obj->Test2);
123
124
        Config::inst()->update(TestObject::class, 'content_field', 'Content');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface SilverStripe\Config\Coll...nfigCollectionInterface as the method update() does only exist in the following implementations of said interface: SilverStripe\Config\Coll...s\DeltaConfigCollection, SilverStripe\Config\Coll...\MemoryConfigCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
125
        $obj = new TestObject;
126
        $obj->Content = $html;
127
        $obj->Test2   = $html;
128
        $this->assertNotEquals($html, $obj->Content);
129
        $this->assertEquals($html, $obj->Test2);
130
131
        Config::inst()->update(TestObject::class, 'content_field', 'Test2');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface SilverStripe\Config\Coll...nfigCollectionInterface as the method update() does only exist in the following implementations of said interface: SilverStripe\Config\Coll...s\DeltaConfigCollection, SilverStripe\Config\Coll...\MemoryConfigCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
132
        $obj = new TestObject;
133
        $obj->Content = $html;
134
        $obj->Test2   = $html;
135
        // The overriding works on a class basis, so the Content field
136
        // will still be overriden
137
        $this->assertNotEquals($html, $obj->Content);
138
        $this->assertNotEquals($html, $obj->Test2);
139
    }
140
}
141