mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 00:30:02 +00:00
Release 1.3.2 (#74)
* Fixes #71 * [GH-61] Fix manual mapping leading to duplicates in DB * [GH-73] Fix Gameyfin only detecting PC games * Improve game title matching (#77) * Implement some filename suffix logic Removes some common file suffixes from files downloaded from for example itch.io. Also removes trailing/leading whitespace/-/_/./() and version numbers starting with a "v" like "v1.2.3". * Add edge cases for game titles (#76) * Fix SONAR code smells Co-authored-by: tr7zw <tr7zw@live.de> Co-authored-by: Pfuenzle <dark.leon64@gmail.com> * Validate some combinations of filename with added suffixes (#79) Also fixes a bug of not removing trailing empty []. * Improve test coverage (#70) * Implemented missing testcases for IgdbWrapper Refactored getPlatformBySlug to return Optional<> * Fixed SONAR findings * Implemented integration tests for the DB * Started implementing tests for controller * Finished GamesControllerTest * Added ImageControllerTest * Implemented LibraryControllerTest * Add LibraryManagementControllerTest * Updated some dependencies * Add DownloadServiceTest * Introduced "gameyfin.data" property to specify a folder for both cache and DB. De-facto removed "gameyfin.db" and "gameyfin.cache" properties Refactored file-system code to be cleaner and easier to test * Refactored filesystem code Implemented FilesystemServiceTest * Fix SONAR code smells * Implemented GameServiceTest * Implemented ImageServiceTest * Fix website scroll position when clicking on game covers in the library view (#94) Fixes #81 * Expansion panels are now not collapsing when last active filter is de-selected (#95) Fixes #86 --------- Co-authored-by: tr7zw <tr7zw@live.de> Co-authored-by: Pfuenzle <dark.leon64@gmail.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import com.google.protobuf.Timestamp;
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.config.WebClientConfig;
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
import de.grimsi.gameyfin.entities.Platform;
|
||||
import de.grimsi.gameyfin.igdb.dto.TwitchOAuthTokenDto;
|
||||
import de.grimsi.gameyfin.mapper.GameMapper;
|
||||
import io.github.resilience4j.bulkhead.Bulkhead;
|
||||
@@ -32,6 +33,7 @@ import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static de.grimsi.gameyfin.igdb.IgdbApiQueryBuilder.equal;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -298,6 +300,67 @@ class IgdbWrapperTest {
|
||||
assertThat(r2.getBody().readUtf8()).isEqualTo(r2_expectedQuery);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findPlatforms() throws InterruptedException {
|
||||
Igdb.PlatformResult platformResult = Igdb.PlatformResult.newBuilder()
|
||||
.addAllPlatforms(List.of(
|
||||
Igdb.Platform.newBuilder().setSlug("platform_1").setName("Platform 1").build(),
|
||||
Igdb.Platform.newBuilder().setSlug("platform_2").setName("Platform 2").build(),
|
||||
Igdb.Platform.newBuilder().setSlug("platform_3").setName("Platform 3").build()))
|
||||
.build();
|
||||
|
||||
String searchTerm = platformResult.getPlatforms(0).getSlug();
|
||||
int limit = 10;
|
||||
|
||||
igdbApiMock.enqueue(new MockResponse()
|
||||
.setBody(toBuffer(platformResult))
|
||||
.setHeader("Content-Type", "application/protobuf")
|
||||
);
|
||||
|
||||
List<Platform> result = target.findPlatforms(searchTerm, limit);
|
||||
|
||||
assertThat(result.get(0).getSlug()).isEqualTo(searchTerm);
|
||||
|
||||
RecordedRequest r = igdbApiMock.takeRequest();
|
||||
assertThat(r.getRequestUrl()).isNotNull();
|
||||
assertThat(r.getRequestUrl().encodedPath()).isEqualTo("/%s".formatted(IgdbApiProperties.ENDPOINT_PLATFORMS_PROTOBUF));
|
||||
|
||||
String expectedQuery = "search \"%s\";fields slug,name;limit %s;".formatted(searchTerm, limit);
|
||||
|
||||
assertThat(r.getBody().readUtf8()).isEqualTo(expectedQuery);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPlatformBySlug() throws InterruptedException {
|
||||
Igdb.PlatformResult platformResult = Igdb.PlatformResult.newBuilder()
|
||||
.addAllPlatforms(List.of(
|
||||
Igdb.Platform.newBuilder().setSlug("platform_1").setName("Platform 1").build()))
|
||||
.build();
|
||||
|
||||
String slug = platformResult.getPlatforms(0).getSlug();
|
||||
|
||||
igdbApiMock.enqueue(new MockResponse()
|
||||
.setBody(toBuffer(platformResult))
|
||||
.setHeader("Content-Type", "application/protobuf")
|
||||
);
|
||||
|
||||
Optional<Platform> result = target.getPlatformBySlug(slug);
|
||||
|
||||
assertThat(result).isPresent();
|
||||
|
||||
Platform platform = result.get();
|
||||
|
||||
assertThat(platform.getSlug()).isEqualTo(slug);
|
||||
|
||||
RecordedRequest r = igdbApiMock.takeRequest();
|
||||
assertThat(r.getRequestUrl()).isNotNull();
|
||||
assertThat(r.getRequestUrl().encodedPath()).isEqualTo("/%s".formatted(IgdbApiProperties.ENDPOINT_PLATFORMS_PROTOBUF));
|
||||
|
||||
String expectedQuery = "fields slug,name,platform_logo;where slug = \"%s\";".formatted(slug);
|
||||
|
||||
assertThat(r.getBody().readUtf8()).isEqualTo(expectedQuery);
|
||||
}
|
||||
|
||||
private static Buffer toBuffer(Message input) {
|
||||
Buffer b = new Buffer();
|
||||
b.write(input.toByteArray());
|
||||
|
||||
@@ -13,7 +13,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class CompanyMapperTest extends RandomMapperTest<Igdb.InvolvedCompany, Company> {
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void toCompany() {
|
||||
Igdb.InvolvedCompany input = generateRandomInput();
|
||||
|
||||
@@ -25,7 +24,6 @@ class CompanyMapperTest extends RandomMapperTest<Igdb.InvolvedCompany, Company>
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void toCompanies() {
|
||||
List<Igdb.InvolvedCompany> input = List.of(generateRandomInput(), generateRandomInput(), generateRandomInput());
|
||||
|
||||
@@ -37,18 +35,4 @@ class CompanyMapperTest extends RandomMapperTest<Igdb.InvolvedCompany, Company>
|
||||
assertThat(output.get(i).getLogoId()).isEqualTo(input.get(i).getCompany().getLogo().getImageId());
|
||||
}
|
||||
}
|
||||
|
||||
private static Igdb.InvolvedCompany generateRandomInvolvedCompany() {
|
||||
Igdb.Company c = Igdb.Company.newBuilder()
|
||||
.setSlug(UUID.randomUUID().toString())
|
||||
.setName(UUID.randomUUID().toString())
|
||||
.setLogo(Igdb.CompanyLogo.newBuilder()
|
||||
.setImageId(UUID.randomUUID().toString())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
return Igdb.InvolvedCompany.newBuilder()
|
||||
.setCompany(c)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class GenreMapperTest extends RandomMapperTest<Igdb.Genre, Genre> {
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void toGenre() {
|
||||
Igdb.Genre input = generateRandomInput();
|
||||
|
||||
@@ -23,7 +22,6 @@ class GenreMapperTest extends RandomMapperTest<Igdb.Genre, Genre> {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void toGenres() {
|
||||
List<Igdb.Genre> input = List.of(generateRandomInput(), generateRandomInput(), generateRandomInput());
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
public class RandomMapperTest<Input extends Message, Output> {
|
||||
|
||||
private static final int DEFAULT_COUNT = 5;
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
protected final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
private final Class<Input> inputClass;
|
||||
private final Class<Output> outputClass;
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package de.grimsi.gameyfin.repositories;
|
||||
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.service.FilesystemService;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest
|
||||
class DetectedGameRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private DetectedGameRepository target;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@BeforeEach
|
||||
void dropTable() {
|
||||
target.deleteAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsByPath() {
|
||||
String path = "some/random/path";
|
||||
DetectedGame input = DetectedGame.builder()
|
||||
.slug("slug")
|
||||
.title("title")
|
||||
.coverId("coverId")
|
||||
.path(path)
|
||||
.build();
|
||||
|
||||
assertThat(target.existsByPath(path)).isFalse();
|
||||
|
||||
target.save(input);
|
||||
|
||||
assertThat(target.existsByPath(path)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsBySlug() {
|
||||
String slug = "some-random-slug";
|
||||
DetectedGame input = DetectedGame.builder()
|
||||
.slug(slug)
|
||||
.title("title")
|
||||
.coverId("coverId")
|
||||
.path("path")
|
||||
.build();
|
||||
|
||||
assertThat(target.existsBySlug(slug)).isFalse();
|
||||
|
||||
target.save(input);
|
||||
|
||||
assertThat(target.existsBySlug(slug)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByPath() {
|
||||
String path = "some/random/path";
|
||||
DetectedGame input = DetectedGame.builder()
|
||||
.slug("slug")
|
||||
.title("title")
|
||||
.coverId("coverId")
|
||||
.path(path)
|
||||
.build();
|
||||
|
||||
assertThat(target.findByPath(path)).isEmpty();
|
||||
|
||||
target.save(input);
|
||||
|
||||
Optional<DetectedGame> optionalResult = target.findByPath(path);
|
||||
|
||||
assertThat(optionalResult).isPresent();
|
||||
|
||||
DetectedGame result = optionalResult.get();
|
||||
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"", "some/random/library/path/"})
|
||||
void getAllByPathNotInAndPathStartsWith(String library) {
|
||||
String libraryPath = Path.of(library).toString();
|
||||
String otherLibraryPath = Path.of("another/random/library/path/").toString();
|
||||
|
||||
List<DetectedGame> detectedGames = easyRandom.objects(DetectedGame.class, 2).peek(g -> g.setPath(Path.of(libraryPath, g.getPath()).toString())).toList();
|
||||
List<DetectedGame> detectedGamesDifferentLibrary = easyRandom.objects(DetectedGame.class, 2).peek(g -> g.setPath(Path.of(otherLibraryPath, g.getPath()).toString())).toList();
|
||||
List<DetectedGame> deletedGames = easyRandom.objects(DetectedGame.class, 2).peek(g -> g.setPath(Path.of(libraryPath, g.getPath()).toString())).toList();
|
||||
List<Path> gamePaths = detectedGames.stream().map(DetectedGame::getPath).map(Path::of).collect(Collectors.toList());
|
||||
gamePaths.addAll(detectedGamesDifferentLibrary.stream().map(DetectedGame::getPath).map(Path::of).toList());
|
||||
|
||||
target.saveAll(detectedGames);
|
||||
target.saveAll(detectedGamesDifferentLibrary);
|
||||
|
||||
assertThat(target.getAllByPathNotInAndPathStartsWith(gamePaths, libraryPath)).isEmpty();
|
||||
|
||||
target.saveAll(deletedGames);
|
||||
|
||||
List<DetectedGame> result = target.getAllByPathNotInAndPathStartsWith(gamePaths, libraryPath);
|
||||
assertThat(result)
|
||||
.hasSize(2)
|
||||
.containsOnlyOnceElementsOf(deletedGames);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.grimsi.gameyfin.repositories;
|
||||
|
||||
import de.grimsi.gameyfin.entities.Library;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest
|
||||
class LibraryRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private LibraryRepository target;
|
||||
|
||||
@Test
|
||||
void existsByPathIgnoreCase() {
|
||||
String path = "Some/Random/Path";
|
||||
Library input = Library.builder().path(path).build();
|
||||
|
||||
assertThat(target.existsByPathIgnoreCase(path)).isFalse();
|
||||
|
||||
target.save(input);
|
||||
|
||||
assertThat(target.existsByPathIgnoreCase(path)).isTrue();
|
||||
assertThat(target.existsByPathIgnoreCase(path.toLowerCase(Locale.ENGLISH))).isTrue();
|
||||
assertThat(target.existsByPathIgnoreCase(path.toUpperCase(Locale.ENGLISH))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByPath() {
|
||||
String path = "Some/Random/Path";
|
||||
Library input = Library.builder().path(path).build();
|
||||
|
||||
target.save(input);
|
||||
|
||||
Optional<Library> optionalResult = target.findByPath(path);
|
||||
|
||||
assertThat(optionalResult).isPresent();
|
||||
|
||||
Library result = optionalResult.get();
|
||||
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package de.grimsi.gameyfin.repositories;
|
||||
|
||||
import de.grimsi.gameyfin.entities.UnmappableFile;
|
||||
import de.grimsi.gameyfin.service.FilesystemService;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest
|
||||
class UnmappableFileRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private UnmappableFileRepository target;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@BeforeEach
|
||||
void dropTable() {
|
||||
target.deleteAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsByPath() {
|
||||
String path = "some/random/path";
|
||||
UnmappableFile input = new UnmappableFile(path);
|
||||
|
||||
assertThat(target.existsByPath(path)).isFalse();
|
||||
|
||||
target.save(input);
|
||||
|
||||
assertThat(target.existsByPath(path)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByPath() {
|
||||
String path = "some/random/path";
|
||||
UnmappableFile input = new UnmappableFile(path);
|
||||
|
||||
assertThat(target.findByPath(path)).isEmpty();
|
||||
|
||||
target.save(input);
|
||||
|
||||
Optional<UnmappableFile> optionalResult = target.findByPath(path);
|
||||
|
||||
assertThat(optionalResult).isPresent();
|
||||
|
||||
UnmappableFile result = optionalResult.get();
|
||||
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"", "some/random/library/path/"})
|
||||
void getAllByPathNotInAndPathStartsWith(String library) {
|
||||
String libraryPath = Path.of(library).toString();
|
||||
String otherLibraryPath = Path.of("another/random/library/path/").toString();
|
||||
|
||||
List<UnmappableFile> UnmappableFiles = easyRandom.objects(UnmappableFile.class, 2).peek(g -> g.setPath(Path.of(libraryPath, g.getPath()).toString())).toList();
|
||||
List<UnmappableFile> UnmappableFilesDifferentLibrary = easyRandom.objects(UnmappableFile.class, 2).peek(g -> g.setPath(Path.of(otherLibraryPath, g.getPath()).toString())).toList();
|
||||
List<UnmappableFile> deletedGames = easyRandom.objects(UnmappableFile.class, 2).peek(g -> g.setPath(Path.of(libraryPath, g.getPath()).toString())).toList();
|
||||
List<Path> gamePaths = UnmappableFiles.stream().map(UnmappableFile::getPath).map(Path::of).collect(Collectors.toList());
|
||||
gamePaths.addAll(UnmappableFilesDifferentLibrary.stream().map(UnmappableFile::getPath).map(Path::of).toList());
|
||||
|
||||
target.saveAll(UnmappableFiles);
|
||||
target.saveAll(UnmappableFilesDifferentLibrary);
|
||||
|
||||
assertThat(target.getAllByPathNotInAndPathStartsWith(gamePaths, libraryPath)).isEmpty();
|
||||
|
||||
target.saveAll(deletedGames);
|
||||
|
||||
List<UnmappableFile> result = target.getAllByPathNotInAndPathStartsWith(gamePaths, libraryPath);
|
||||
assertThat(result)
|
||||
.hasSize(2)
|
||||
.containsOnlyOnceElementsOf(deletedGames);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
import de.grimsi.gameyfin.dto.GameOverviewDto;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.service.DownloadService;
|
||||
import de.grimsi.gameyfin.service.GameService;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.in;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class GamesControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private GamesController target;
|
||||
|
||||
@Mock
|
||||
private GameService gameServiceMock;
|
||||
|
||||
@Mock
|
||||
private DownloadService downloadServiceMock;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@Test
|
||||
void getAllGames() {
|
||||
List<DetectedGame> input = easyRandom.objects(DetectedGame.class, 5).toList();
|
||||
|
||||
when(gameServiceMock.getAllDetectedGames()).thenReturn(input);
|
||||
|
||||
List<DetectedGame> result = target.getAllGames();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllDetectedGames();
|
||||
assertThat(result).hasSameElementsAs(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGame() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
String slug = input.getSlug();
|
||||
|
||||
when(gameServiceMock.getDetectedGame(slug)).thenReturn(input);
|
||||
|
||||
DetectedGame result = target.getGame(slug);
|
||||
|
||||
verify(gameServiceMock, times(1)).getDetectedGame(slug);
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGameOverviews() {
|
||||
List<GameOverviewDto> input = easyRandom.objects(GameOverviewDto.class, 5).toList();
|
||||
|
||||
when(gameServiceMock.getGameOverviews()).thenReturn(input);
|
||||
|
||||
List<GameOverviewDto> result = target.getGameOverviews();
|
||||
|
||||
verify(gameServiceMock, times(1)).getGameOverviews();
|
||||
assertThat(result).hasSameElementsAs(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGameMappings() {
|
||||
Map<String, String> input = easyRandom.objects(String.class, 5).collect(Collectors.toMap(String::toLowerCase, String::toUpperCase));
|
||||
|
||||
when(gameServiceMock.getAllMappings()).thenReturn(input);
|
||||
|
||||
Map<String, String> result = target.getGameMappings();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllMappings();
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadGameFiles_File() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
String slug = input.getSlug();
|
||||
String downloadFilename = input.getSlug();
|
||||
long downloadFileSize = 1337L;
|
||||
|
||||
when(gameServiceMock.getDetectedGame(slug)).thenReturn(input);
|
||||
when(downloadServiceMock.getDownloadFileName(input)).thenReturn(downloadFilename);
|
||||
when(downloadServiceMock.getDownloadFileSize(input)).thenReturn(downloadFileSize);
|
||||
|
||||
ResponseEntity<StreamingResponseBody> result = target.downloadGameFiles(slug);
|
||||
|
||||
HttpHeaders expectedHeaders = new HttpHeaders();
|
||||
expectedHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"%s\"".formatted(downloadFilename));
|
||||
expectedHeaders.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
|
||||
expectedHeaders.add(HttpHeaders.PRAGMA, "no-cache");
|
||||
expectedHeaders.add(HttpHeaders.EXPIRES, "0");
|
||||
expectedHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
expectedHeaders.setContentLength(downloadFileSize);
|
||||
|
||||
verify(gameServiceMock, times(1)).getDetectedGame(slug);
|
||||
verify(downloadServiceMock, times(1)).getDownloadFileName(input);
|
||||
verify(downloadServiceMock, times(1)).getDownloadFileSize(input);
|
||||
assertThat(result.getHeaders()).isEqualTo(expectedHeaders);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadGameFiles_Zip() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
String slug = input.getSlug();
|
||||
String downloadFilename = input.getSlug() + ".zip";
|
||||
long downloadFileSize = 0L;
|
||||
|
||||
when(gameServiceMock.getDetectedGame(slug)).thenReturn(input);
|
||||
when(downloadServiceMock.getDownloadFileName(input)).thenReturn(downloadFilename);
|
||||
when(downloadServiceMock.getDownloadFileSize(input)).thenReturn(downloadFileSize);
|
||||
|
||||
ResponseEntity<StreamingResponseBody> result = target.downloadGameFiles(slug);
|
||||
|
||||
HttpHeaders expectedHeaders = new HttpHeaders();
|
||||
expectedHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"%s\"".formatted(downloadFilename));
|
||||
expectedHeaders.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
|
||||
expectedHeaders.add(HttpHeaders.PRAGMA, "no-cache");
|
||||
expectedHeaders.add(HttpHeaders.EXPIRES, "0");
|
||||
expectedHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
|
||||
verify(gameServiceMock, times(1)).getDetectedGame(slug);
|
||||
verify(downloadServiceMock, times(1)).getDownloadFileName(input);
|
||||
verify(downloadServiceMock, times(1)).getDownloadFileSize(input);
|
||||
assertThat(result.getHeaders()).isEqualTo(expectedHeaders);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshGame() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
String slug = input.getSlug();
|
||||
|
||||
when(gameServiceMock.refreshGame(slug)).thenReturn(input);
|
||||
|
||||
DetectedGame result = target.refreshGame(slug);
|
||||
|
||||
verify(gameServiceMock, times(1)).refreshGame(slug);
|
||||
assertThat(result).isEqualTo(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
import de.grimsi.gameyfin.service.DownloadService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.in;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static reactor.core.publisher.Mono.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ImageControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private ImageController target;
|
||||
|
||||
@Mock
|
||||
private DownloadService downloadServiceMock;
|
||||
|
||||
@Test
|
||||
void getImage() {
|
||||
byte[] content = "content".getBytes();
|
||||
Resource resource = new ByteArrayResource(content);
|
||||
String input = "imageId";
|
||||
|
||||
doReturn(resource).when(downloadServiceMock).sendImageToClient(input);
|
||||
|
||||
ResponseEntity<Resource> result = target.getImage(input);
|
||||
|
||||
verify(downloadServiceMock, times(1)).sendImageToClient(input);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo(resource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
import de.grimsi.gameyfin.dto.ImageDownloadResultDto;
|
||||
import de.grimsi.gameyfin.dto.LibraryScanRequestDto;
|
||||
import de.grimsi.gameyfin.dto.LibraryScanResult;
|
||||
import de.grimsi.gameyfin.dto.LibraryScanResultDto;
|
||||
import de.grimsi.gameyfin.entities.Library;
|
||||
import de.grimsi.gameyfin.service.ImageService;
|
||||
import de.grimsi.gameyfin.service.LibraryService;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LibraryControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private LibraryController target;
|
||||
|
||||
@Mock
|
||||
private LibraryService libraryServiceMock;
|
||||
|
||||
@Mock
|
||||
private ImageService imageServiceMock;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@Test
|
||||
void scanLibraries_All_NoImages() {
|
||||
int libraryCount = 5;
|
||||
LibraryScanRequestDto input = new LibraryScanRequestDto("", false);
|
||||
List<Library> libraries = easyRandom.objects(Library.class, libraryCount).toList();
|
||||
LibraryScanResult lsr = easyRandom.nextObject(LibraryScanResult.class);
|
||||
|
||||
when(libraryServiceMock.getLibraries()).thenReturn(libraries);
|
||||
when(libraryServiceMock.scanGameLibrary(any(Library.class))).thenReturn(lsr);
|
||||
|
||||
LibraryScanResultDto result = target.scanLibraries(input);
|
||||
|
||||
verify(libraryServiceMock, times(1)).getLibraries();
|
||||
verify(libraryServiceMock, never()).getLibrary(any(String.class));
|
||||
verify(libraryServiceMock, times(libraryCount)).scanGameLibrary(any(Library.class));
|
||||
verify(imageServiceMock, never()).downloadCompanyLogosFromIgdb();
|
||||
verify(imageServiceMock, never()).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, never()).downloadGameScreenshotsFromIgdb();
|
||||
assertThat(result.getNewGames()).isEqualTo(lsr.getNewGames() * libraries.size());
|
||||
assertThat(result.getDeletedGames()).isEqualTo(lsr.getDeletedGames() * libraries.size());
|
||||
assertThat(result.getNewUnmappableFiles()).isEqualTo(lsr.getNewUnmappableFiles() * libraries.size());
|
||||
assertThat(result.getTotalGames()).isEqualTo(lsr.getTotalGames() * libraries.size());
|
||||
assertThat(result.getCoverDownloads()).isZero();
|
||||
assertThat(result.getScreenshotDownloads()).isZero();
|
||||
assertThat(result.getCompanyLogoDownloads()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void scanLibraries_Single_NoImages() {
|
||||
String libraryPath = "some/random/path";
|
||||
LibraryScanRequestDto input = new LibraryScanRequestDto(libraryPath, false);
|
||||
Library library = easyRandom.nextObject(Library.class);
|
||||
LibraryScanResult lsr = easyRandom.nextObject(LibraryScanResult.class);
|
||||
|
||||
when(libraryServiceMock.getLibrary(libraryPath)).thenReturn(library);
|
||||
when(libraryServiceMock.scanGameLibrary(any(Library.class))).thenReturn(lsr);
|
||||
|
||||
LibraryScanResultDto result = target.scanLibraries(input);
|
||||
|
||||
verify(libraryServiceMock, never()).getLibraries();
|
||||
verify(libraryServiceMock, times(1)).getLibrary(libraryPath);
|
||||
verify(libraryServiceMock, times(1)).scanGameLibrary(any(Library.class));
|
||||
verify(imageServiceMock, never()).downloadCompanyLogosFromIgdb();
|
||||
verify(imageServiceMock, never()).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, never()).downloadGameScreenshotsFromIgdb();
|
||||
assertThat(result.getNewGames()).isEqualTo(lsr.getNewGames());
|
||||
assertThat(result.getDeletedGames()).isEqualTo(lsr.getDeletedGames());
|
||||
assertThat(result.getNewUnmappableFiles()).isEqualTo(lsr.getNewUnmappableFiles());
|
||||
assertThat(result.getTotalGames()).isEqualTo(lsr.getTotalGames());
|
||||
assertThat(result.getCoverDownloads()).isZero();
|
||||
assertThat(result.getScreenshotDownloads()).isZero();
|
||||
assertThat(result.getCompanyLogoDownloads()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void scanLibraries_All_DownloadImages() {
|
||||
int libraryCount = 5;
|
||||
LibraryScanRequestDto input = new LibraryScanRequestDto("", true);
|
||||
List<Library> libraries = easyRandom.objects(Library.class, libraryCount).toList();
|
||||
LibraryScanResult lsr = easyRandom.nextObject(LibraryScanResult.class);
|
||||
|
||||
when(libraryServiceMock.getLibraries()).thenReturn(libraries);
|
||||
when(libraryServiceMock.scanGameLibrary(any(Library.class))).thenReturn(lsr);
|
||||
when(imageServiceMock.downloadGameCoversFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadGameScreenshotsFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadCompanyLogosFromIgdb()).thenReturn(1);
|
||||
|
||||
LibraryScanResultDto result = target.scanLibraries(input);
|
||||
|
||||
verify(libraryServiceMock, times(1)).getLibraries();
|
||||
verify(libraryServiceMock, never()).getLibrary(any(String.class));
|
||||
verify(libraryServiceMock, times(libraryCount)).scanGameLibrary(any(Library.class));
|
||||
verify(imageServiceMock, times(1)).downloadCompanyLogosFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameScreenshotsFromIgdb();
|
||||
assertThat(result.getNewGames()).isEqualTo(lsr.getNewGames() * libraries.size());
|
||||
assertThat(result.getDeletedGames()).isEqualTo(lsr.getDeletedGames() * libraries.size());
|
||||
assertThat(result.getNewUnmappableFiles()).isEqualTo(lsr.getNewUnmappableFiles() * libraries.size());
|
||||
assertThat(result.getTotalGames()).isEqualTo(lsr.getTotalGames() * libraries.size());
|
||||
assertThat(result.getCoverDownloads()).isEqualTo(1);
|
||||
assertThat(result.getScreenshotDownloads()).isEqualTo(1);
|
||||
assertThat(result.getCompanyLogoDownloads()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void scanLibraries_Single_DownloadImages() {
|
||||
String libraryPath = "some/random/path";
|
||||
LibraryScanRequestDto input = new LibraryScanRequestDto(libraryPath, true);
|
||||
Library library = easyRandom.nextObject(Library.class);
|
||||
LibraryScanResult lsr = easyRandom.nextObject(LibraryScanResult.class);
|
||||
|
||||
when(libraryServiceMock.getLibrary(libraryPath)).thenReturn(library);
|
||||
when(libraryServiceMock.scanGameLibrary(any(Library.class))).thenReturn(lsr);
|
||||
when(imageServiceMock.downloadGameCoversFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadGameScreenshotsFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadCompanyLogosFromIgdb()).thenReturn(1);
|
||||
|
||||
LibraryScanResultDto result = target.scanLibraries(input);
|
||||
|
||||
verify(libraryServiceMock, never()).getLibraries();
|
||||
verify(libraryServiceMock, times(1)).getLibrary(libraryPath);
|
||||
verify(libraryServiceMock, times(1)).scanGameLibrary(any(Library.class));
|
||||
verify(imageServiceMock, times(1)).downloadCompanyLogosFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameScreenshotsFromIgdb();
|
||||
assertThat(result.getNewGames()).isEqualTo(lsr.getNewGames());
|
||||
assertThat(result.getDeletedGames()).isEqualTo(lsr.getDeletedGames());
|
||||
assertThat(result.getNewUnmappableFiles()).isEqualTo(lsr.getNewUnmappableFiles());
|
||||
assertThat(result.getTotalGames()).isEqualTo(lsr.getTotalGames());
|
||||
assertThat(result.getCoverDownloads()).isEqualTo(1);
|
||||
assertThat(result.getScreenshotDownloads()).isEqualTo(1);
|
||||
assertThat(result.getCompanyLogoDownloads()).isEqualTo(1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void downloadImages() {
|
||||
when(imageServiceMock.downloadGameCoversFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadGameScreenshotsFromIgdb()).thenReturn(1);
|
||||
when(imageServiceMock.downloadCompanyLogosFromIgdb()).thenReturn(1);
|
||||
|
||||
ImageDownloadResultDto result = target.downloadImages();
|
||||
|
||||
verify(imageServiceMock, times(1)).downloadCompanyLogosFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameScreenshotsFromIgdb();
|
||||
assertThat(result.getScreenshotDownloads()).isOne();
|
||||
assertThat(result.getCoverDownloads()).isOne();
|
||||
assertThat(result.getCompanyLogoDownloads()).isOne();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllFiles() {
|
||||
List<Path> gameFiles = easyRandom.objects(String.class, 5).map(Path::of).toList();
|
||||
|
||||
when(libraryServiceMock.getGameFiles()).thenReturn(gameFiles);
|
||||
|
||||
List<String> result = target.getAllFiles();
|
||||
|
||||
verify(libraryServiceMock, times(1)).getGameFiles();
|
||||
assertThat(result).hasSameElementsAs(gameFiles.stream().map(Path::toString).toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
import de.grimsi.gameyfin.dto.PathToSlugDto;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.entities.Library;
|
||||
import de.grimsi.gameyfin.entities.Platform;
|
||||
import de.grimsi.gameyfin.service.GameService;
|
||||
import de.grimsi.gameyfin.service.ImageService;
|
||||
import de.grimsi.gameyfin.service.LibraryService;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LibraryManagementControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private LibraryManagementController target;
|
||||
|
||||
@Mock
|
||||
private GameService gameServiceMock;
|
||||
|
||||
@Mock
|
||||
private ImageService imageServiceMock;
|
||||
|
||||
@Mock
|
||||
private LibraryService libraryServiceMock;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@Test
|
||||
void deleteGame() {
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
|
||||
target.deleteGame(slug);
|
||||
|
||||
verify(gameServiceMock, times(1)).deleteGame(slug);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteUnmappedFile() {
|
||||
Long id = easyRandom.nextLong();
|
||||
|
||||
target.deleteUnmappedFile(id);
|
||||
|
||||
verify(gameServiceMock, times(1)).deleteUnmappedFile(id);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void confirmMatch(boolean confirm) {
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
|
||||
target.confirmMatch(slug, confirm);
|
||||
|
||||
verify(gameServiceMock, times(1)).confirmGame(slug, confirm);
|
||||
}
|
||||
|
||||
@Test
|
||||
void manuallyMapPathToSlug() {
|
||||
PathToSlugDto input = easyRandom.nextObject(PathToSlugDto.class);
|
||||
DetectedGame game = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
when(gameServiceMock.mapPathToGame(input.getPath(), input.getSlug())).thenReturn(game);
|
||||
|
||||
DetectedGame result = target.manuallyMapPathToSlug(input);
|
||||
|
||||
verify(gameServiceMock, times(1)).mapPathToGame(input.getPath(), input.getSlug());
|
||||
verify(imageServiceMock, times(1)).downloadGameScreenshotsFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadGameCoversFromIgdb();
|
||||
verify(imageServiceMock, times(1)).downloadCompanyLogosFromIgdb();
|
||||
|
||||
assertThat(result).isEqualTo(game);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUnmappedFiles() {
|
||||
target.getUnmappedFiles();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllUnmappedFiles();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAutocompleteSuggestions() {
|
||||
String searchTerm = easyRandom.nextObject(String.class);
|
||||
int limit = 10;
|
||||
List<AutocompleteSuggestionDto> a = easyRandom.objects(AutocompleteSuggestionDto.class, limit).toList();
|
||||
|
||||
when(libraryServiceMock.getAutocompleteSuggestions(searchTerm, limit)).thenReturn(a);
|
||||
|
||||
List<AutocompleteSuggestionDto> result = target.getAutocompleteSuggestions(searchTerm, limit);
|
||||
|
||||
verify(libraryServiceMock, times(1)).getAutocompleteSuggestions(searchTerm, limit);
|
||||
assertThat(result).isEqualTo(a);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPlatforms() {
|
||||
String searchTerm = easyRandom.nextObject(String.class);
|
||||
int limit = 10;
|
||||
List<Platform> p = easyRandom.objects(Platform.class, limit).toList();
|
||||
|
||||
when(libraryServiceMock.getPlatforms(searchTerm, limit)).thenReturn(p);
|
||||
|
||||
List<Platform> result = target.getPlatforms(searchTerm, limit);
|
||||
|
||||
verify(libraryServiceMock, times(1)).getPlatforms(searchTerm, limit);
|
||||
assertThat(result).isEqualTo(p);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLibraries() {
|
||||
target.getLibraries();
|
||||
|
||||
verify(libraryServiceMock, times(1)).getOrCreateLibraries();
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapPathToPlatform() {
|
||||
PathToSlugDto input = easyRandom.nextObject(PathToSlugDto.class);
|
||||
Library l = easyRandom.nextObject(Library.class);
|
||||
|
||||
when(libraryServiceMock.mapPlatformsToLibrary(input.getPath(), input.getSlug())).thenReturn(l);
|
||||
|
||||
Library result = target.mapPathToPlatform(input);
|
||||
|
||||
verify(libraryServiceMock, times(1)).mapPlatformsToLibrary(input.getPath(), input.getSlug());
|
||||
assertThat(result).isEqualTo(l);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DownloadServiceTest {
|
||||
|
||||
@Mock
|
||||
private FilesystemService filesystemServiceMock;
|
||||
|
||||
@InjectMocks
|
||||
private DownloadService target;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@Test
|
||||
void getDownloadFileName_File() {
|
||||
try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
filesMock.when(() -> Files.isDirectory(any())).thenReturn(false);
|
||||
when(filesystemServiceMock.getPath(any())).thenReturn(Path.of(input.getPath()));
|
||||
|
||||
String result = target.getDownloadFileName(input);
|
||||
|
||||
assertThat(result).isEqualTo(input.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDownloadFileName_Folder() {
|
||||
try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
|
||||
filesMock.when(() -> Files.isDirectory(any())).thenReturn(true);
|
||||
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
when(filesystemServiceMock.getPath(any())).thenReturn(Path.of(input.getPath()));
|
||||
|
||||
String result = target.getDownloadFileName(input);
|
||||
|
||||
assertThat(result).isEqualTo("%s.zip".formatted(input.getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDownloadFileSize_File() throws IOException {
|
||||
try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
|
||||
filesMock.when(() -> Files.isDirectory(any())).thenReturn(false);
|
||||
when(filesystemServiceMock.getSizeOnDisk(any())).thenReturn(1337L);
|
||||
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
Long result = target.getDownloadFileSize(input);
|
||||
|
||||
assertThat(result).isEqualTo(1337L);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDownloadFileSize_Folder() {
|
||||
try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
|
||||
filesMock.when(() -> Files.isDirectory(any())).thenReturn(true);
|
||||
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
Long result = target.getDownloadFileSize(input);
|
||||
|
||||
assertThat(result).isZero();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import com.google.common.jimfs.Configuration;
|
||||
import com.google.common.jimfs.Jimfs;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.buffer.*;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Named.named;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FilesystemServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private FilesystemService target;
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
private static final FileSystem unixFS = Jimfs.newFileSystem(Configuration.unix());
|
||||
private static final FileSystem osxFS = Jimfs.newFileSystem(Configuration.osX());
|
||||
private static final FileSystem winFS = Jimfs.newFileSystem(Configuration.windows());
|
||||
|
||||
private static final String CACHE_PATH = "path/to/cache";
|
||||
|
||||
void setup(FileSystem fileSystem) {
|
||||
ReflectionTestUtils.setField(target, "fileSystem", fileSystem);
|
||||
ReflectionTestUtils.setField(target, "cacheFolderPath", CACHE_PATH);
|
||||
target.createCacheFolder();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void closeFileSystems() throws IOException {
|
||||
unixFS.close();
|
||||
osxFS.close();
|
||||
winFS.close();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void getPath(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String testPath = "some/random/path";
|
||||
Path input = fileSystem.getPath(testPath);
|
||||
Files.createDirectories(input);
|
||||
|
||||
Path result = target.getPath(testPath);
|
||||
|
||||
assertThat(result).isEqualTo(input);
|
||||
|
||||
Files.deleteIfExists(input);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void createCacheFolder(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
Path cache = fileSystem.getPath(CACHE_PATH);
|
||||
Files.deleteIfExists(cache);
|
||||
|
||||
assertThat(Files.exists(cache)).isFalse();
|
||||
|
||||
target.createCacheFolder();
|
||||
|
||||
assertThat(Files.exists(cache)).isTrue();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void saveFileToCache(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[1024];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
try(InputStream i = new ByteArrayInputStream(fileContent)) {
|
||||
DataBufferFactory dbFactory = new DefaultDataBufferFactory();
|
||||
Flux<DataBuffer> d = DataBufferUtils.readInputStream(() -> i, dbFactory, 1);
|
||||
|
||||
target.saveFileToCache(d, fileName);
|
||||
|
||||
assertThat(Files.readAllBytes(savedFilePath)).isEqualTo(fileContent);
|
||||
}
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void getFileFromCache(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[1024];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
Files.write(savedFilePath, fileContent);
|
||||
|
||||
ByteArrayResource expected = new ByteArrayResource(fileContent);
|
||||
|
||||
assertThat(target.getFileFromCache(fileName)).isEqualTo(expected);
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void deleteFileFromCache(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[1024];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
Files.write(savedFilePath, fileContent);
|
||||
assertThat(Files.exists(savedFilePath)).isTrue();
|
||||
|
||||
target.deleteFileFromCache(fileName);
|
||||
|
||||
assertThat(Files.exists(savedFilePath)).isFalse();
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void isCachedFileCorrupt_True(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
Files.write(savedFilePath, new byte[0]);
|
||||
assertThat(target.isCachedFileCorrupt(fileName)).isTrue();
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void isCachedFileCorrupt_False(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[1024];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
Files.write(savedFilePath, fileContent);
|
||||
assertThat(target.isCachedFileCorrupt(fileName)).isFalse();
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void doesCachedFileExist(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[1024];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Path savedFilePath = fileSystem.getPath(CACHE_PATH, fileName);
|
||||
|
||||
assertThat(target.doesCachedFileExist(fileName)).isFalse();
|
||||
|
||||
Files.write(savedFilePath, fileContent);
|
||||
|
||||
assertThat(target.doesCachedFileExist(fileName)).isTrue();
|
||||
|
||||
Files.deleteIfExists(savedFilePath);
|
||||
}
|
||||
|
||||
@Disabled("Due to JimFS not supporting the \"Path.toFile()\" call")
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void getSizeOnDisk_Directory(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String directoryName = easyRandom.nextObject(String.class);
|
||||
int fileSize = 1024;
|
||||
int fileCount = 5;
|
||||
|
||||
Files.createDirectories(fileSystem.getPath(directoryName));
|
||||
|
||||
for(int i = 0; i < fileCount; i++) {
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[fileSize];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
Files.write(fileSystem.getPath(directoryName, fileName), fileContent);
|
||||
}
|
||||
|
||||
long directorySize = target.getSizeOnDisk(fileSystem.getPath(directoryName));
|
||||
|
||||
assertThat(directorySize).isEqualTo(fileSize * fileCount);
|
||||
}
|
||||
|
||||
@Disabled("Due to JimFS not supporting the \"Path.toFile()\" call")
|
||||
@ParameterizedTest
|
||||
@MethodSource("fileSystems")
|
||||
void getSizeOnDisk_File(FileSystem fileSystem) throws IOException {
|
||||
setup(fileSystem);
|
||||
|
||||
String directoryName = easyRandom.nextObject(String.class);
|
||||
int fileSize = 1024;
|
||||
String fileName = easyRandom.nextObject(String.class);
|
||||
byte[] fileContent = new byte[fileSize];
|
||||
easyRandom.nextBytes(fileContent);
|
||||
|
||||
Files.write(fileSystem.getPath(directoryName, fileName), fileContent);
|
||||
|
||||
long directorySize = target.getSizeOnDisk(fileSystem.getPath(directoryName));
|
||||
|
||||
assertThat(directorySize).isEqualTo(fileSize);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> fileSystems() {
|
||||
return Stream.of(
|
||||
arguments(named("Unix", unixFS)),
|
||||
arguments(named("OSX", osxFS)),
|
||||
arguments(named("Windows", winFS))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.dto.GameOverviewDto;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.entities.Library;
|
||||
import de.grimsi.gameyfin.entities.Platform;
|
||||
import de.grimsi.gameyfin.entities.UnmappableFile;
|
||||
import de.grimsi.gameyfin.igdb.IgdbApiProperties;
|
||||
import de.grimsi.gameyfin.igdb.IgdbWrapper;
|
||||
import de.grimsi.gameyfin.mapper.GameMapper;
|
||||
import de.grimsi.gameyfin.repositories.DetectedGameRepository;
|
||||
import de.grimsi.gameyfin.repositories.LibraryRepository;
|
||||
import de.grimsi.gameyfin.repositories.UnmappableFileRepository;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.in;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class GameServiceTest {
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
@InjectMocks
|
||||
private GameService target;
|
||||
|
||||
@Mock
|
||||
private IgdbWrapper igdbWrapperMock;
|
||||
|
||||
@Mock
|
||||
private GameMapper gameMapperMock;
|
||||
|
||||
@Mock
|
||||
private DetectedGameRepository detectedGameRepositoryMock;
|
||||
|
||||
@Mock
|
||||
private UnmappableFileRepository unmappableFileRepositoryMock;
|
||||
|
||||
@Mock
|
||||
private LibraryRepository libraryRepositoryMock;
|
||||
|
||||
@Mock
|
||||
private FilesystemService filesystemServiceMock;
|
||||
|
||||
@Test
|
||||
void getAllDetectedGames() {
|
||||
List<DetectedGame> input = easyRandom.objects(DetectedGame.class, 5).toList();
|
||||
|
||||
when(detectedGameRepositoryMock.findAll()).thenReturn(input);
|
||||
|
||||
List<DetectedGame> result = target.getAllDetectedGames();
|
||||
|
||||
assertThat(result).hasSameElementsAs(input);
|
||||
verify(detectedGameRepositoryMock, times(1)).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDetectedGame() {
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
when(detectedGameRepositoryMock.findById(slug)).thenReturn(Optional.of(input));
|
||||
|
||||
DetectedGame result = target.getDetectedGame(slug);
|
||||
|
||||
assertThat(result).isEqualTo(input);
|
||||
verify(detectedGameRepositoryMock, times(1)).findById(slug);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDetectedGame_NotFound() {
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
|
||||
when(detectedGameRepositoryMock.findById(slug)).thenReturn(Optional.empty());
|
||||
|
||||
ResponseStatusException e = assertThrows(ResponseStatusException.class, () -> target.getDetectedGame(slug));
|
||||
|
||||
assertThat(e.getStatus()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
verify(detectedGameRepositoryMock, times(1)).findById(slug);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllUnmappedFiles() {
|
||||
List<UnmappableFile> input = easyRandom.objects(UnmappableFile.class, 5).toList();
|
||||
|
||||
when(unmappableFileRepositoryMock.findAll()).thenReturn(input);
|
||||
|
||||
List<UnmappableFile> result = target.getAllUnmappedFiles();
|
||||
|
||||
assertThat(result).hasSameElementsAs(input);
|
||||
verify(unmappableFileRepositoryMock, times(1)).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAllMappings() {
|
||||
Stream<DetectedGame> gameStream = easyRandom.objects(DetectedGame.class, 5);
|
||||
List<DetectedGame> games = gameStream.toList();
|
||||
Map<String, String> input = games.stream().collect(Collectors.toMap(DetectedGame::getPath, DetectedGame::getTitle));
|
||||
|
||||
when(detectedGameRepositoryMock.findAll()).thenReturn(games);
|
||||
|
||||
Map<String, String> result = target.getAllMappings();
|
||||
|
||||
assertThat(result).containsAllEntriesOf(input);
|
||||
verify(detectedGameRepositoryMock, times(1)).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getGameOverviews() {
|
||||
Stream<DetectedGame> gameStream = easyRandom.objects(DetectedGame.class, 5);
|
||||
List<DetectedGame> games = gameStream.toList();
|
||||
List<GameOverviewDto> input = games.stream()
|
||||
.map(d -> GameOverviewDto.builder()
|
||||
.coverId(d.getCoverId())
|
||||
.slug(d.getSlug())
|
||||
.title(d.getTitle())
|
||||
.build())
|
||||
.toList();
|
||||
|
||||
when(detectedGameRepositoryMock.findAll()).thenReturn(games);
|
||||
when(gameMapperMock.toGameOverviewDto(any())).thenCallRealMethod();
|
||||
|
||||
List<GameOverviewDto> result = target.getGameOverviews();
|
||||
|
||||
assertThat(result).hasSameElementsAs(input);
|
||||
verify(detectedGameRepositoryMock, times(1)).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteGame() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
when(detectedGameRepositoryMock.findById(input.getSlug())).thenReturn(Optional.of(input));
|
||||
|
||||
target.deleteGame(input.getSlug());
|
||||
|
||||
verify(detectedGameRepositoryMock, times(1)).findById(input.getSlug());
|
||||
verify(unmappableFileRepositoryMock, times(1)).save(new UnmappableFile(input.getPath()));
|
||||
verify(detectedGameRepositoryMock, times(1)).delete(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteUnmappedFile() {
|
||||
Long input = easyRandom.nextLong();
|
||||
|
||||
target.deleteUnmappedFile(input);
|
||||
|
||||
verify(unmappableFileRepositoryMock, times(1)).deleteById(input);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {true, false})
|
||||
void confirmGame(boolean confirmMatch) {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
input.setConfirmedMatch(!confirmMatch);
|
||||
|
||||
when(detectedGameRepositoryMock.findById(input.getSlug())).thenReturn(Optional.of(input));
|
||||
when(detectedGameRepositoryMock.save(any(DetectedGame.class))).thenAnswer(invocation -> invocation.getArgument(0, DetectedGame.class));
|
||||
|
||||
DetectedGame result = target.confirmGame(input.getSlug(), confirmMatch);
|
||||
|
||||
assertThat(result).usingRecursiveComparison()
|
||||
.ignoringFields("confirmedMatch")
|
||||
.isEqualTo(input);
|
||||
assertThat(result.isConfirmedMatch()).isEqualTo(confirmMatch);
|
||||
|
||||
verify(detectedGameRepositoryMock, times(1)).save(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapPathToGame_UnmappableFile() {
|
||||
DetectedGame mockedDetectedGame = easyRandom.nextObject(DetectedGame.class);
|
||||
mockedDetectedGame.setConfirmedMatch(false);
|
||||
UnmappableFile input = new UnmappableFile(mockedDetectedGame.getPath());
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
Library mockedLibrary = Library.builder()
|
||||
.path(input.getPath())
|
||||
.platforms(easyRandom.objects(Platform.class, 5).toList())
|
||||
.build();
|
||||
|
||||
when(detectedGameRepositoryMock.existsBySlug(slug)).thenReturn(false);
|
||||
when(detectedGameRepositoryMock.save(any(DetectedGame.class))).thenAnswer(invocation -> invocation.getArgument(0, DetectedGame.class));
|
||||
when(unmappableFileRepositoryMock.findByPath(input.getPath())).thenReturn(Optional.of(input));
|
||||
when(filesystemServiceMock.getPath(input.getPath())).thenReturn(Path.of("parent", input.getPath()));
|
||||
when(igdbWrapperMock.getGameBySlug(slug)).thenReturn(Optional.of(Igdb.Game.newBuilder().build()));
|
||||
when(libraryRepositoryMock.findByPath(any())).thenReturn(Optional.of(mockedLibrary));
|
||||
when(gameMapperMock.toDetectedGame(any(Igdb.Game.class), any(Path.class), any(Library.class))).thenReturn(mockedDetectedGame);
|
||||
|
||||
DetectedGame result = target.mapPathToGame(input.getPath(), slug);
|
||||
|
||||
verify(detectedGameRepositoryMock, times(1)).existsBySlug(slug);
|
||||
verify(detectedGameRepositoryMock, never()).findByPath(input.getPath());
|
||||
verify(unmappableFileRepositoryMock, times(1)).findByPath(input.getPath());
|
||||
|
||||
assertThat(result).usingRecursiveComparison()
|
||||
.ignoringFields("confirmedMatch")
|
||||
.isEqualTo(mockedDetectedGame);
|
||||
assertThat(result.isConfirmedMatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapPathToGame_DetectedGame() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
input.setConfirmedMatch(false);
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
Library mockedLibrary = Library.builder()
|
||||
.path(input.getPath())
|
||||
.platforms(easyRandom.objects(Platform.class, 5).toList())
|
||||
.build();
|
||||
|
||||
when(detectedGameRepositoryMock.existsBySlug(slug)).thenReturn(false);
|
||||
when(detectedGameRepositoryMock.save(any(DetectedGame.class))).thenAnswer(invocation -> invocation.getArgument(0, DetectedGame.class));
|
||||
when(detectedGameRepositoryMock.findByPath(input.getPath())).thenReturn(Optional.of(input));
|
||||
when(unmappableFileRepositoryMock.findByPath(input.getPath())).thenReturn(Optional.empty());
|
||||
when(filesystemServiceMock.getPath(input.getPath())).thenReturn(Path.of("parent", input.getPath()));
|
||||
when(igdbWrapperMock.getGameBySlug(slug)).thenReturn(Optional.of(Igdb.Game.newBuilder().build()));
|
||||
when(libraryRepositoryMock.findByPath(any())).thenReturn(Optional.of(mockedLibrary));
|
||||
when(gameMapperMock.toDetectedGame(any(Igdb.Game.class), any(Path.class), any(Library.class))).thenReturn(input);
|
||||
|
||||
DetectedGame result = target.mapPathToGame(input.getPath(), slug);
|
||||
|
||||
verify(detectedGameRepositoryMock, times(1)).existsBySlug(slug);
|
||||
verify(detectedGameRepositoryMock, times(1)).findByPath(input.getPath());
|
||||
verify(unmappableFileRepositoryMock, times(1)).findByPath(input.getPath());
|
||||
|
||||
assertThat(result).usingRecursiveComparison()
|
||||
.ignoringFields("confirmedMatch")
|
||||
.isEqualTo(input);
|
||||
assertThat(result.isConfirmedMatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapPathToGame_SlugAlreadyInDatabase() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
when(detectedGameRepositoryMock.existsBySlug(input.getSlug())).thenReturn(true);
|
||||
|
||||
ResponseStatusException e = assertThrows(ResponseStatusException.class, () -> target.mapPathToGame(input.getPath(), input.getSlug()));
|
||||
|
||||
assertThat(e.getStatus()).isEqualTo(HttpStatus.CONFLICT);
|
||||
verify(detectedGameRepositoryMock, times(1)).existsBySlug(input.getSlug());
|
||||
verify(detectedGameRepositoryMock, never()).findByPath(input.getPath());
|
||||
verify(unmappableFileRepositoryMock, never()).findByPath(input.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void mapPathToGame_PathNotInDatabase() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
|
||||
when(detectedGameRepositoryMock.existsBySlug(input.getSlug())).thenReturn(false);
|
||||
when(detectedGameRepositoryMock.findByPath(input.getPath())).thenReturn(Optional.empty());
|
||||
when(unmappableFileRepositoryMock.findByPath(input.getPath())).thenReturn(Optional.empty());
|
||||
|
||||
ResponseStatusException e = assertThrows(ResponseStatusException.class, () -> target.mapPathToGame(input.getPath(), input.getSlug()));
|
||||
|
||||
assertThat(e.getStatus()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
verify(detectedGameRepositoryMock, times(1)).existsBySlug(input.getSlug());
|
||||
verify(detectedGameRepositoryMock, times(1)).findByPath(input.getPath());
|
||||
verify(unmappableFileRepositoryMock, times(1)).findByPath(input.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshGame() {
|
||||
DetectedGame input = easyRandom.nextObject(DetectedGame.class);
|
||||
input.setConfirmedMatch(true);
|
||||
Library mockedLibrary = Library.builder()
|
||||
.path(input.getPath())
|
||||
.platforms(easyRandom.objects(Platform.class, 5).toList())
|
||||
.build();
|
||||
|
||||
when(detectedGameRepositoryMock.findById(input.getSlug())).thenReturn(Optional.of(input));
|
||||
when(detectedGameRepositoryMock.save(any(DetectedGame.class))).thenAnswer(invocation -> invocation.getArgument(0, DetectedGame.class));
|
||||
when(filesystemServiceMock.getPath(input.getPath())).thenReturn(Path.of("parent", input.getPath()));
|
||||
when(igdbWrapperMock.getGameBySlug(input.getSlug())).thenReturn(Optional.of(Igdb.Game.newBuilder().build()));
|
||||
when(libraryRepositoryMock.findByPath(any())).thenReturn(Optional.of(mockedLibrary));
|
||||
when(gameMapperMock.toDetectedGame(any(Igdb.Game.class), any(Path.class), any(Library.class))).thenReturn(input);
|
||||
|
||||
DetectedGame result = target.refreshGame(input.getSlug());
|
||||
|
||||
assertThat(result).usingRecursiveComparison()
|
||||
.ignoringFields("confirmedMatch")
|
||||
.isEqualTo(input);
|
||||
assertThat(result.isConfirmedMatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshGame_NotFound() {
|
||||
String slug = easyRandom.nextObject(String.class);
|
||||
|
||||
when(detectedGameRepositoryMock.findById(slug)).thenReturn(Optional.empty());
|
||||
|
||||
ResponseStatusException e = assertThrows(ResponseStatusException.class, () -> target.refreshGame(slug));
|
||||
|
||||
assertThat(e.getStatus()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
verify(detectedGameRepositoryMock, times(1)).findById(slug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import de.grimsi.gameyfin.entities.Company;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import org.jeasy.random.EasyRandom;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ImageServiceTest {
|
||||
|
||||
private final EasyRandom easyRandom = new EasyRandom();
|
||||
|
||||
private FilesystemService filesystemServiceMock;
|
||||
private GameService gameServiceMock;
|
||||
|
||||
private ImageService target;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
WebClient.Builder webClientBuilderMock = mock(WebClient.Builder.class);
|
||||
gameServiceMock = mock(GameService.class);
|
||||
filesystemServiceMock = mock(FilesystemService.class);
|
||||
|
||||
target = new ImageService(filesystemServiceMock, gameServiceMock, webClientBuilderMock);
|
||||
|
||||
ReflectionTestUtils.setField(target, "webclientBuilder", webClientBuilderMock);
|
||||
when(webClientBuilderMock.baseUrl(any(String.class))).thenReturn(WebClient.builder());
|
||||
|
||||
target.init();
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadGameCoversFromIgdb() {
|
||||
List<DetectedGame> detectedGames = easyRandom.objects(DetectedGame.class, 5).toList();
|
||||
|
||||
when(gameServiceMock.getAllDetectedGames()).thenReturn(detectedGames);
|
||||
|
||||
target.downloadGameCoversFromIgdb();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllDetectedGames();
|
||||
verify(filesystemServiceMock, times(detectedGames.size())).saveFileToCache(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadGameScreenshotsFromIgdb() {
|
||||
List<DetectedGame> detectedGames = easyRandom.objects(DetectedGame.class, 5).toList();
|
||||
List<String> screenshotIds = detectedGames.stream().flatMap(d -> d.getScreenshotIds().stream()).toList();
|
||||
|
||||
when(gameServiceMock.getAllDetectedGames()).thenReturn(detectedGames);
|
||||
|
||||
target.downloadGameScreenshotsFromIgdb();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllDetectedGames();
|
||||
verify(filesystemServiceMock, times(screenshotIds.size())).saveFileToCache(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadCompanyLogosFromIgdb() {
|
||||
List<DetectedGame> detectedGames = easyRandom.objects(DetectedGame.class, 5).toList();
|
||||
Set<String> companyLogoIds = detectedGames.stream().flatMap(d -> d.getCompanies().stream())
|
||||
.map(Company::getLogoId).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
when(gameServiceMock.getAllDetectedGames()).thenReturn(detectedGames);
|
||||
|
||||
target.downloadCompanyLogosFromIgdb();
|
||||
|
||||
verify(gameServiceMock, times(1)).getAllDetectedGames();
|
||||
verify(filesystemServiceMock, times(companyLogoIds.size())).saveFileToCache(any(), any());
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,26 @@
|
||||
package de.grimsi.gameyfin.util;
|
||||
|
||||
import com.google.common.jimfs.Configuration;
|
||||
import com.google.common.jimfs.Jimfs;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Named.named;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Named.named;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
import com.google.common.jimfs.Configuration;
|
||||
import com.google.common.jimfs.Jimfs;
|
||||
|
||||
class FilenameUtilTest {
|
||||
|
||||
@@ -30,10 +29,13 @@ class FilenameUtilTest {
|
||||
private static final FileSystem winFS = Jimfs.newFileSystem(Configuration.windows());
|
||||
|
||||
private static final List<String> gameFileExtensions = List.of("extension_1", "extension_2", "extension_3");
|
||||
private static final List<String> possibleGameFileSuffixes = Arrays.asList("windows, win, english, win32, win64, opengl, stable".split(", "));
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
new FilenameUtil().setPossibleGameFileExtensions(gameFileExtensions);
|
||||
FilenameUtil filenameUtil = new FilenameUtil();
|
||||
filenameUtil.setPossibleGameFileExtensions(gameFileExtensions);
|
||||
filenameUtil.setPossibleGameFileSuffixes(possibleGameFileSuffixes);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -113,6 +115,46 @@ class FilenameUtilTest {
|
||||
|
||||
Files.deleteIfExists(p);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("exampleFilenames")
|
||||
void removeFileSuffixes(String filename) {
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "-win"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "-v1.05.4"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "-win32"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "-win-opengl(windows)"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "-windows-stable"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "[windows]"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "[stable]"))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s".formatted(filename, "(opengl)"))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("exampleFilenames")
|
||||
void removeFileSuffixesFileExtensions(String filename) {
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "-win", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "-v1.05.4", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "-win32", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "-win-opengl(windows)", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "-windows-stable", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "[windows]", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "[stable]", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath("%s.%s.%s".formatted(filename, "(opengl)", gameFileExtensions.get(0)))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("exampleFilenames")
|
||||
void removeFileSuffixesWithAddedSpaces(String filename) {
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "-win", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "-v1.05.4", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "-win32", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "-win-opengl(windows)", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "-windows-stable", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "[windows]", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "[stable]", gameFileExtensions.get(0)))));
|
||||
assertEquals(filename, FilenameUtil.getFilenameWithoutAdditions(unixFS.getPath(" %s.%s .%s".formatted(filename, "(opengl)", gameFileExtensions.get(0)))));
|
||||
}
|
||||
|
||||
|
||||
private static Stream<Arguments> fileSystems() {
|
||||
return Stream.of(
|
||||
@@ -121,4 +163,12 @@ class FilenameUtilTest {
|
||||
arguments(named("Windows", winFS))
|
||||
);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> exampleFilenames() {
|
||||
return Stream.of(
|
||||
arguments(named("example_file", "example_file")),
|
||||
arguments(named("example-file", "example-file")),
|
||||
arguments(named("example file", "example file"))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,8 @@ gameyfin:
|
||||
igdb:
|
||||
api:
|
||||
client-id: igdb_client_id
|
||||
client-secret: igdb_client_secret
|
||||
client-secret: igdb_client_secret
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:${spring.datasource.db-name}
|
||||
@@ -0,0 +1 @@
|
||||
mock-maker-inline
|
||||
Reference in New Issue
Block a user