]> BookStack Code Mirror - bookstack/blob - tests/Helpers/FileProvider.php
OIDC: Added testing coverage for picture fetching
[bookstack] / tests / Helpers / FileProvider.php
1 <?php
2
3 namespace Tests\Helpers;
4
5 use BookStack\Entities\Models\Page;
6 use BookStack\Uploads\Attachment;
7 use BookStack\Uploads\AttachmentService;
8 use Illuminate\Http\UploadedFile;
9 use Illuminate\Testing\TestResponse;
10 use stdClass;
11 use Tests\TestCase;
12
13 class FileProvider
14 {
15     /**
16      * Get the path to a file in the test-data-directory.
17      */
18     public function testFilePath(string $fileName): string
19     {
20         return base_path('tests/test-data/' . $fileName);
21     }
22
23     /**
24      * Creates a new temporary image file using the given name,
25      * with the content decoded from the given bas64 file name.
26      * Is generally used for testing sketchy files that could trip AV.
27      */
28     public function imageFromBase64File(string $base64FileName, string $imageFileName): UploadedFile
29     {
30         $imagePath = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), $imageFileName]);
31         $base64FilePath = $this->testFilePath($base64FileName);
32         $data = file_get_contents($base64FilePath);
33         $decoded = base64_decode($data);
34         file_put_contents($imagePath, $decoded);
35
36         return new UploadedFile($imagePath, $imageFileName, 'image/png', null, true);
37     }
38
39     /**
40      * Get a test image UploadedFile instance, that can be uploaded via test requests.
41      */
42     public function uploadedImage(string $fileName, string $testDataFileName = ''): UploadedFile
43     {
44         return new UploadedFile($this->testFilePath($testDataFileName ?: 'test-image.png'), $fileName, 'image/png', null, true);
45     }
46
47     /**
48      * Get a test txt UploadedFile instance, that can be uploaded via test requests.
49      */
50     public function uploadedTextFile(string $fileName): UploadedFile
51     {
52         return new UploadedFile($this->testFilePath('test-file.txt'), $fileName, 'text/plain', null, true);
53     }
54
55     /**
56      * Get raw data for a PNG image test file.
57      */
58     public function pngImageData(): string
59     {
60         return file_get_contents($this->testFilePath('test-image.png'));
61     }
62
63     /**
64      * Get raw data for a Jpeg image test file.
65      */
66     public function jpegImageData(): string
67     {
68         return file_get_contents($this->testFilePath('test-image.jpg'));
69     }
70
71     /**
72      * Get the expected relative path for an uploaded image of the given type and filename.
73      */
74     public function expectedImagePath(string $imageType, string $fileName): string
75     {
76         return '/uploads/images/' . $imageType . '/' . date('Y-m') . '/' . $fileName;
77     }
78
79     /**
80      * Performs an image gallery upload request with the given name.
81      */
82     public function uploadGalleryImage(TestCase $case, string $name, int $uploadedTo = 0, string $contentType = 'image/png', string $testDataFileName = ''): TestResponse
83     {
84         $file = $this->uploadedImage($name, $testDataFileName);
85
86         return $case->call('POST', '/images/gallery', ['uploaded_to' => $uploadedTo], [], ['file' => $file], ['CONTENT_TYPE' => $contentType]);
87     }
88
89     /**
90      * Upload a new gallery image and return a set of details about the image,
91      * including the json decoded response of the upload.
92      * Ensures the upload succeeds.
93      *
94      * @return array{name: string, path: string, page: Page, response: stdClass}
95      */
96     public function uploadGalleryImageToPage(TestCase $case, Page $page, string $testDataFileName = ''): array
97     {
98         $imageName = $testDataFileName ?: 'first-image.png';
99         $relPath = $this->expectedImagePath('gallery', $imageName);
100         $this->deleteAtRelativePath($relPath);
101
102         $upload = $this->uploadGalleryImage($case, $imageName, $page->id, 'image/png', $testDataFileName);
103         $upload->assertStatus(200);
104
105         return [
106             'name' => $imageName,
107             'path' => $relPath,
108             'page' => $page,
109             'response' => json_decode($upload->getContent()),
110         ];
111     }
112
113     /**
114      * Uploads an attachment file with the given name.
115      */
116     public function uploadAttachmentFile(TestCase $case, string $name, int $uploadedTo = 0): TestResponse
117     {
118         $file = $this->uploadedTextFile($name);
119
120         return $case->call('POST', '/attachments/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
121     }
122
123     /**
124      * Upload a new attachment from the given raw data of the given type, to the given page.
125      * Returns the attachment
126      */
127     public function uploadAttachmentDataToPage(TestCase $case, Page $page, string $filename, string $content, string $mimeType): Attachment
128     {
129         $file = tmpfile();
130         $filePath = stream_get_meta_data($file)['uri'];
131         file_put_contents($filePath, $content);
132         $upload = new UploadedFile($filePath, $filename, $mimeType, null, true);
133
134         $case->call('POST', '/attachments/upload', ['uploaded_to' => $page->id], [], ['file' => $upload], []);
135
136         return $page->attachments()->where('uploaded_to', '=', $page->id)->latest()->firstOrFail();
137     }
138
139     /**
140      * Delete an uploaded image.
141      */
142     public function deleteAtRelativePath(string $path): void
143     {
144         $fullPath = $this->relativeToFullPath($path);
145         if (file_exists($fullPath)) {
146             unlink($fullPath);
147         }
148     }
149
150     /**
151      * Convert a relative path used by default in this provider to a full
152      * absolute local filesystem path.
153      */
154     public function relativeToFullPath(string $path): string
155     {
156         return public_path($path);
157     }
158
159     /**
160      * Delete all uploaded files.
161      * To assist with cleanup.
162      */
163     public function deleteAllAttachmentFiles(): void
164     {
165         $fileService = app()->make(AttachmentService::class);
166         foreach (Attachment::all() as $file) {
167             $fileService->deleteFile($file);
168         }
169     }
170
171     /**
172      * Reset the application favicon image in the public path.
173      */
174     public function resetAppFavicon(): void
175     {
176         file_put_contents(public_path('favicon.ico'), file_get_contents(public_path('icon.ico')));
177     }
178 }