Passed
Push — master ( 4d6caf...4726e4 )
by Siad
10:49
created

MkdirTaskTest::assertFileModeIs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
/**
21
 * Tests the Mkdir Task
22
 *
23
 * @package phing.tasks.system
24
 */
25
class MkdirTaskTest extends BuildFileTest
26
{
27
    private $originalUmask;
28
29
    public function setUp(): void
30
    {
31
        $this->originalUmask = umask();
32
        $this->configureProject(
33
            PHING_TEST_BASE . '/etc/tasks/system/MkdirTaskTest.xml'
34
        );
35
36
        $this->executeTarget('clean');
37
        mkdir(PHING_TEST_BASE . '/etc/tasks/system/tmp');
38
    }
39
40
    public function tearDown(): void
41
    {
42
        $this->executeTarget('clean');
43
        umask($this->originalUmask);
44
    }
45
46
    /**
47
     * @dataProvider umaskIsHonouredWhenNotUsingModeArgumentDataProvider
48
     */
49
    public function testUmaskIsHonouredWhenNotUsingModeArgument($umask, $expectedDirMode)
50
    {
51
        if ($umask !== 0) {
52
            $this->markTestSkippedIfOsIsWindows();
53
        }
54
55
        umask($umask);
56
        $this->executeTarget(__FUNCTION__);
57
        $this->assertFileModeIs(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', $expectedDirMode);
58
    }
59
60
    public function umaskIsHonouredWhenNotUsingModeArgumentDataProvider()
61
    {
62
        return [
63
            [0000, 0777],
64
            [0007, 0770],
65
            [0077, 0700],
66
        ];
67
    }
68
69
    public function testUmaskIsIgnoredWhenUsingModeArgument()
70
    {
71
        umask(0077);
72
        $this->executeTarget(__FUNCTION__);
73
        $this->assertFileModeIs(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 0777);
74
    }
75
76
    /**
77
     * @dataProvider parentDirectoriesHaveDefaultPermissionsDataProvider
78
     */
79
    public function testParentDirectoriesHaveDefaultPermissions($umask, $expectedModeA, $expectedModeB)
80
    {
81
        if ($umask !== 0) {
82
            $this->markTestSkippedIfOsIsWindows();
83
        }
84
85
        umask($umask);
86
        $this->executeTarget(__FUNCTION__);
87
        $this->assertFileModeIs(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', $expectedModeA);
88
        $this->assertFileModeIs(PHING_TEST_BASE . '/etc/tasks/system/tmp/a/b', $expectedModeB);
89
    }
90
91
    public function parentDirectoriesHaveDefaultPermissionsDataProvider()
92
    {
93
        return [
94
            [
95
                'umask' => 0000,
96
                'expectedPermissionsOfA' => 0777,
97
                'expectedPermissionsOfB' => 0555,
98
            ],
99
            [
100
                'umask' => 0077,
101
                'expectedPermissionsOfA' => 0700,
102
                'expectedPermissionsOfB' => 0555,
103
            ],
104
        ];
105
    }
106
107
    public function testAclIsInheritedFromParentDirectoryDefaultAcl()
108
    {
109
        $this->markTestSkippedIfAclIsNotSupported();
110
111
        shell_exec('setfacl --remove-default ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
112
        shell_exec('setfacl --modify default:user:root:rwx ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
113
114
        $this->executeTarget(__FUNCTION__);
115
116
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'user:root:rwx');
117
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'default:user:root:rwx');
118
    }
119
120
    public function testUmaskIsIgnoredWhenAclIsUsedAndTaskDoesNotHaveModeArgument()
121
    {
122
        $this->markTestSkippedIfAclIsNotSupported();
123
124
        shell_exec('setfacl --remove-default ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
125
        shell_exec('setfacl --modify default:user:root:rwx ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
126
127
        umask(0077);
128
        $this->executeTarget(__FUNCTION__);
129
130
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'mask::rwx');
131
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'user:root:rwx');
132
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'default:user:root:rwx');
133
    }
134
135
    public function testUmaskIsIgnoredWhenAclIsUsedAndTaskHasModeArgument()
136
    {
137
        $this->markTestSkippedIfAclIsNotSupported();
138
139
        shell_exec('setfacl --remove-default ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
140
        shell_exec('setfacl --modify default:user:root:rwx ' . PHING_TEST_BASE . '/etc/tasks/system/tmp');
141
142
        umask(0077);
143
        $this->executeTarget(__FUNCTION__);
144
145
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'mask::rwx');
146
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'user:root:rwx');
147
        $this->assertFileAclContains(PHING_TEST_BASE . '/etc/tasks/system/tmp/a', 'default:user:root:rwx');
148
    }
149
150
    /**
151
     * @param string $filename
152
     * @param int $mode
153
     */
154
    private function assertFileModeIs($filename, $mode)
155
    {
156
        $stat = stat($filename);
157
158
        $this->assertSame(
159
            sprintf("%03o", $mode),
160
            sprintf("%03o", $stat['mode'] & 0777),
161
            sprintf('Failed asserting that file mode of "%s" is %03o', $filename, $mode)
162
        );
163
    }
164
165
    /**
166
     * @param string $filename
167
     * @param string $expectedAclEntry
168
     */
169
    private function assertFileAclContains($filename, $expectedAclEntry)
170
    {
171
        $output = shell_exec('getfacl --omit-header --absolute-names ' . escapeshellarg($filename));
172
173
        $aclEntries = preg_split('/[\r\n]+/', $output, -1, PREG_SPLIT_NO_EMPTY);
174
175
        $matchFound = false;
176
        foreach ($aclEntries as $aclEntry) {
177
            if ($aclEntry === $expectedAclEntry) {
178
                $matchFound = true;
179
                break;
180
            }
181
        }
182
183
        $this->assertTrue(
184
            $matchFound,
185
            sprintf(
186
                'Failed asserting that ACL of file "%s" contains "%s" entry.' . "\n"
187
                . 'Following ACL entries are present:' . "\n%s\n",
188
                $filename,
189
                $expectedAclEntry,
190
                implode("\n", $aclEntries)
0 ignored issues
show
Bug introduced by
It seems like $aclEntries can also be of type false; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
                implode("\n", /** @scrutinizer ignore-type */ $aclEntries)
Loading history...
191
            )
192
        );
193
    }
194
195
    private function markTestSkippedIfOsIsWindows()
196
    {
197
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
198
            $this->markTestSkipped('POSIX ACL tests cannot be run on Windows.');
199
        }
200
    }
201
202
    private function markTestSkippedIfAclIsNotSupported()
203
    {
204
        $this->markTestSkippedIfOsIsWindows();
205
206
        exec('which setfacl', $dummyOutput, $exitCode);
207
        if ($exitCode !== 0) {
208
            $this->markTestSkipped('"setfacl" command not found. POSIX ACL tests cannot be run.');
209
        }
210
    }
211
}
212