Skip to content

Commit 58594f3

Browse files
committed
Add tests for ImageValidationTrait and update documentation
- Add comprehensive tests for isValidImage() method - Add tests verifying dimension methods handle non-image files gracefully - Update Validation.md with isValidImage usage examples - Document all available image validation methods
1 parent 680e78c commit 58594f3

File tree

2 files changed

+294
-20
lines changed

2 files changed

+294
-20
lines changed

docs/Documentation/Validation.md

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,71 @@ class ImageValidator implements UploadValidatorInterface
3030
$validator->add('file', 'fileUnderPhpSizeLimit', [
3131
'rule' => 'isUnderPhpSizeLimit',
3232
'message' => 'This file is too large',
33-
'provider' => 'upload'
33+
'provider' => 'upload',
3434
]);
35+
36+
// Validate that the file is actually an image before checking dimensions
37+
$validator->add('file', 'fileIsValidImage', [
38+
'rule' => 'isValidImage',
39+
'message' => 'File must be a valid image (JPEG, PNG, GIF, or WebP)',
40+
'provider' => 'upload',
41+
'on' => function($context) {
42+
$file = $context['data']['file'] ?? null;
43+
return $file && $file->getError() == UPLOAD_ERR_OK;
44+
},
45+
]);
46+
3547
$validator->add('file', 'fileAboveMinHeight', [
3648
'rule' => ['isAboveMinHeight', 50],
3749
'message' => 'This image should at least be 50px high',
38-
'provider' => 'upload'
50+
'provider' => 'upload',
51+
'on' => function($context) {
52+
$file = $context['data']['file'] ?? null;
53+
return $file && $file->getError() == UPLOAD_ERR_OK;
54+
},
3955
]);
4056
$validator->add('file', 'fileAboveMinWidth', [
4157
'rule' => ['isAboveMinWidth', 50],
4258
'message' => 'This image should at least be 50px wide',
43-
'provider' => 'upload'
44-
]);
45-
46-
$validator->add('file', 'customName', [
47-
'rule' => 'nameOfTheRule',
48-
'message' => 'yourErrorMessage',
4959
'provider' => 'upload',
5060
'on' => function($context) {
51-
return !empty($context['data']['file']);
52-
}
61+
$file = $context['data']['file'] ?? null;
62+
return $file && $file->getError() == UPLOAD_ERR_OK;
63+
},
5364
]);
5465
}
55-
56-
/**
57-
* @param mixed $data
58-
*
59-
* @return false
60-
*/
61-
public static function isUnderPhpSizeLimit($data): bool
62-
{
63-
...
64-
}
6566
}
67+
```
68+
69+
## Available Image Validation Rules
70+
71+
The `ImageValidationTrait` provides the following validation methods:
72+
73+
### isValidImage
74+
75+
Validates that the uploaded file is a valid image. Use this before dimension checks to provide clear error messages when non-image files are uploaded.
76+
77+
```php
78+
// Default: allows JPEG, PNG, GIF, WebP
79+
$validator->add('file', 'fileIsValidImage', [
80+
'rule' => 'isValidImage',
81+
'message' => 'File must be a valid image',
82+
'provider' => 'upload',
83+
]);
84+
85+
// Custom allowed types
86+
$validator->add('file', 'fileIsValidImage', [
87+
'rule' => ['isValidImage', [IMAGETYPE_JPEG, IMAGETYPE_PNG]],
88+
'message' => 'File must be a JPEG or PNG image',
89+
'provider' => 'upload',
90+
]);
91+
```
92+
93+
### Dimension Validators
94+
95+
- `isAboveMinWidth($check, int $width)` - Check minimum width
96+
- `isBelowMaxWidth($check, int $width)` - Check maximum width
97+
- `isAboveMinHeight($check, int $height)` - Check minimum height
98+
- `isBelowMaxHeight($check, int $height)` - Check maximum height
99+
100+
All dimension validators safely handle non-image files by returning `false` instead of throwing an error.
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace FileStorage\Test\TestCase\Model\Validation;
4+
5+
use Cake\Core\Plugin;
6+
use Cake\TestSuite\TestCase;
7+
use FileStorage\Model\Validation\ImageValidationTrait;
8+
use Laminas\Diactoros\UploadedFile;
9+
10+
class ImageValidationTraitTest extends TestCase
11+
{
12+
use ImageValidationTrait;
13+
14+
/**
15+
* Path to the file fixtures.
16+
*
17+
* @var string
18+
*/
19+
protected string $fileFixtures;
20+
21+
/**
22+
* @return void
23+
*/
24+
public function setUp(): void
25+
{
26+
parent::setUp();
27+
28+
$this->fileFixtures = Plugin::path('FileStorage') . 'tests' . DS . 'Fixture' . DS . 'File' . DS;
29+
}
30+
31+
/**
32+
* @return void
33+
*/
34+
public function testIsValidImageWithValidJpeg(): void
35+
{
36+
$file = new UploadedFile(
37+
$this->fileFixtures . 'titus.jpg',
38+
filesize($this->fileFixtures . 'titus.jpg'),
39+
UPLOAD_ERR_OK,
40+
'titus.jpg',
41+
'image/jpeg',
42+
);
43+
44+
$this->assertTrue(static::isValidImage($file));
45+
}
46+
47+
/**
48+
* @return void
49+
*/
50+
public function testIsValidImageWithValidPng(): void
51+
{
52+
$file = new UploadedFile(
53+
$this->fileFixtures . 'cake.icon.png',
54+
filesize($this->fileFixtures . 'cake.icon.png'),
55+
UPLOAD_ERR_OK,
56+
'cake.icon.png',
57+
'image/png',
58+
);
59+
60+
$this->assertTrue(static::isValidImage($file));
61+
}
62+
63+
/**
64+
* @return void
65+
*/
66+
public function testIsValidImageWithTextFile(): void
67+
{
68+
// Create a temporary text file
69+
$tmpFile = TMP . 'test-text-file.txt';
70+
file_put_contents($tmpFile, 'This is not an image');
71+
72+
$file = new UploadedFile(
73+
$tmpFile,
74+
filesize($tmpFile),
75+
UPLOAD_ERR_OK,
76+
'test.txt',
77+
'text/plain',
78+
);
79+
80+
$this->assertFalse(static::isValidImage($file));
81+
82+
unlink($tmpFile);
83+
}
84+
85+
/**
86+
* @return void
87+
*/
88+
public function testIsValidImageWithCustomAllowedTypes(): void
89+
{
90+
$file = new UploadedFile(
91+
$this->fileFixtures . 'cake.icon.png',
92+
filesize($this->fileFixtures . 'cake.icon.png'),
93+
UPLOAD_ERR_OK,
94+
'cake.icon.png',
95+
'image/png',
96+
);
97+
98+
// PNG should pass when PNG is allowed
99+
$this->assertTrue(static::isValidImage($file, [IMAGETYPE_PNG]));
100+
101+
// PNG should fail when only JPEG is allowed
102+
$this->assertFalse(static::isValidImage($file, [IMAGETYPE_JPEG]));
103+
}
104+
105+
/**
106+
* @return void
107+
*/
108+
public function testIsValidImageWithArrayFormat(): void
109+
{
110+
$check = [
111+
'tmp_name' => $this->fileFixtures . 'titus.jpg',
112+
'name' => 'titus.jpg',
113+
'type' => 'image/jpeg',
114+
'size' => filesize($this->fileFixtures . 'titus.jpg'),
115+
'error' => UPLOAD_ERR_OK,
116+
];
117+
118+
$this->assertTrue(static::isValidImage($check));
119+
}
120+
121+
/**
122+
* @return void
123+
*/
124+
public function testIsValidImageWithMissingTmpName(): void
125+
{
126+
$check = [
127+
'name' => 'test.jpg',
128+
];
129+
130+
$this->assertFalse(static::isValidImage($check));
131+
}
132+
133+
/**
134+
* @return void
135+
*/
136+
public function testIsAboveMinWidthWithNonImageFile(): void
137+
{
138+
// Create a temporary text file
139+
$tmpFile = TMP . 'test-not-image.txt';
140+
file_put_contents($tmpFile, 'This is not an image');
141+
142+
$file = new UploadedFile(
143+
$tmpFile,
144+
filesize($tmpFile),
145+
UPLOAD_ERR_OK,
146+
'test.txt',
147+
'text/plain',
148+
);
149+
150+
// Should return false instead of throwing an error
151+
$this->assertFalse(static::isAboveMinWidth($file, 50));
152+
153+
unlink($tmpFile);
154+
}
155+
156+
/**
157+
* @return void
158+
*/
159+
public function testIsBelowMaxWidthWithNonImageFile(): void
160+
{
161+
$tmpFile = TMP . 'test-not-image.txt';
162+
file_put_contents($tmpFile, 'This is not an image');
163+
164+
$file = new UploadedFile(
165+
$tmpFile,
166+
filesize($tmpFile),
167+
UPLOAD_ERR_OK,
168+
'test.txt',
169+
'text/plain',
170+
);
171+
172+
$this->assertFalse(static::isBelowMaxWidth($file, 400));
173+
174+
unlink($tmpFile);
175+
}
176+
177+
/**
178+
* @return void
179+
*/
180+
public function testIsAboveMinHeightWithNonImageFile(): void
181+
{
182+
$tmpFile = TMP . 'test-not-image.txt';
183+
file_put_contents($tmpFile, 'This is not an image');
184+
185+
$file = new UploadedFile(
186+
$tmpFile,
187+
filesize($tmpFile),
188+
UPLOAD_ERR_OK,
189+
'test.txt',
190+
'text/plain',
191+
);
192+
193+
$this->assertFalse(static::isAboveMinHeight($file, 50));
194+
195+
unlink($tmpFile);
196+
}
197+
198+
/**
199+
* @return void
200+
*/
201+
public function testIsBelowMaxHeightWithNonImageFile(): void
202+
{
203+
$tmpFile = TMP . 'test-not-image.txt';
204+
file_put_contents($tmpFile, 'This is not an image');
205+
206+
$file = new UploadedFile(
207+
$tmpFile,
208+
filesize($tmpFile),
209+
UPLOAD_ERR_OK,
210+
'test.txt',
211+
'text/plain',
212+
);
213+
214+
$this->assertFalse(static::isBelowMaxHeight($file, 400));
215+
216+
unlink($tmpFile);
217+
}
218+
219+
/**
220+
* @return void
221+
*/
222+
public function testDimensionMethodsWithValidImage(): void
223+
{
224+
$file = new UploadedFile(
225+
$this->fileFixtures . 'titus.jpg',
226+
filesize($this->fileFixtures . 'titus.jpg'),
227+
UPLOAD_ERR_OK,
228+
'titus.jpg',
229+
'image/jpeg',
230+
);
231+
232+
// titus.jpg is larger than 50px
233+
$this->assertTrue(static::isAboveMinWidth($file, 50));
234+
$this->assertTrue(static::isAboveMinHeight($file, 50));
235+
236+
// titus.jpg is larger than 400px wide (based on existing test)
237+
$this->assertFalse(static::isBelowMaxWidth($file, 400));
238+
}
239+
}

0 commit comments

Comments
 (0)