clientService = $this->createMock(IClientService::class);
$this->mapper = $this->createMock(ChangesMapper::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->checker = new ChangesCheck($this->clientService, $this->mapper, $this->logger);
}
public function statusCodeProvider():array {
return [
[200, ChangesCheck::RESPONSE_HAS_CONTENT],
[304, ChangesCheck::RESPONSE_USE_CACHE],
[404, ChangesCheck::RESPONSE_NO_CONTENT],
[418, ChangesCheck::RESPONSE_NO_CONTENT],
];
}
/**
* @dataProvider statusCodeProvider
*/
public function testEvaluateResponse(int $statusCode, int $expected): void {
$response = $this->createMock(IResponse::class);
$response->expects($this->atLeastOnce())
->method('getStatusCode')
->willReturn($statusCode);
if (!in_array($statusCode, [200, 304, 404])) {
$this->logger->expects($this->once())
->method('debug');
}
$evaluation = $this->invokePrivate($this->checker, 'evaluateResponse', [$response]);
$this->assertSame($expected, $evaluation);
}
public function testCacheResultInsert(): void {
$version = '13.0.4';
$entry = $this->createMock(Changes::class);
$entry->expects($this->exactly(2))
->method('__call')
->withConsecutive(['getVersion'], ['setVersion', [$version]])
->willReturnOnConsecutiveCalls('', null);
$this->mapper->expects($this->once())
->method('insert');
$this->mapper->expects($this->never())
->method('update');
$this->invokePrivate($this->checker, 'cacheResult', [$entry, $version]);
}
public function testCacheResultUpdate(): void {
$version = '13.0.4';
$entry = $this->createMock(Changes::class);
$entry->expects($this->once())
->method('__call')
->willReturn($version);
$this->mapper->expects($this->never())
->method('insert');
$this->mapper->expects($this->once())
->method('update');
$this->invokePrivate($this->checker, 'cacheResult', [$entry, $version]);
}
public function changesXMLProvider(): array {
return [
[ # 0 - full example
'
- Refined user interface
- End-to-end Encryption
- Video and Text Chat
- Changes to the Nginx configuration
- Theming: CSS files were consolidated
- Überarbeitete Benutzerschnittstelle
- Ende-zu-Ende Verschlüsselung
- Video- und Text-Chat
- Änderungen an der Nginx Konfiguration
- Theming: CSS Dateien wurden konsolidiert
',
[
'changelogURL' => 'https://nextcloud.com/changelog/#13-0-0',
'whatsNew' => [
'en' => [
'regular' => [
'Refined user interface',
'End-to-end Encryption',
'Video and Text Chat'
],
'admin' => [
'Changes to the Nginx configuration',
'Theming: CSS files were consolidated'
],
],
'de' => [
'regular' => [
'Überarbeitete Benutzerschnittstelle',
'Ende-zu-Ende Verschlüsselung',
'Video- und Text-Chat'
],
'admin' => [
'Änderungen an der Nginx Konfiguration',
'Theming: CSS Dateien wurden konsolidiert'
],
],
],
]
],
[ # 1- admin part not translated
'
- Refined user interface
- End-to-end Encryption
- Video and Text Chat
- Changes to the Nginx configuration
- Theming: CSS files were consolidated
- Überarbeitete Benutzerschnittstelle
- Ende-zu-Ende Verschlüsselung
- Video- und Text-Chat
',
[
'changelogURL' => 'https://nextcloud.com/changelog/#13-0-0',
'whatsNew' => [
'en' => [
'regular' => [
'Refined user interface',
'End-to-end Encryption',
'Video and Text Chat'
],
'admin' => [
'Changes to the Nginx configuration',
'Theming: CSS files were consolidated'
],
],
'de' => [
'regular' => [
'Überarbeitete Benutzerschnittstelle',
'Ende-zu-Ende Verschlüsselung',
'Video- und Text-Chat'
],
'admin' => [
],
],
],
]
],
[ # 2 - minimal set
'
- Refined user interface
- End-to-end Encryption
- Video and Text Chat
',
[
'changelogURL' => 'https://nextcloud.com/changelog/#13-0-0',
'whatsNew' => [
'en' => [
'regular' => [
'Refined user interface',
'End-to-end Encryption',
'Video and Text Chat'
],
'admin' => [],
],
],
]
],
[ # 3 - minimal set (procrastinator edition)
'
- Write this tomorrow
',
[
'changelogURL' => 'https://nextcloud.com/changelog/#13-0-0',
'whatsNew' => [
'en' => [
'regular' => [
'Write this tomorrow',
],
'admin' => [],
],
],
]
],
[ # 4 - empty
'',
[]
],
];
}
/**
* @dataProvider changesXMLProvider
*/
public function testExtractData(string $body, array $expected): void {
$actual = $this->invokePrivate($this->checker, 'extractData', [$body]);
$this->assertSame($expected, $actual);
}
public function etagProvider() {
return [
[''],
['a27aab83d8205d73978435076e53d143']
];
}
/**
* @dataProvider etagProvider
*/
public function testQueryChangesServer(string $etag): void {
$uri = 'https://changes.nextcloud.server/?13.0.5';
$entry = $this->createMock(Changes::class);
$entry->expects($this->any())
->method('__call')
->willReturn($etag);
$expectedHeaders = $etag === '' ? [] : ['If-None-Match' => [$etag]];
$client = $this->createMock(IClient::class);
$client->expects($this->once())
->method('get')
->with($uri, ['headers' => $expectedHeaders])
->willReturn($this->createMock(IResponse::class));
$this->clientService->expects($this->once())
->method('newClient')
->willReturn($client);
$response = $this->invokePrivate($this->checker, 'queryChangesServer', [$uri, $entry]);
$this->assertInstanceOf(IResponse::class, $response);
}
public function versionProvider(): array {
return [
['13.0.7', '13.0.7'],
['13.0.7.3', '13.0.7'],
['13.0.7.3.42', '13.0.7'],
['13.0', '13.0.0'],
['13', '13.0.0'],
['', '0.0.0'],
];
}
/**
* @dataProvider versionProvider
*/
public function testNormalizeVersion(string $input, string $expected): void {
$normalized = $this->checker->normalizeVersion($input);
$this->assertSame($expected, $normalized);
}
public function changeDataProvider():array {
$testDataFound = $testDataNotFound = $this->versionProvider();
array_walk($testDataFound, function (&$params) {
$params[] = true;
});
array_walk($testDataNotFound, function (&$params) {
$params[] = false;
});
return array_merge($testDataFound, $testDataNotFound);
}
/**
* @dataProvider changeDataProvider
*
*/
public function testGetChangesForVersion(string $inputVersion, string $normalizedVersion, bool $isFound): void {
$mocker = $this->mapper->expects($this->once())
->method('getChanges')
->with($normalizedVersion);
if (!$isFound) {
$this->expectException(DoesNotExistException::class);
$mocker->willThrowException(new DoesNotExistException('Changes info is not present'));
} else {
$entry = $this->createMock(Changes::class);
$entry->expects($this->once())
->method('__call')
->with('getData')
->willReturn('{"changelogURL":"https:\/\/nextcloud.com\/changelog\/#13-0-0","whatsNew":{"en":{"regular":["Refined user interface","End-to-end Encryption","Video and Text Chat"],"admin":["Changes to the Nginx configuration","Theming: CSS files were consolidated"]},"de":{"regular":["\u00dcberarbeitete Benutzerschnittstelle","Ende-zu-Ende Verschl\u00fcsselung","Video- und Text-Chat"],"admin":["\u00c4nderungen an der Nginx Konfiguration","Theming: CSS Dateien wurden konsolidiert"]}}}');
$mocker->willReturn($entry);
}
/** @noinspection PhpUnhandledExceptionInspection */
$data = $this->checker->getChangesForVersion($inputVersion);
$this->assertTrue(isset($data['whatsNew']['en']['regular']));
$this->assertTrue(isset($data['changelogURL']));
}
public function testGetChangesForVersionEmptyData(): void {
$entry = $this->createMock(Changes::class);
$entry->expects($this->once())
->method('__call')
->with('getData')
->willReturn('');
$this->mapper->expects($this->once())
->method('getChanges')
->with('13.0.7')
->willReturn($entry);
$this->expectException(DoesNotExistException::class);
/** @noinspection PhpUnhandledExceptionInspection */
$this->checker->getChangesForVersion('13.0.7');
}
}