Completed
Push — master ( ca4819...0ca6f7 )
by Joas
28:28 queued 14s
created
apps/dav/tests/unit/BackgroundJob/CleanupOrphanedChildrenJobTest.php 2 patches
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -21,150 +21,150 @@
 block discarded – undo
21 21
 use Test\TestCase;
22 22
 
23 23
 class CleanupOrphanedChildrenJobTest extends TestCase {
24
-	private CleanupOrphanedChildrenJob $job;
25
-
26
-	private ITimeFactory&MockObject $timeFactory;
27
-	private IDBConnection&MockObject $connection;
28
-	private LoggerInterface&MockObject $logger;
29
-	private IJobList&MockObject $jobList;
30
-
31
-	protected function setUp(): void {
32
-		parent::setUp();
33
-
34
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
35
-		$this->connection = $this->createMock(IDBConnection::class);
36
-		$this->logger = $this->createMock(LoggerInterface::class);
37
-		$this->jobList = $this->createMock(IJobList::class);
38
-
39
-		$this->job = new CleanupOrphanedChildrenJob(
40
-			$this->timeFactory,
41
-			$this->connection,
42
-			$this->logger,
43
-			$this->jobList,
44
-		);
45
-	}
46
-
47
-	private function getArgument(): array {
48
-		return [
49
-			'childTable' => 'childTable',
50
-			'parentTable' => 'parentTable',
51
-			'parentId' => 'parentId',
52
-			'logMessage' => 'logMessage',
53
-		];
54
-	}
55
-
56
-	private function getMockQueryBuilder(): IQueryBuilder&MockObject {
57
-		$expr = $this->createMock(IExpressionBuilder::class);
58
-		$qb = $this->createMock(IQueryBuilder::class);
59
-		$qb->method('select')
60
-			->willReturnSelf();
61
-		$qb->method('from')
62
-			->willReturnSelf();
63
-		$qb->method('leftJoin')
64
-			->willReturnSelf();
65
-		$qb->method('where')
66
-			->willReturnSelf();
67
-		$qb->method('setMaxResults')
68
-			->willReturnSelf();
69
-		$qb->method('andWhere')
70
-			->willReturnSelf();
71
-		$qb->method('expr')
72
-			->willReturn($expr);
73
-		$qb->method('delete')
74
-			->willReturnSelf();
75
-		return $qb;
76
-	}
77
-
78
-	public function testRunWithoutOrphans(): void {
79
-		$argument = $this->getArgument();
80
-		$selectQb = $this->getMockQueryBuilder();
81
-		$result = $this->createMock(IResult::class);
82
-
83
-		$this->connection->expects(self::once())
84
-			->method('getQueryBuilder')
85
-			->willReturn($selectQb);
86
-		$selectQb->expects(self::once())
87
-			->method('executeQuery')
88
-			->willReturn($result);
89
-		$result->expects(self::once())
90
-			->method('fetchAll')
91
-			->willReturn([]);
92
-		$result->expects(self::once())
93
-			->method('closeCursor');
94
-		$this->jobList->expects(self::never())
95
-			->method('add');
96
-
97
-		self::invokePrivate($this->job, 'run', [$argument]);
98
-	}
99
-
100
-	public function testRunWithPartialBatch(): void {
101
-		$argument = $this->getArgument();
102
-		$selectQb = $this->getMockQueryBuilder();
103
-		$deleteQb = $this->getMockQueryBuilder();
104
-		$result = $this->createMock(IResult::class);
105
-
106
-		$calls = [
107
-			$selectQb,
108
-			$deleteQb,
109
-		];
110
-		$this->connection->method('getQueryBuilder')
111
-			->willReturnCallback(function () use (&$calls) {
112
-				return array_shift($calls);
113
-			});
114
-		$selectQb->expects(self::once())
115
-			->method('executeQuery')
116
-			->willReturn($result);
117
-		$result->expects(self::once())
118
-			->method('fetchAll')
119
-			->willReturn([
120
-				['id' => 42],
121
-				['id' => 43],
122
-			]);
123
-		$result->expects(self::once())
124
-			->method('closeCursor');
125
-		$deleteQb->expects(self::once())
126
-			->method('delete')
127
-			->willReturnSelf();
128
-		$deleteQb->expects(self::once())
129
-			->method('executeStatement');
130
-		$this->jobList->expects(self::never())
131
-			->method('add');
132
-
133
-		self::invokePrivate($this->job, 'run', [$argument]);
134
-	}
135
-
136
-	public function testRunWithFullBatch(): void {
137
-		$argument = $this->getArgument();
138
-		$selectQb = $this->getMockQueryBuilder();
139
-		$deleteQb = $this->getMockQueryBuilder();
140
-		$result = $this->createMock(IResult::class);
141
-
142
-		$calls = [
143
-			$selectQb,
144
-			$deleteQb,
145
-		];
146
-		$this->connection->method('getQueryBuilder')
147
-			->willReturnCallback(function () use (&$calls) {
148
-				return array_shift($calls);
149
-			});
150
-
151
-		$selectQb->expects(self::once())
152
-			->method('executeQuery')
153
-			->willReturn($result);
154
-		$result->expects(self::once())
155
-			->method('fetchAll')
156
-			->willReturn(array_map(static fn ($i) => ['id' => 42 + $i], range(0, 999)));
157
-		$result->expects(self::once())
158
-			->method('closeCursor');
159
-		$deleteQb->expects(self::once())
160
-			->method('delete')
161
-			->willReturnSelf();
162
-		$deleteQb->expects(self::once())
163
-			->method('executeStatement');
164
-		$this->jobList->expects(self::once())
165
-			->method('add')
166
-			->with(CleanupOrphanedChildrenJob::class, $argument);
167
-
168
-		self::invokePrivate($this->job, 'run', [$argument]);
169
-	}
24
+    private CleanupOrphanedChildrenJob $job;
25
+
26
+    private ITimeFactory&MockObject $timeFactory;
27
+    private IDBConnection&MockObject $connection;
28
+    private LoggerInterface&MockObject $logger;
29
+    private IJobList&MockObject $jobList;
30
+
31
+    protected function setUp(): void {
32
+        parent::setUp();
33
+
34
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
35
+        $this->connection = $this->createMock(IDBConnection::class);
36
+        $this->logger = $this->createMock(LoggerInterface::class);
37
+        $this->jobList = $this->createMock(IJobList::class);
38
+
39
+        $this->job = new CleanupOrphanedChildrenJob(
40
+            $this->timeFactory,
41
+            $this->connection,
42
+            $this->logger,
43
+            $this->jobList,
44
+        );
45
+    }
46
+
47
+    private function getArgument(): array {
48
+        return [
49
+            'childTable' => 'childTable',
50
+            'parentTable' => 'parentTable',
51
+            'parentId' => 'parentId',
52
+            'logMessage' => 'logMessage',
53
+        ];
54
+    }
55
+
56
+    private function getMockQueryBuilder(): IQueryBuilder&MockObject {
57
+        $expr = $this->createMock(IExpressionBuilder::class);
58
+        $qb = $this->createMock(IQueryBuilder::class);
59
+        $qb->method('select')
60
+            ->willReturnSelf();
61
+        $qb->method('from')
62
+            ->willReturnSelf();
63
+        $qb->method('leftJoin')
64
+            ->willReturnSelf();
65
+        $qb->method('where')
66
+            ->willReturnSelf();
67
+        $qb->method('setMaxResults')
68
+            ->willReturnSelf();
69
+        $qb->method('andWhere')
70
+            ->willReturnSelf();
71
+        $qb->method('expr')
72
+            ->willReturn($expr);
73
+        $qb->method('delete')
74
+            ->willReturnSelf();
75
+        return $qb;
76
+    }
77
+
78
+    public function testRunWithoutOrphans(): void {
79
+        $argument = $this->getArgument();
80
+        $selectQb = $this->getMockQueryBuilder();
81
+        $result = $this->createMock(IResult::class);
82
+
83
+        $this->connection->expects(self::once())
84
+            ->method('getQueryBuilder')
85
+            ->willReturn($selectQb);
86
+        $selectQb->expects(self::once())
87
+            ->method('executeQuery')
88
+            ->willReturn($result);
89
+        $result->expects(self::once())
90
+            ->method('fetchAll')
91
+            ->willReturn([]);
92
+        $result->expects(self::once())
93
+            ->method('closeCursor');
94
+        $this->jobList->expects(self::never())
95
+            ->method('add');
96
+
97
+        self::invokePrivate($this->job, 'run', [$argument]);
98
+    }
99
+
100
+    public function testRunWithPartialBatch(): void {
101
+        $argument = $this->getArgument();
102
+        $selectQb = $this->getMockQueryBuilder();
103
+        $deleteQb = $this->getMockQueryBuilder();
104
+        $result = $this->createMock(IResult::class);
105
+
106
+        $calls = [
107
+            $selectQb,
108
+            $deleteQb,
109
+        ];
110
+        $this->connection->method('getQueryBuilder')
111
+            ->willReturnCallback(function () use (&$calls) {
112
+                return array_shift($calls);
113
+            });
114
+        $selectQb->expects(self::once())
115
+            ->method('executeQuery')
116
+            ->willReturn($result);
117
+        $result->expects(self::once())
118
+            ->method('fetchAll')
119
+            ->willReturn([
120
+                ['id' => 42],
121
+                ['id' => 43],
122
+            ]);
123
+        $result->expects(self::once())
124
+            ->method('closeCursor');
125
+        $deleteQb->expects(self::once())
126
+            ->method('delete')
127
+            ->willReturnSelf();
128
+        $deleteQb->expects(self::once())
129
+            ->method('executeStatement');
130
+        $this->jobList->expects(self::never())
131
+            ->method('add');
132
+
133
+        self::invokePrivate($this->job, 'run', [$argument]);
134
+    }
135
+
136
+    public function testRunWithFullBatch(): void {
137
+        $argument = $this->getArgument();
138
+        $selectQb = $this->getMockQueryBuilder();
139
+        $deleteQb = $this->getMockQueryBuilder();
140
+        $result = $this->createMock(IResult::class);
141
+
142
+        $calls = [
143
+            $selectQb,
144
+            $deleteQb,
145
+        ];
146
+        $this->connection->method('getQueryBuilder')
147
+            ->willReturnCallback(function () use (&$calls) {
148
+                return array_shift($calls);
149
+            });
150
+
151
+        $selectQb->expects(self::once())
152
+            ->method('executeQuery')
153
+            ->willReturn($result);
154
+        $result->expects(self::once())
155
+            ->method('fetchAll')
156
+            ->willReturn(array_map(static fn ($i) => ['id' => 42 + $i], range(0, 999)));
157
+        $result->expects(self::once())
158
+            ->method('closeCursor');
159
+        $deleteQb->expects(self::once())
160
+            ->method('delete')
161
+            ->willReturnSelf();
162
+        $deleteQb->expects(self::once())
163
+            ->method('executeStatement');
164
+        $this->jobList->expects(self::once())
165
+            ->method('add')
166
+            ->with(CleanupOrphanedChildrenJob::class, $argument);
167
+
168
+        self::invokePrivate($this->job, 'run', [$argument]);
169
+    }
170 170
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 			$deleteQb,
109 109
 		];
110 110
 		$this->connection->method('getQueryBuilder')
111
-			->willReturnCallback(function () use (&$calls) {
111
+			->willReturnCallback(function() use (&$calls) {
112 112
 				return array_shift($calls);
113 113
 			});
114 114
 		$selectQb->expects(self::once())
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 			$deleteQb,
145 145
 		];
146 146
 		$this->connection->method('getQueryBuilder')
147
-			->willReturnCallback(function () use (&$calls) {
147
+			->willReturnCallback(function() use (&$calls) {
148 148
 				return array_shift($calls);
149 149
 			});
150 150
 
Please login to merge, or discard this patch.
apps/dav/tests/unit/BackgroundJob/RefreshWebcalJobTest.php 1 patch
Indentation   +75 added lines, -75 removed lines patch added patch discarded remove patch
@@ -19,79 +19,79 @@
 block discarded – undo
19 19
 use Test\TestCase;
20 20
 
21 21
 class RefreshWebcalJobTest extends TestCase {
22
-	private RefreshWebcalService&MockObject $refreshWebcalService;
23
-	private IConfig&MockObject $config;
24
-	private LoggerInterface $logger;
25
-	private ITimeFactory&MockObject $timeFactory;
26
-	private IJobList&MockObject $jobList;
27
-
28
-	protected function setUp(): void {
29
-		parent::setUp();
30
-
31
-		$this->refreshWebcalService = $this->createMock(RefreshWebcalService::class);
32
-		$this->config = $this->createMock(IConfig::class);
33
-		$this->logger = $this->createMock(LoggerInterface::class);
34
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
35
-
36
-		$this->jobList = $this->createMock(IJobList::class);
37
-	}
38
-
39
-	/**
40
-	 *
41
-	 * @param int $lastRun
42
-	 * @param int $time
43
-	 * @param bool $process
44
-	 *
45
-	 * @dataProvider runDataProvider
46
-	 */
47
-	public function testRun(int $lastRun, int $time, bool $process): void {
48
-		$backgroundJob = new RefreshWebcalJob($this->refreshWebcalService, $this->config, $this->logger, $this->timeFactory);
49
-		$backgroundJob->setId(42);
50
-
51
-		$backgroundJob->setArgument([
52
-			'principaluri' => 'principals/users/testuser',
53
-			'uri' => 'sub123',
54
-		]);
55
-		$backgroundJob->setLastRun($lastRun);
56
-
57
-		$this->refreshWebcalService->expects($this->once())
58
-			->method('getSubscription')
59
-			->with('principals/users/testuser', 'sub123')
60
-			->willReturn([
61
-				'id' => '99',
62
-				'uri' => 'sub456',
63
-				'{http://apple.com/ns/ical/}refreshrate' => 'P1D',
64
-				'{http://calendarserver.org/ns/}subscribed-strip-todos' => '1',
65
-				'{http://calendarserver.org/ns/}subscribed-strip-alarms' => '1',
66
-				'{http://calendarserver.org/ns/}subscribed-strip-attachments' => '1',
67
-				'source' => 'webcal://foo.bar/bla'
68
-			]);
69
-
70
-		$this->config->expects($this->once())
71
-			->method('getAppValue')
72
-			->with('dav', 'calendarSubscriptionRefreshRate', 'P1D')
73
-			->willReturn('P1W');
74
-
75
-		$this->timeFactory->method('getTime')
76
-			->willReturn($time);
77
-
78
-		if ($process) {
79
-			$this->refreshWebcalService->expects($this->once())
80
-				->method('refreshSubscription')
81
-				->with('principals/users/testuser', 'sub123');
82
-		} else {
83
-			$this->refreshWebcalService->expects($this->never())
84
-				->method('refreshSubscription')
85
-				->with('principals/users/testuser', 'sub123');
86
-		}
87
-
88
-		$backgroundJob->start($this->jobList);
89
-	}
90
-
91
-	public static function runDataProvider():array {
92
-		return [
93
-			[0, 100000, true],
94
-			[100000, 100000, false]
95
-		];
96
-	}
22
+    private RefreshWebcalService&MockObject $refreshWebcalService;
23
+    private IConfig&MockObject $config;
24
+    private LoggerInterface $logger;
25
+    private ITimeFactory&MockObject $timeFactory;
26
+    private IJobList&MockObject $jobList;
27
+
28
+    protected function setUp(): void {
29
+        parent::setUp();
30
+
31
+        $this->refreshWebcalService = $this->createMock(RefreshWebcalService::class);
32
+        $this->config = $this->createMock(IConfig::class);
33
+        $this->logger = $this->createMock(LoggerInterface::class);
34
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
35
+
36
+        $this->jobList = $this->createMock(IJobList::class);
37
+    }
38
+
39
+    /**
40
+     *
41
+     * @param int $lastRun
42
+     * @param int $time
43
+     * @param bool $process
44
+     *
45
+     * @dataProvider runDataProvider
46
+     */
47
+    public function testRun(int $lastRun, int $time, bool $process): void {
48
+        $backgroundJob = new RefreshWebcalJob($this->refreshWebcalService, $this->config, $this->logger, $this->timeFactory);
49
+        $backgroundJob->setId(42);
50
+
51
+        $backgroundJob->setArgument([
52
+            'principaluri' => 'principals/users/testuser',
53
+            'uri' => 'sub123',
54
+        ]);
55
+        $backgroundJob->setLastRun($lastRun);
56
+
57
+        $this->refreshWebcalService->expects($this->once())
58
+            ->method('getSubscription')
59
+            ->with('principals/users/testuser', 'sub123')
60
+            ->willReturn([
61
+                'id' => '99',
62
+                'uri' => 'sub456',
63
+                '{http://apple.com/ns/ical/}refreshrate' => 'P1D',
64
+                '{http://calendarserver.org/ns/}subscribed-strip-todos' => '1',
65
+                '{http://calendarserver.org/ns/}subscribed-strip-alarms' => '1',
66
+                '{http://calendarserver.org/ns/}subscribed-strip-attachments' => '1',
67
+                'source' => 'webcal://foo.bar/bla'
68
+            ]);
69
+
70
+        $this->config->expects($this->once())
71
+            ->method('getAppValue')
72
+            ->with('dav', 'calendarSubscriptionRefreshRate', 'P1D')
73
+            ->willReturn('P1W');
74
+
75
+        $this->timeFactory->method('getTime')
76
+            ->willReturn($time);
77
+
78
+        if ($process) {
79
+            $this->refreshWebcalService->expects($this->once())
80
+                ->method('refreshSubscription')
81
+                ->with('principals/users/testuser', 'sub123');
82
+        } else {
83
+            $this->refreshWebcalService->expects($this->never())
84
+                ->method('refreshSubscription')
85
+                ->with('principals/users/testuser', 'sub123');
86
+        }
87
+
88
+        $backgroundJob->start($this->jobList);
89
+    }
90
+
91
+    public static function runDataProvider():array {
92
+        return [
93
+            [0, 100000, true],
94
+            [100000, 100000, false]
95
+        ];
96
+    }
97 97
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Upload/AssemblyStreamTest.php 2 patches
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -12,161 +12,161 @@
 block discarded – undo
12 12
 
13 13
 class AssemblyStreamTest extends \Test\TestCase {
14 14
 
15
-	/**
16
-	 * @dataProvider providesNodes()
17
-	 */
18
-	public function testGetContents(string $expected, array $nodeData): void {
19
-		$nodes = [];
20
-		foreach ($nodeData as $data) {
21
-			$nodes[] = $this->buildNode(...$data);
22
-		}
23
-		$stream = AssemblyStream::wrap($nodes);
24
-		$content = stream_get_contents($stream);
25
-
26
-		$this->assertEquals($expected, $content);
27
-	}
28
-
29
-	/**
30
-	 * @dataProvider providesNodes()
31
-	 */
32
-	public function testGetContentsFread(string $expected, array $nodeData, int $chunkLength = 3): void {
33
-		$nodes = [];
34
-		foreach ($nodeData as $data) {
35
-			$nodes[] = $this->buildNode(...$data);
36
-		}
37
-		$stream = AssemblyStream::wrap($nodes);
38
-
39
-		$content = '';
40
-		while (!feof($stream)) {
41
-			$chunk = fread($stream, $chunkLength);
42
-			$content .= $chunk;
43
-			if ($chunkLength !== 3) {
44
-				$this->assertEquals($chunkLength, strlen($chunk));
45
-			}
46
-		}
47
-
48
-		$this->assertEquals($expected, $content);
49
-	}
50
-
51
-	/**
52
-	 * @dataProvider providesNodes()
53
-	 */
54
-	public function testSeek(string $expected, array $nodeData): void {
55
-		$nodes = [];
56
-		foreach ($nodeData as $data) {
57
-			$nodes[] = $this->buildNode(...$data);
58
-		}
59
-
60
-		$stream = AssemblyStream::wrap($nodes);
61
-
62
-		$offset = floor(strlen($expected) * 0.6);
63
-		if (fseek($stream, $offset) === -1) {
64
-			$this->fail('fseek failed');
65
-		}
66
-
67
-		$content = stream_get_contents($stream);
68
-		$this->assertEquals(substr($expected, $offset), $content);
69
-	}
70
-
71
-	public static function providesNodes(): array {
72
-		$data8k = self::makeData(8192);
73
-		$dataLess8k = self::makeData(8191);
74
-
75
-		$tonofnodes = [];
76
-		$tonofdata = '';
77
-		for ($i = 0; $i < 101; $i++) {
78
-			$thisdata = random_int(0, 100); // variable length and content
79
-			$tonofdata .= $thisdata;
80
-			$tonofnodes[] = [(string)$i, (string)$thisdata];
81
-		}
82
-
83
-		return[
84
-			'one node zero bytes' => [
85
-				'', [
86
-					['0', ''],
87
-				]],
88
-			'one node only' => [
89
-				'1234567890', [
90
-					['0', '1234567890'],
91
-				]],
92
-			'one node buffer boundary' => [
93
-				$data8k, [
94
-					['0', $data8k],
95
-				]],
96
-			'two nodes' => [
97
-				'1234567890', [
98
-					['1', '67890'],
99
-					['0', '12345'],
100
-				]],
101
-			'two nodes end on buffer boundary' => [
102
-				$data8k . $data8k, [
103
-					['1', $data8k],
104
-					['0', $data8k],
105
-				]],
106
-			'two nodes with one on buffer boundary' => [
107
-				$data8k . $dataLess8k, [
108
-					['1', $dataLess8k],
109
-					['0', $data8k],
110
-				]],
111
-			'two nodes on buffer boundary plus one byte' => [
112
-				$data8k . 'X' . $data8k, [
113
-					['1', $data8k],
114
-					['0', $data8k . 'X'],
115
-				]],
116
-			'two nodes on buffer boundary plus one byte at the end' => [
117
-				$data8k . $data8k . 'X', [
118
-					['1', $data8k . 'X'],
119
-					['0', $data8k],
120
-				]],
121
-			'a ton of nodes' => [
122
-				$tonofdata, $tonofnodes
123
-			],
124
-			'one read over multiple nodes' => [
125
-				'1234567890', [
126
-					['0', '1234'],
127
-					['1', '5678'],
128
-					['2', '90'],
129
-				], 10],
130
-			'two reads over multiple nodes' => [
131
-				'1234567890', [
132
-					['0', '1234'],
133
-					['1', '5678'],
134
-					['2', '90'],
135
-				], 5],
136
-		];
137
-	}
138
-
139
-	private static function makeData(int $count): string {
140
-		$data = '';
141
-		$base = '1234567890';
142
-		$j = 0;
143
-		for ($i = 0; $i < $count; $i++) {
144
-			$data .= $base[$j];
145
-			$j++;
146
-			if (!isset($base[$j])) {
147
-				$j = 0;
148
-			}
149
-		}
150
-		return $data;
151
-	}
152
-
153
-	private function buildNode(string $name, string $data) {
154
-		$node = $this->getMockBuilder(File::class)
155
-			->onlyMethods(['getName', 'get', 'getSize'])
156
-			->getMock();
157
-
158
-		$node->expects($this->any())
159
-			->method('getName')
160
-			->willReturn($name);
161
-
162
-		$node->expects($this->any())
163
-			->method('get')
164
-			->willReturn($data);
165
-
166
-		$node->expects($this->any())
167
-			->method('getSize')
168
-			->willReturn(strlen($data));
169
-
170
-		return $node;
171
-	}
15
+    /**
16
+     * @dataProvider providesNodes()
17
+     */
18
+    public function testGetContents(string $expected, array $nodeData): void {
19
+        $nodes = [];
20
+        foreach ($nodeData as $data) {
21
+            $nodes[] = $this->buildNode(...$data);
22
+        }
23
+        $stream = AssemblyStream::wrap($nodes);
24
+        $content = stream_get_contents($stream);
25
+
26
+        $this->assertEquals($expected, $content);
27
+    }
28
+
29
+    /**
30
+     * @dataProvider providesNodes()
31
+     */
32
+    public function testGetContentsFread(string $expected, array $nodeData, int $chunkLength = 3): void {
33
+        $nodes = [];
34
+        foreach ($nodeData as $data) {
35
+            $nodes[] = $this->buildNode(...$data);
36
+        }
37
+        $stream = AssemblyStream::wrap($nodes);
38
+
39
+        $content = '';
40
+        while (!feof($stream)) {
41
+            $chunk = fread($stream, $chunkLength);
42
+            $content .= $chunk;
43
+            if ($chunkLength !== 3) {
44
+                $this->assertEquals($chunkLength, strlen($chunk));
45
+            }
46
+        }
47
+
48
+        $this->assertEquals($expected, $content);
49
+    }
50
+
51
+    /**
52
+     * @dataProvider providesNodes()
53
+     */
54
+    public function testSeek(string $expected, array $nodeData): void {
55
+        $nodes = [];
56
+        foreach ($nodeData as $data) {
57
+            $nodes[] = $this->buildNode(...$data);
58
+        }
59
+
60
+        $stream = AssemblyStream::wrap($nodes);
61
+
62
+        $offset = floor(strlen($expected) * 0.6);
63
+        if (fseek($stream, $offset) === -1) {
64
+            $this->fail('fseek failed');
65
+        }
66
+
67
+        $content = stream_get_contents($stream);
68
+        $this->assertEquals(substr($expected, $offset), $content);
69
+    }
70
+
71
+    public static function providesNodes(): array {
72
+        $data8k = self::makeData(8192);
73
+        $dataLess8k = self::makeData(8191);
74
+
75
+        $tonofnodes = [];
76
+        $tonofdata = '';
77
+        for ($i = 0; $i < 101; $i++) {
78
+            $thisdata = random_int(0, 100); // variable length and content
79
+            $tonofdata .= $thisdata;
80
+            $tonofnodes[] = [(string)$i, (string)$thisdata];
81
+        }
82
+
83
+        return[
84
+            'one node zero bytes' => [
85
+                '', [
86
+                    ['0', ''],
87
+                ]],
88
+            'one node only' => [
89
+                '1234567890', [
90
+                    ['0', '1234567890'],
91
+                ]],
92
+            'one node buffer boundary' => [
93
+                $data8k, [
94
+                    ['0', $data8k],
95
+                ]],
96
+            'two nodes' => [
97
+                '1234567890', [
98
+                    ['1', '67890'],
99
+                    ['0', '12345'],
100
+                ]],
101
+            'two nodes end on buffer boundary' => [
102
+                $data8k . $data8k, [
103
+                    ['1', $data8k],
104
+                    ['0', $data8k],
105
+                ]],
106
+            'two nodes with one on buffer boundary' => [
107
+                $data8k . $dataLess8k, [
108
+                    ['1', $dataLess8k],
109
+                    ['0', $data8k],
110
+                ]],
111
+            'two nodes on buffer boundary plus one byte' => [
112
+                $data8k . 'X' . $data8k, [
113
+                    ['1', $data8k],
114
+                    ['0', $data8k . 'X'],
115
+                ]],
116
+            'two nodes on buffer boundary plus one byte at the end' => [
117
+                $data8k . $data8k . 'X', [
118
+                    ['1', $data8k . 'X'],
119
+                    ['0', $data8k],
120
+                ]],
121
+            'a ton of nodes' => [
122
+                $tonofdata, $tonofnodes
123
+            ],
124
+            'one read over multiple nodes' => [
125
+                '1234567890', [
126
+                    ['0', '1234'],
127
+                    ['1', '5678'],
128
+                    ['2', '90'],
129
+                ], 10],
130
+            'two reads over multiple nodes' => [
131
+                '1234567890', [
132
+                    ['0', '1234'],
133
+                    ['1', '5678'],
134
+                    ['2', '90'],
135
+                ], 5],
136
+        ];
137
+    }
138
+
139
+    private static function makeData(int $count): string {
140
+        $data = '';
141
+        $base = '1234567890';
142
+        $j = 0;
143
+        for ($i = 0; $i < $count; $i++) {
144
+            $data .= $base[$j];
145
+            $j++;
146
+            if (!isset($base[$j])) {
147
+                $j = 0;
148
+            }
149
+        }
150
+        return $data;
151
+    }
152
+
153
+    private function buildNode(string $name, string $data) {
154
+        $node = $this->getMockBuilder(File::class)
155
+            ->onlyMethods(['getName', 'get', 'getSize'])
156
+            ->getMock();
157
+
158
+        $node->expects($this->any())
159
+            ->method('getName')
160
+            ->willReturn($name);
161
+
162
+        $node->expects($this->any())
163
+            ->method('get')
164
+            ->willReturn($data);
165
+
166
+        $node->expects($this->any())
167
+            ->method('getSize')
168
+            ->willReturn(strlen($data));
169
+
170
+        return $node;
171
+    }
172 172
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
 		for ($i = 0; $i < 101; $i++) {
78 78
 			$thisdata = random_int(0, 100); // variable length and content
79 79
 			$tonofdata .= $thisdata;
80
-			$tonofnodes[] = [(string)$i, (string)$thisdata];
80
+			$tonofnodes[] = [(string) $i, (string) $thisdata];
81 81
 		}
82 82
 
83 83
 		return[
@@ -99,23 +99,23 @@  discard block
 block discarded – undo
99 99
 					['0', '12345'],
100 100
 				]],
101 101
 			'two nodes end on buffer boundary' => [
102
-				$data8k . $data8k, [
102
+				$data8k.$data8k, [
103 103
 					['1', $data8k],
104 104
 					['0', $data8k],
105 105
 				]],
106 106
 			'two nodes with one on buffer boundary' => [
107
-				$data8k . $dataLess8k, [
107
+				$data8k.$dataLess8k, [
108 108
 					['1', $dataLess8k],
109 109
 					['0', $data8k],
110 110
 				]],
111 111
 			'two nodes on buffer boundary plus one byte' => [
112
-				$data8k . 'X' . $data8k, [
112
+				$data8k.'X'.$data8k, [
113 113
 					['1', $data8k],
114
-					['0', $data8k . 'X'],
114
+					['0', $data8k.'X'],
115 115
 				]],
116 116
 			'two nodes on buffer boundary plus one byte at the end' => [
117
-				$data8k . $data8k . 'X', [
118
-					['1', $data8k . 'X'],
117
+				$data8k.$data8k.'X', [
118
+					['1', $data8k.'X'],
119 119
 					['0', $data8k],
120 120
 				]],
121 121
 			'a ton of nodes' => [
Please login to merge, or discard this patch.