Passed
Push — 4 ( c79638...9463aa )
by Steve
07:35 queued 12s
created

FileFieldTest::createInvalidUploadedFileData()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 17
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 25
rs 9.7
1
<?php
2
3
namespace SilverStripe\Forms\Tests;
4
5
use ReflectionMethod;
6
use SilverStripe\Assets\Upload_Validator;
7
use SilverStripe\Dev\FunctionalTest;
8
use SilverStripe\Control\Controller;
9
use SilverStripe\Forms\FileField;
10
use SilverStripe\Forms\FieldList;
11
use SilverStripe\Forms\Form;
12
use SilverStripe\Forms\RequiredFields;
13
14
class FileFieldTest extends FunctionalTest
15
{
16
    /**
17
     * Test a valid upload of a required file in a form. Error is set to 0, as the upload went well
18
     *
19
     * @skipUpgrade
20
     */
21
    public function testUploadRequiredFile()
22
    {
23
        $form = new Form(
24
            Controller::curr(),
25
            'Form',
26
            new FieldList(
27
                $fileField = new FileField('cv', 'Upload your CV')
28
            ),
29
            new FieldList()
30
        );
31
        $fileFieldValue = [
32
            'name' => 'aCV.txt',
33
            'type' => 'application/octet-stream',
34
            'tmp_name' => '/private/var/tmp/phpzTQbqP',
35
            'error' => 0,
36
            'size' => 3471
37
        ];
38
        $fileField->setValue($fileFieldValue);
39
40
        $this->assertTrue($form->validationResult()->isValid());
41
    }
42
43
    /**
44
     * Test that FileField::validate() is run on FileFields with both single and multi-file syntax
45
     * By default FileField::validate() will return true early if the $_FILES super-global does not contain the
46
     * corresponding FileField::name. This early return means the files was not fully run through FileField::validate()
47
     * So for this test we create an invalid file upload on purpose and test that false was returned which means that
48
     * the file was run through FileField::validate() function
49
     */
50
    public function testMultiFileSyntaxUploadIsValidated()
51
    {
52
        $names = [
53
            'single_file_syntax',
54
            'multi_file_syntax_a[]',
55
            'multi_file_syntax_b[0]',
56
            'multi_file_syntax_c[key]'
57
        ];
58
        foreach ($names as $name) {
59
            $form = new Form(
60
                Controller::curr(),
61
                'Form',
62
                new FieldList($fileField = new FileField($name, 'My desc')),
63
                new FieldList()
64
            );
65
            $fileData = $this->createInvalidUploadedFileData($name, "FileFieldTest.txt");
66
            // FileFields with multi_file_syntax[] files will appear in the $_FILES super-global
67
            // with the [] brackets trimmed e.g. $_FILES[multi_file_syntax]
68
            $_FILES = [preg_replace('#\[(.*?)\]#', '', $name) => $fileData];
69
            $fileField->setValue($fileData);
70
            $validator = $form->getValidator();
71
            $isValid = $fileField->validate($validator);
72
            $this->assertFalse($isValid, "$name was run through the validate() function");
73
        }
74
    }
75
76
    protected function createInvalidUploadedFileData($name, $tmpFileName): array
77
    {
78
        $tmpFilePath = TEMP_PATH . DIRECTORY_SEPARATOR . $tmpFileName;
79
80
        // multi_file_syntax
81
        if (strpos($name, '[') !== false) {
82
            $key = 0;
83
            if (preg_match('#\[(.+?)\]#', $name, $m)) {
84
                $key = $m[1];
85
            }
86
            return [
87
                'name' => [$key => $tmpFileName],
88
                'type' => [$key => 'text/plaintext'],
89
                'size' => [$key => 0],
90
                'tmp_name' => [$key => $tmpFilePath],
91
                'error' => [$key => UPLOAD_ERR_NO_FILE],
92
            ];
93
        }
94
        // single_file_syntax
95
        return [
96
            'name' => $tmpFileName,
97
            'type' => 'text/plaintext',
98
            'size' => 0,
99
            'tmp_name' => $tmpFilePath,
100
            'error' => UPLOAD_ERR_NO_FILE,
101
        ];
102
    }
103
104
    /**
105
     * @skipUpgrade
106
     */
107
    public function testGetAcceptFileTypes()
108
    {
109
        $field = new FileField('image', 'Image');
110
        $field->setAllowedExtensions('jpg', 'png');
0 ignored issues
show
Unused Code introduced by
The call to SilverStripe\Forms\FileF...:setAllowedExtensions() has too many arguments starting with 'png'. ( Ignorable by Annotation )

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

110
        $field->/** @scrutinizer ignore-call */ 
111
                setAllowedExtensions('jpg', 'png');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
'jpg' of type string is incompatible with the type array expected by parameter $rules of SilverStripe\Forms\FileF...:setAllowedExtensions(). ( Ignorable by Annotation )

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

110
        $field->setAllowedExtensions(/** @scrutinizer ignore-type */ 'jpg', 'png');
Loading history...
111
112
        $method = new ReflectionMethod($field, 'getAcceptFileTypes');
113
        $method->setAccessible(true);
114
        $allowed = $method->invoke($field);
115
116
        $expected = ['.jpg', '.png', 'image/jpeg', 'image/png'];
117
        foreach ($expected as $extensionOrMime) {
118
            $this->assertContains($extensionOrMime, $allowed);
119
        }
120
    }
121
122
    /**
123
     * Test different scenarii for a failed upload : an error occured, no files where provided
124
     * @skipUpgrade
125
     */
126
    public function testUploadMissingRequiredFile()
127
    {
128
        $form = new Form(
129
            Controller::curr(),
130
            'Form',
131
            new FieldList(
132
                $fileField = new FileField('cv', 'Upload your CV')
133
            ),
134
            new FieldList(),
135
            new RequiredFields('cv')
136
        );
137
        // All fields are filled but for some reason an error occured when uploading the file => fails
138
        $fileFieldValue = [
139
            'name' => 'aCV.txt',
140
            'type' => 'application/octet-stream',
141
            'tmp_name' => '/private/var/tmp/phpzTQbqP',
142
            'error' => 1,
143
            'size' => 3471
144
        ];
145
        $fileField->setValue($fileFieldValue);
146
147
        $this->assertFalse(
148
            $form->validationResult()->isValid(),
149
            'An error occured when uploading a file, but the validator returned true'
150
        );
151
152
        // We pass an empty set of parameters for the uploaded file => fails
153
        $fileFieldValue = [];
154
        $fileField->setValue($fileFieldValue);
155
156
        $this->assertFalse(
157
            $form->validationResult()->isValid(),
158
            'An empty array was passed as parameter for an uploaded file, but the validator returned true'
159
        );
160
161
        // We pass an null value for the uploaded file => fails
162
        $fileFieldValue = null;
163
        $fileField->setValue($fileFieldValue);
164
165
        $this->assertFalse(
166
            $form->validationResult()->isValid(),
167
            'A null value was passed as parameter for an uploaded file, but the validator returned true'
168
        );
169
    }
170
}
171