1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
<?php
declare(strict_types=1);
namespace Drupal\Tests;
use Drupal\Core\StreamWrapper\PublicStream;
/**
* Provides methods to create test files from given values.
*
* This trait is meant to be used only by test classes.
*/
trait TestFileCreationTrait {
/**
* Whether the files were copied to the test files directory.
*
* @var bool
*/
protected $generatedTestFiles = FALSE;
/**
* Gets a list of files that can be used in tests.
*
* The first time this method is called, it will call
* $this->generateFile() to generate binary and ASCII text files in the
* public:// directory. It will also copy all files in
* core/tests/fixtures/files to public://. These contain image, SQL, PHP,
* JavaScript, and HTML files.
*
* All filenames are prefixed with their type and have appropriate extensions:
* - text-*.txt
* - binary-*.txt
* - html-*.html and html-*.txt
* - image-*.png, image-*.jpg, and image-*.gif
* - javascript-*.txt and javascript-*.script
* - php-*.txt and php-*.php
* - sql-*.txt and sql-*.sql
*
* Any subsequent calls will not generate any new files, or copy the files
* over again. However, if a test class adds a new file to public:// that
* is prefixed with one of the above types, it will get returned as well, even
* on subsequent calls.
*
* @param string $type
* File type, possible values: 'binary', 'html', 'image', 'javascript',
* 'php', 'sql', 'text'.
* @param int|null $size
* (optional) File size in bytes to match. Defaults to NULL, which will not
* filter the returned list by size.
*
* @return object[]
* List of files in public:// that match the filter(s). Each file is an
* object with 'uri', 'filename', and 'name' properties.
*/
protected function getTestFiles($type, $size = NULL) {
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
if (empty($this->generatedTestFiles)) {
// Generate binary test files.
$lines = [64, 1024];
$count = 0;
foreach ($lines as $line) {
$this->generateFile('binary-' . $count++, 64, $line, 'binary');
}
// Generate ASCII text test files.
$lines = [16, 256, 1024, 2048, 20480];
$count = 0;
foreach ($lines as $line) {
$this->generateFile('text-' . $count++, 64, $line, 'text');
}
// Copy other test files from fixtures.
$original = \Drupal::root() . '/core/tests/fixtures/files';
$files = $file_system->scanDirectory($original, '/(html|image|javascript|php|sql)-.*/');
foreach ($files as $file) {
$file_system->copy($file->uri, PublicStream::basePath());
}
$this->generatedTestFiles = TRUE;
}
$files = [];
// Make sure type is valid.
if (in_array($type, ['binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'])) {
$files = $file_system->scanDirectory('public://', '/' . $type . '\-.*/');
// If size is set then remove any files that are not of that size.
if ($size !== NULL) {
foreach ($files as $file) {
$stats = stat($file->uri);
if ($stats['size'] != $size) {
unset($files[$file->uri]);
}
}
}
}
usort($files, [$this, 'compareFiles']);
return $files;
}
/**
* Compares two files based on size and file name.
*
* Callback for uasort() within \TestFileCreationTrait::getTestFiles().
*
* @param object $file1
* The first file.
* @param object $file2
* The second class.
*
* @return int
* -1 if $file1 is smaller than $file2, 0 if they are the same size, and 1
*/
protected function compareFiles($file1, $file2): int {
$compare_size = filesize($file1->uri) - filesize($file2->uri);
if ($compare_size) {
// Sort by file size.
return $compare_size;
}
else {
// The files were the same size, so sort alphabetically.
return strnatcmp($file1->name, $file2->name);
}
}
/**
* Generates a test file.
*
* @param string $filename
* The name of the file, including the path. The suffix '.txt' is appended
* to the supplied file name and the file is put into the public:// files
* directory.
* @param int $width
* The number of characters on one line.
* @param int $lines
* The number of lines in the file.
* @param string $type
* (optional) The type, one of:
* - text: The generated file contains random ASCII characters.
* - binary: The generated file contains random characters whose codes are
* in the range of 0 to 31.
* - binary-text: The generated file contains random sequence of '0' and '1'
* values.
*
* @return string
* The name of the file, including the path.
*/
protected static function generateFile($filename, $width, $lines, $type = 'binary-text') {
$text = '';
for ($i = 0; $i < $lines; $i++) {
// Generate $width - 1 characters to leave space for the "\n" character.
for ($j = 0; $j < $width - 1; $j++) {
switch ($type) {
case 'text':
$text .= chr(rand(32, 126));
break;
case 'binary':
$text .= chr(rand(0, 31));
break;
case 'binary-text':
default:
$text .= rand(0, 1);
break;
}
}
$text .= "\n";
}
// Create filename.
$filename = 'public://' . $filename . '.txt';
file_put_contents($filename, $text);
return $filename;
}
}
|