diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b312ed4
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,27 @@
+name: CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: maven
+
+ - name: Compile
+ run: ./mvnw compile -B
+
+ - name: Run tests
+ run: ./mvnw test -B
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..7164225
Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..7f3c032
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.0/maven-wrapper-3.3.0.jar
diff --git a/pom.xml b/pom.xml
index 8d104b3..4dcc2fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
Environment manager
21
+ 1.5.5.Final
@@ -49,6 +50,15 @@
springdoc-openapi-starter-webmvc-ui
2.3.0
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
org.springframework.boot
spring-boot-starter-actuator
@@ -92,6 +102,16 @@
lombok
1.18.30
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+ org.projectlombok
+ lombok-mapstruct-binding
+ 0.2.0
+
diff --git a/src/main/java/preponderous/viron/controllers/DebugController.java b/src/main/java/preponderous/viron/controllers/DebugController.java
index def2681..1dd54ba 100644
--- a/src/main/java/preponderous/viron/controllers/DebugController.java
+++ b/src/main/java/preponderous/viron/controllers/DebugController.java
@@ -1,17 +1,18 @@
package preponderous.viron.controllers;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import preponderous.viron.dto.EntityDto;
+import preponderous.viron.dto.EnvironmentDto;
+import preponderous.viron.exceptions.InvalidRequestException;
+import preponderous.viron.mappers.EntityMapper;
+import preponderous.viron.mappers.EnvironmentMapper;
import preponderous.viron.models.Entity;
import preponderous.viron.models.Environment;
import preponderous.viron.models.Grid;
@@ -24,19 +25,26 @@
@RestController
@RequestMapping("/api/v1/debug")
@Slf4j
+@Validated
public class DebugController {
private final EntityService entityService;
private final EnvironmentService environmentService;
private final GridService gridService;
private final LocationService locationService;
+ private final EntityMapper entityMapper;
+ private final EnvironmentMapper environmentMapper;
- List entityNamePool = new ArrayList<>(Arrays.asList("Tom", "Jerry", "Spike", "Tyke", "Nibbles", "Butch", "Tuffy", "Lightning", "Mammy", "Quacker", "Toodles", "Droopy", "Screwy", "Meathead", "George", "Dripple", "McWolf"));
+ private final List entityNamePool = List.of("Tom", "Jerry", "Spike", "Tyke", "Nibbles", "Butch", "Tuffy", "Lightning", "Mammy", "Quacker", "Toodles", "Droopy", "Screwy", "Meathead", "George", "Dripple", "McWolf");
- public DebugController(EntityService entityService, EnvironmentService environmentService, GridService gridService, LocationService locationService) {
+ public DebugController(EntityService entityService, EnvironmentService environmentService,
+ GridService gridService, LocationService locationService,
+ EntityMapper entityMapper, EnvironmentMapper environmentMapper) {
this.entityService = entityService;
this.environmentService = environmentService;
this.gridService = gridService;
this.locationService = locationService;
+ this.entityMapper = entityMapper;
+ this.environmentMapper = environmentMapper;
}
/**
@@ -44,10 +52,14 @@ public DebugController(EntityService entityService, EnvironmentService environme
* It ensures the entities are properly created and assigned to valid locations in the grid.
*/
@PostMapping("/create-sample-data")
- public ResponseEntity createSampleData() {
+ @ResponseStatus(HttpStatus.CREATED)
+ public EnvironmentDto createSampleData() {
// create an environment with one 10x10 grid
Environment environment = environmentService.createEnvironment("Sample Environment", 1, 10);
List grids = gridService.getGridsInEnvironment(environment.getEnvironmentId());
+ if (grids.isEmpty()) {
+ throw new InvalidRequestException("No grids found in environment: " + environment.getEnvironmentId());
+ }
Grid grid = grids.getFirst();
List locations = locationService.getLocationsInGrid(grid.getGridId());
@@ -66,12 +78,12 @@ public ResponseEntity createSampleData() {
}
}
if (location == null) {
- return ResponseEntity.badRequest().body(null); // exit if no valid location found
+ throw new InvalidRequestException("No valid location found at coordinates (" + x + ", " + y + ")");
}
locationService.addEntityToLocation(entity.getEntityId(), location.getLocationId());
}
- return ResponseEntity.ok(environment);
+ return environmentMapper.toDto(environment);
}
/**
@@ -81,7 +93,8 @@ public ResponseEntity createSampleData() {
* @param environmentName the name of the environment to be created
*/
@PostMapping("/create-world-and-place-entity/{environmentName}")
- public ResponseEntity createWorldAndPlaceEntity(@PathVariable String environmentName) {
+ @ResponseStatus(HttpStatus.CREATED)
+ public EntityDto createWorldAndPlaceEntity(@PathVariable @NotBlank String environmentName) {
// create an environment
int numGrids = 1;
int gridSize = 5;
@@ -90,7 +103,10 @@ public ResponseEntity createWorldAndPlaceEntity(@PathVariable String env
// get grid info
List grids = gridService.getGridsInEnvironment(environment.getEnvironmentId());
- Grid grid = grids.get(0);
+ if (grids.isEmpty()) {
+ throw new InvalidRequestException("No grids found in environment: " + environment.getEnvironmentId());
+ }
+ Grid grid = grids.getFirst();
log.info("Grid created: {} with size {}x{}", grid.getGridId(), grid.getRows(), grid.getColumns());
// create an entity
@@ -110,11 +126,10 @@ public ResponseEntity createWorldAndPlaceEntity(@PathVariable String env
}
}
if (location == null) {
- log.error("No valid location found for entity at row {} and column {}", entityRow, entityColumn);
- return ResponseEntity.badRequest().body(null);
+ throw new InvalidRequestException("No valid location found for entity at row " + entityRow + " and column " + entityColumn);
}
locationService.addEntityToLocation(entity.getEntityId(), location.getLocationId());
log.info("Entity {} placed at location ({}, {})", entity.getName(), entityRow, entityColumn);
- return ResponseEntity.ok(entity);
+ return entityMapper.toDto(entity);
}
}
\ No newline at end of file
diff --git a/src/main/java/preponderous/viron/controllers/EntityController.java b/src/main/java/preponderous/viron/controllers/EntityController.java
index 14a3e1c..a1bf6bb 100644
--- a/src/main/java/preponderous/viron/controllers/EntityController.java
+++ b/src/main/java/preponderous/viron/controllers/EntityController.java
@@ -2,120 +2,93 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import preponderous.viron.exceptions.EntityCreationException;
+import preponderous.viron.dto.EntityDto;
+import preponderous.viron.exceptions.NotFoundException;
+import preponderous.viron.exceptions.ServiceException;
import preponderous.viron.factories.EntityFactory;
+import preponderous.viron.mappers.EntityMapper;
import preponderous.viron.models.Entity;
import preponderous.viron.repositories.EntityRepository;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
import java.util.List;
@RestController
@RequestMapping("/api/v1/entities")
@Slf4j
@RequiredArgsConstructor
+@Validated
public class EntityController {
private final EntityRepository entityRepository;
private final EntityFactory entityFactory;
+ private final EntityMapper entityMapper;
@GetMapping
- public ResponseEntity> getAllEntities() {
- try {
- return ResponseEntity.ok(entityRepository.findAll());
- } catch (Exception e) {
- log.error("Error fetching all entities: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getAllEntities() {
+ List entities = entityRepository.findAll();
+ return entityMapper.toDtoList(entities);
}
@GetMapping("/{id}")
- public ResponseEntity getEntityById(@PathVariable int id) {
- try {
- return entityRepository.findById(id)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching entity by id {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public EntityDto getEntityById(@PathVariable @Min(1) int id) {
+ Entity entity = entityRepository.findById(id)
+ .orElseThrow(() -> new NotFoundException("Entity not found with id: " + id));
+ return entityMapper.toDto(entity);
}
@GetMapping("/environment/{environmentId}")
- public ResponseEntity> getEntitiesInEnvironment(@PathVariable int environmentId) {
- try {
- return ResponseEntity.ok(entityRepository.findByEnvironmentId(environmentId));
- } catch (Exception e) {
- log.error("Error fetching entities in environment {}: {}", environmentId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getEntitiesInEnvironment(@PathVariable @Min(1) int environmentId) {
+ List entities = entityRepository.findByEnvironmentId(environmentId);
+ return entityMapper.toDtoList(entities);
}
@GetMapping("/grid/{gridId}")
- public ResponseEntity> getEntitiesInGrid(@PathVariable int gridId) {
- try {
- return ResponseEntity.ok(entityRepository.findByGridId(gridId));
- } catch (Exception e) {
- log.error("Error fetching entities in grid {}: {}", gridId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getEntitiesInGrid(@PathVariable @Min(1) int gridId) {
+ List entities = entityRepository.findByGridId(gridId);
+ return entityMapper.toDtoList(entities);
}
@GetMapping("/location/{locationId}")
- public ResponseEntity> getEntitiesInLocation(@PathVariable int locationId) {
- try {
- return ResponseEntity.ok(entityRepository.findByLocationId(locationId));
- } catch (Exception e) {
- log.error("Error fetching entities in location {}: {}", locationId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getEntitiesInLocation(@PathVariable @Min(1) int locationId) {
+ List entities = entityRepository.findByLocationId(locationId);
+ return entityMapper.toDtoList(entities);
}
@GetMapping("/unassigned")
- public ResponseEntity> getEntitiesNotInAnyLocation() {
- try {
- return ResponseEntity.ok(entityRepository.findEntitiesNotInAnyLocation());
- } catch (Exception e) {
- log.error("Error fetching unassigned entities: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getEntitiesNotInAnyLocation() {
+ List entities = entityRepository.findEntitiesNotInAnyLocation();
+ return entityMapper.toDtoList(entities);
}
@PostMapping("/{name}")
- public ResponseEntity createEntity(@PathVariable String name) {
- try {
- Entity newEntity = entityFactory.createEntity(name);
- return ResponseEntity.ok(newEntity);
- } catch (EntityCreationException e) {
- log.error("Error creating entity with name {}: {}", name, e.getMessage());
- return ResponseEntity.badRequest().build();
- } catch (Exception e) {
- log.error("Unexpected error creating entity: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ @ResponseStatus(HttpStatus.CREATED)
+ public EntityDto createEntity(@PathVariable @NotBlank String name) {
+ Entity newEntity = entityFactory.createEntity(name);
+ return entityMapper.toDto(newEntity);
}
@DeleteMapping("/{id}")
- public ResponseEntity deleteEntity(@PathVariable int id) {
- try {
- return entityRepository.deleteById(id)
- ? ResponseEntity.ok().build()
- : ResponseEntity.notFound().build();
- } catch (Exception e) {
- log.error("Error deleting entity {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteEntity(@PathVariable @Min(1) int id) {
+ if (entityRepository.findById(id).isEmpty()) {
+ throw new NotFoundException("Entity not found with id: " + id);
+ }
+ if (!entityRepository.deleteById(id)) {
+ throw new ServiceException("Failed to delete entity with id: " + id);
}
}
@PatchMapping("/{id}/name/{name}")
- public ResponseEntity updateEntityName(@PathVariable int id, @PathVariable String name) {
- try {
- return entityRepository.updateName(id, name)
- ? ResponseEntity.ok().build()
- : ResponseEntity.notFound().build();
- } catch (Exception e) {
- log.error("Error updating name for entity {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ public void updateEntityName(@PathVariable @Min(1) int id, @PathVariable @NotBlank String name) {
+ if (entityRepository.findById(id).isEmpty()) {
+ throw new NotFoundException("Entity not found with id: " + id);
+ }
+ if (!entityRepository.updateName(id, name)) {
+ throw new ServiceException("Failed to update name for entity " + id);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/preponderous/viron/controllers/EnvironmentController.java b/src/main/java/preponderous/viron/controllers/EnvironmentController.java
index ff1933e..c7708cf 100644
--- a/src/main/java/preponderous/viron/controllers/EnvironmentController.java
+++ b/src/main/java/preponderous/viron/controllers/EnvironmentController.java
@@ -6,189 +6,148 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import preponderous.viron.exceptions.EnvironmentCreationException;
+import preponderous.viron.dto.EnvironmentDto;
+import preponderous.viron.exceptions.NotFoundException;
+import preponderous.viron.exceptions.ServiceException;
import preponderous.viron.factories.EnvironmentFactory;
+import preponderous.viron.mappers.EnvironmentMapper;
import preponderous.viron.models.Environment;
import preponderous.viron.repositories.EnvironmentRepository;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
import java.util.List;
@RestController
@RequestMapping("/api/v1/environments")
@Slf4j
@RequiredArgsConstructor
+@Validated
public class EnvironmentController {
private final EnvironmentRepository environmentRepository;
private final EnvironmentFactory environmentFactory;
+ private final EnvironmentMapper environmentMapper;
@GetMapping
- public ResponseEntity> getAllEnvironments() {
- try {
- return ResponseEntity.ok(environmentRepository.findAll());
- } catch (Exception e) {
- log.error("Error fetching all environments: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getAllEnvironments() {
+ List environments = environmentRepository.findAll();
+ return environmentMapper.toDtoList(environments);
}
@GetMapping("/{id}")
- public ResponseEntity getEnvironmentById(@PathVariable int id) {
- try {
- return environmentRepository.findById(id)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching environment by id {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public EnvironmentDto getEnvironmentById(@PathVariable @Min(1) int id) {
+ Environment environment = environmentRepository.findById(id)
+ .orElseThrow(() -> new NotFoundException("Environment not found with id: " + id));
+ return environmentMapper.toDto(environment);
}
@GetMapping("/name/{name}")
- public ResponseEntity getEnvironmentByName(@PathVariable String name) {
- try {
- return environmentRepository.findByName(name)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching environment by name {}: {}", name, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public EnvironmentDto getEnvironmentByName(@PathVariable @NotBlank String name) {
+ Environment environment = environmentRepository.findByName(name)
+ .orElseThrow(() -> new NotFoundException("Environment not found with name: " + name));
+ return environmentMapper.toDto(environment);
}
@GetMapping("/entity/{entityId}")
- public ResponseEntity getEnvironmentOfEntity(@PathVariable int entityId) {
- try {
- return environmentRepository.findByEntityId(entityId)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching environment for entity {}: {}", entityId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public EnvironmentDto getEnvironmentOfEntity(@PathVariable @Min(1) int entityId) {
+ Environment environment = environmentRepository.findByEntityId(entityId)
+ .orElseThrow(() -> new NotFoundException("Environment not found for entity: " + entityId));
+ return environmentMapper.toDto(environment);
}
@PostMapping("/{name}/{numGrids}/{gridSize}")
- public ResponseEntity createEnvironment(
- @PathVariable String name,
- @PathVariable int numGrids,
- @PathVariable int gridSize) {
- try {
- Environment newEnvironment = environmentFactory.createEnvironment(name, numGrids, gridSize);
- return ResponseEntity.ok(newEnvironment);
- } catch (EnvironmentCreationException e) {
- log.error("Error creating environment with name {}: {}", name, e.getMessage());
- return ResponseEntity.badRequest().build();
- } catch (Exception e) {
- log.error("Unexpected error creating environment: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ @ResponseStatus(HttpStatus.CREATED)
+ public EnvironmentDto createEnvironment(
+ @PathVariable @NotBlank String name,
+ @PathVariable @Min(1) int numGrids,
+ @PathVariable @Min(1) int gridSize) {
+ Environment newEnvironment = environmentFactory.createEnvironment(name, numGrids, gridSize);
+ return environmentMapper.toDto(newEnvironment);
}
@DeleteMapping("/{id}")
- public ResponseEntity deleteEnvironment(@PathVariable int id) {
- try {
- if (environmentRepository.findById(id).isEmpty()) {
- log.info("Environment with id {} does not exist, cannot delete", id);
- return ResponseEntity.notFound().build();
- }
-
- log.info("Attempting to delete environment with id {}", id);
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteEnvironment(@PathVariable @Min(1) int id) {
+ if (environmentRepository.findById(id).isEmpty()) {
+ throw new NotFoundException("Environment not found with id: " + id);
+ }
- List entityIds = environmentRepository.findEntityIdsByEnvironmentId(id);
- List locationIds = environmentRepository.findLocationIdsByEnvironmentId(id);
- List gridIds = environmentRepository.findGridIdsByEnvironmentId(id);
+ log.info("Attempting to delete environment with id {}", id);
- // Delete associations
- for (int entityId : entityIds) {
- if (!environmentRepository.deleteEntityLocation(entityId)) {
- log.error("Error deleting entity_location with entity id {}", entityId);
- return ResponseEntity.internalServerError().build();
- }
- }
+ List entityIds = environmentRepository.findEntityIdsByEnvironmentId(id);
+ List locationIds = environmentRepository.findLocationIdsByEnvironmentId(id);
+ List gridIds = environmentRepository.findGridIdsByEnvironmentId(id);
- for (int locationId : locationIds) {
- if (!environmentRepository.deleteLocationGrid(locationId)) {
- log.error("Error deleting location_grid with location id {}", locationId);
- return ResponseEntity.internalServerError().build();
- }
+ // Delete associations
+ for (int entityId : entityIds) {
+ if (!environmentRepository.deleteEntityLocation(entityId)) {
+ throw new ServiceException("Error deleting entity_location with entity id " + entityId);
}
+ }
- for (int gridId : gridIds) {
- if (!environmentRepository.deleteGridEnvironment(gridId)) {
- log.error("Error deleting grid_environment with grid id {}", gridId);
- return ResponseEntity.internalServerError().build();
- }
+ for (int locationId : locationIds) {
+ if (!environmentRepository.deleteLocationGrid(locationId)) {
+ throw new ServiceException("Error deleting location_grid with location id " + locationId);
}
+ }
- // Delete entities
- for (int entityId : entityIds) {
- if (!environmentRepository.deleteEntity(entityId)) {
- log.error("Error deleting entity with id {}", entityId);
- return ResponseEntity.internalServerError().build();
- }
- }
- if (!entityIds.isEmpty()) {
- log.info("Entities deleted: {}", entityIds);
+ for (int gridId : gridIds) {
+ if (!environmentRepository.deleteGridEnvironment(gridId)) {
+ throw new ServiceException("Error deleting grid_environment with grid id " + gridId);
}
+ }
- // Delete locations
- for (int locationId : locationIds) {
- if (!environmentRepository.deleteLocation(locationId)) {
- log.error("Error deleting location with id {}", locationId);
- return ResponseEntity.internalServerError().build();
- }
- }
- if (!locationIds.isEmpty()) {
- log.info("Locations deleted: {}", locationIds);
+ // Delete entities
+ for (int entityId : entityIds) {
+ if (!environmentRepository.deleteEntity(entityId)) {
+ throw new ServiceException("Error deleting entity with id " + entityId);
}
+ }
+ if (!entityIds.isEmpty()) {
+ log.info("Entities deleted: {}", entityIds);
+ }
- // Delete grids
- for (int gridId : gridIds) {
- if (!environmentRepository.deleteGrid(gridId)) {
- log.error("Error deleting grid with id {}", gridId);
- return ResponseEntity.internalServerError().build();
- }
- }
- if (!gridIds.isEmpty()) {
- log.info("Grids deleted: {}", gridIds);
+ // Delete locations
+ for (int locationId : locationIds) {
+ if (!environmentRepository.deleteLocation(locationId)) {
+ throw new ServiceException("Error deleting location with id " + locationId);
}
+ }
+ if (!locationIds.isEmpty()) {
+ log.info("Locations deleted: {}", locationIds);
+ }
- // Delete environment
- if (!environmentRepository.deleteById(id)) {
- log.error("Error deleting environment with id {}", id);
- return ResponseEntity.internalServerError().build();
+ // Delete grids
+ for (int gridId : gridIds) {
+ if (!environmentRepository.deleteGrid(gridId)) {
+ throw new ServiceException("Error deleting grid with id " + gridId);
}
+ }
+ if (!gridIds.isEmpty()) {
+ log.info("Grids deleted: {}", gridIds);
+ }
- log.info("Environment with id {} deleted", id);
- return ResponseEntity.ok().build();
- } catch (Exception e) {
- log.error("Error deleting environment {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ // Delete environment
+ if (!environmentRepository.deleteById(id)) {
+ throw new ServiceException("Error deleting environment with id " + id);
}
+
+ log.info("Environment with id {} deleted", id);
}
@PatchMapping("/{id}/name/{name}")
- public ResponseEntity updateEnvironmentName(@PathVariable int id, @PathVariable String name) {
- try {
- // First check if the environment exists
- if (environmentRepository.findById(id).isEmpty()) {
- log.info("Environment with id {} not found", id);
- return ResponseEntity.notFound().build();
- }
+ public void updateEnvironmentName(@PathVariable @Min(1) int id, @PathVariable @NotBlank String name) {
+ if (environmentRepository.findById(id).isEmpty()) {
+ throw new NotFoundException("Environment not found with id: " + id);
+ }
- boolean updated = environmentRepository.updateName(id, name);
- if (updated) {
- log.info("Updated name for environment {} to '{}'", id, name);
- return ResponseEntity.ok().build();
- } else {
- log.error("Failed to update name for environment {}", id);
- return ResponseEntity.internalServerError().build();
- }
- } catch (Exception e) {
- log.error("Error updating name for environment {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ if (!environmentRepository.updateName(id, name)) {
+ throw new ServiceException("Failed to update name for environment " + id);
}
+
+ log.info("Updated name for environment {} to '{}'", id, name);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/preponderous/viron/controllers/GridController.java b/src/main/java/preponderous/viron/controllers/GridController.java
index 9a78727..2436429 100644
--- a/src/main/java/preponderous/viron/controllers/GridController.java
+++ b/src/main/java/preponderous/viron/controllers/GridController.java
@@ -2,61 +2,49 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import preponderous.viron.dto.GridDto;
+import preponderous.viron.exceptions.NotFoundException;
+import preponderous.viron.mappers.GridMapper;
import preponderous.viron.models.Grid;
import preponderous.viron.repositories.GridRepository;
+import jakarta.validation.constraints.Min;
import java.util.List;
@RestController
@RequestMapping("/api/v1/grids")
@Slf4j
@RequiredArgsConstructor
+@Validated
public class GridController {
private final GridRepository gridRepository;
+ private final GridMapper gridMapper;
@GetMapping
- public ResponseEntity> getAllGrids() {
- try {
- return ResponseEntity.ok(gridRepository.findAll());
- } catch (Exception e) {
- log.error("Error fetching all grids: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getAllGrids() {
+ List grids = gridRepository.findAll();
+ return gridMapper.toDtoList(grids);
}
@GetMapping("/{id}")
- public ResponseEntity getGridById(@PathVariable int id) {
- try {
- return gridRepository.findById(id)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching grid by id {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public GridDto getGridById(@PathVariable @Min(1) int id) {
+ Grid grid = gridRepository.findById(id)
+ .orElseThrow(() -> new NotFoundException("Grid not found with id: " + id));
+ return gridMapper.toDto(grid);
}
@GetMapping("/environment/{environmentId}")
- public ResponseEntity> getGridsInEnvironment(@PathVariable int environmentId) {
- try {
- return ResponseEntity.ok(gridRepository.findByEnvironmentId(environmentId));
- } catch (Exception e) {
- log.error("Error fetching grids in environment {}: {}", environmentId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getGridsInEnvironment(@PathVariable @Min(1) int environmentId) {
+ List grids = gridRepository.findByEnvironmentId(environmentId);
+ return gridMapper.toDtoList(grids);
}
@GetMapping("/entity/{entityId}")
- public ResponseEntity getGridOfEntity(@PathVariable int entityId) {
- try {
- return gridRepository.findByEntityId(entityId)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching grid for entity {}: {}", entityId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public GridDto getGridOfEntity(@PathVariable @Min(1) int entityId) {
+ Grid grid = gridRepository.findByEntityId(entityId)
+ .orElseThrow(() -> new NotFoundException("Grid not found for entity: " + entityId));
+ return gridMapper.toDto(grid);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/preponderous/viron/controllers/LocationController.java b/src/main/java/preponderous/viron/controllers/LocationController.java
index 152bde9..cbe90aa 100644
--- a/src/main/java/preponderous/viron/controllers/LocationController.java
+++ b/src/main/java/preponderous/viron/controllers/LocationController.java
@@ -2,107 +2,89 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import preponderous.viron.dto.LocationDto;
+import preponderous.viron.exceptions.NotFoundException;
+import preponderous.viron.exceptions.ServiceException;
+import preponderous.viron.mappers.LocationMapper;
import preponderous.viron.models.Location;
import preponderous.viron.repositories.LocationRepository;
+import jakarta.validation.constraints.Min;
import java.util.List;
@RestController
@RequestMapping("/api/v1/locations")
@Slf4j
@RequiredArgsConstructor
+@Validated
public class LocationController {
private final LocationRepository locationRepository;
+ private final LocationMapper locationMapper;
@GetMapping
- public ResponseEntity> getAllLocations() {
- try {
- return ResponseEntity.ok(locationRepository.findAll());
- } catch (Exception e) {
- log.error("Error fetching all locations: {}", e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getAllLocations() {
+ List locations = locationRepository.findAll();
+ return locationMapper.toDtoList(locations);
}
@GetMapping("/{id}")
- public ResponseEntity getLocationById(@PathVariable int id) {
- try {
- return locationRepository.findById(id)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching location by id {}: {}", id, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public LocationDto getLocationById(@PathVariable @Min(1) int id) {
+ Location location = locationRepository.findById(id)
+ .orElseThrow(() -> new NotFoundException("Location not found with id: " + id));
+ return locationMapper.toDto(location);
}
@GetMapping("/environment/{environmentId}")
- public ResponseEntity> getLocationsInEnvironment(@PathVariable int environmentId) {
- try {
- return ResponseEntity.ok(locationRepository.findByEnvironmentId(environmentId));
- } catch (Exception e) {
- log.error("Error fetching locations in environment {}: {}", environmentId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getLocationsInEnvironment(@PathVariable @Min(1) int environmentId) {
+ List locations = locationRepository.findByEnvironmentId(environmentId);
+ return locationMapper.toDtoList(locations);
}
@GetMapping("/grid/{gridId}")
- public ResponseEntity> getLocationsInGrid(@PathVariable int gridId) {
- try {
- return ResponseEntity.ok(locationRepository.findByGridId(gridId));
- } catch (Exception e) {
- log.error("Error fetching locations in grid {}: {}", gridId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public List getLocationsInGrid(@PathVariable @Min(1) int gridId) {
+ List locations = locationRepository.findByGridId(gridId);
+ return locationMapper.toDtoList(locations);
}
@GetMapping("/entity/{entityId}")
- public ResponseEntity getLocationOfEntity(@PathVariable int entityId) {
- try {
- return locationRepository.findByEntityId(entityId)
- .map(ResponseEntity::ok)
- .orElse(ResponseEntity.notFound().build());
- } catch (Exception e) {
- log.error("Error fetching location of entity {}: {}", entityId, e.getMessage());
- return ResponseEntity.internalServerError().build();
- }
+ public LocationDto getLocationOfEntity(@PathVariable @Min(1) int entityId) {
+ Location location = locationRepository.findByEntityId(entityId)
+ .orElseThrow(() -> new NotFoundException("Location not found for entity: " + entityId));
+ return locationMapper.toDto(location);
}
@PutMapping("/{locationId}/entity/{entityId}")
- public ResponseEntity addEntityToLocation(@PathVariable int entityId, @PathVariable int locationId) {
- try {
- return locationRepository.addEntityToLocation(entityId, locationId)
- ? ResponseEntity.ok().build()
- : ResponseEntity.notFound().build();
- } catch (Exception e) {
- log.error("Error adding entity {} to location {}: {}", entityId, locationId, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ public void addEntityToLocation(@PathVariable("entityId") @Min(1) int entityId, @PathVariable("locationId") @Min(1) int locationId) {
+ if (locationRepository.findById(locationId).isEmpty()) {
+ throw new NotFoundException("Location not found with id: " + locationId);
+ }
+ if (!locationRepository.addEntityToLocation(entityId, locationId)) {
+ throw new ServiceException("Failed to add entity " + entityId + " to location " + locationId);
}
}
@DeleteMapping("/{locationId}/entity/{entityId}")
- public ResponseEntity removeEntityFromLocation(@PathVariable int entityId, @PathVariable int locationId) {
- try {
- return locationRepository.removeEntityFromLocation(entityId, locationId)
- ? ResponseEntity.ok().build()
- : ResponseEntity.notFound().build();
- } catch (Exception e) {
- log.error("Error removing entity {} from location {}: {}", entityId, locationId, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void removeEntityFromLocation(@PathVariable("entityId") @Min(1) int entityId, @PathVariable("locationId") @Min(1) int locationId) {
+ if (locationRepository.findById(locationId).isEmpty()) {
+ throw new NotFoundException("Location not found with id: " + locationId);
+ }
+ if (!locationRepository.removeEntityFromLocation(entityId, locationId)) {
+ throw new ServiceException("Failed to remove entity " + entityId + " from location " + locationId);
}
}
@DeleteMapping("/entity/{entityId}")
- public ResponseEntity removeEntityFromCurrentLocation(@PathVariable int entityId) {
- try {
- return locationRepository.removeEntityFromCurrentLocation(entityId)
- ? ResponseEntity.ok().build()
- : ResponseEntity.notFound().build();
- } catch (Exception e) {
- log.error("Error removing entity {} from current location: {}", entityId, e.getMessage());
- return ResponseEntity.internalServerError().build();
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void removeEntityFromCurrentLocation(@PathVariable @Min(1) int entityId) {
+ if (locationRepository.findByEntityId(entityId).isEmpty()) {
+ throw new NotFoundException("Location not found for entity: " + entityId);
+ }
+ if (!locationRepository.removeEntityFromCurrentLocation(entityId)) {
+ throw new ServiceException("Failed to remove entity " + entityId + " from current location");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/preponderous/viron/dto/EntityDto.java b/src/main/java/preponderous/viron/dto/EntityDto.java
new file mode 100644
index 0000000..3cbd425
--- /dev/null
+++ b/src/main/java/preponderous/viron/dto/EntityDto.java
@@ -0,0 +1,21 @@
+package preponderous.viron.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Data transfer object representing an entity")
+public class EntityDto {
+ @Schema(description = "Unique identifier of the entity")
+ private int entityId;
+
+ @Schema(description = "Name of the entity")
+ private String name;
+
+ @Schema(description = "Date when the entity was created")
+ private String creationDate;
+}
diff --git a/src/main/java/preponderous/viron/dto/EnvironmentDto.java b/src/main/java/preponderous/viron/dto/EnvironmentDto.java
new file mode 100644
index 0000000..e5e9716
--- /dev/null
+++ b/src/main/java/preponderous/viron/dto/EnvironmentDto.java
@@ -0,0 +1,21 @@
+package preponderous.viron.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Data transfer object representing an environment")
+public class EnvironmentDto {
+ @Schema(description = "Unique identifier of the environment")
+ private int environmentId;
+
+ @Schema(description = "Name of the environment")
+ private String name;
+
+ @Schema(description = "Date when the environment was created")
+ private String creationDate;
+}
diff --git a/src/main/java/preponderous/viron/dto/ErrorResponse.java b/src/main/java/preponderous/viron/dto/ErrorResponse.java
new file mode 100644
index 0000000..b7e65e1
--- /dev/null
+++ b/src/main/java/preponderous/viron/dto/ErrorResponse.java
@@ -0,0 +1,18 @@
+package preponderous.viron.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Standard error response body")
+public class ErrorResponse {
+ @Schema(description = "HTTP status code")
+ private int status;
+
+ @Schema(description = "Error message describing what went wrong")
+ private String message;
+}
diff --git a/src/main/java/preponderous/viron/dto/GridDto.java b/src/main/java/preponderous/viron/dto/GridDto.java
new file mode 100644
index 0000000..dc278eb
--- /dev/null
+++ b/src/main/java/preponderous/viron/dto/GridDto.java
@@ -0,0 +1,21 @@
+package preponderous.viron.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Data transfer object representing a grid")
+public class GridDto {
+ @Schema(description = "Unique identifier of the grid")
+ private int gridId;
+
+ @Schema(description = "Number of rows in the grid")
+ private int rows;
+
+ @Schema(description = "Number of columns in the grid")
+ private int columns;
+}
diff --git a/src/main/java/preponderous/viron/dto/LocationDto.java b/src/main/java/preponderous/viron/dto/LocationDto.java
new file mode 100644
index 0000000..fc84495
--- /dev/null
+++ b/src/main/java/preponderous/viron/dto/LocationDto.java
@@ -0,0 +1,21 @@
+package preponderous.viron.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "Data transfer object representing a location")
+public class LocationDto {
+ @Schema(description = "Unique identifier of the location")
+ private int locationId;
+
+ @Schema(description = "X coordinate of the location")
+ private int x;
+
+ @Schema(description = "Y coordinate of the location")
+ private int y;
+}
diff --git a/src/main/java/preponderous/viron/exceptions/GlobalExceptionHandler.java b/src/main/java/preponderous/viron/exceptions/GlobalExceptionHandler.java
new file mode 100644
index 0000000..1bd538f
--- /dev/null
+++ b/src/main/java/preponderous/viron/exceptions/GlobalExceptionHandler.java
@@ -0,0 +1,82 @@
+package preponderous.viron.exceptions;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.HandlerMethodValidationException;
+import preponderous.viron.dto.ErrorResponse;
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(NotFoundException.class)
+ public ResponseEntity handleNotFoundException(NotFoundException ex) {
+ log.warn("Resource not found: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
+ }
+
+ @ExceptionHandler(EntityCreationException.class)
+ public ResponseEntity handleEntityCreationException(EntityCreationException ex) {
+ log.warn("Entity creation failed: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(EnvironmentCreationException.class)
+ public ResponseEntity handleEnvironmentCreationException(EnvironmentCreationException ex) {
+ log.warn("Environment creation failed: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(InvalidRequestException.class)
+ public ResponseEntity handleInvalidRequestException(InvalidRequestException ex) {
+ log.warn("Invalid request: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(EntityServiceException.class)
+ public ResponseEntity handleEntityServiceException(EntityServiceException ex) {
+ log.error("Entity service error: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
+ }
+
+ @ExceptionHandler(ServiceException.class)
+ public ResponseEntity handleServiceException(ServiceException ex) {
+ log.error("Service error: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleValidationException(MethodArgumentNotValidException ex) {
+ String message = ex.getBindingResult().getFieldErrors().stream()
+ .map(error -> error.getField() + ": " + error.getDefaultMessage())
+ .reduce((a, b) -> a + "; " + b)
+ .orElse("Validation failed");
+ log.warn("Validation error: {}", message);
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), message);
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(HandlerMethodValidationException.class)
+ public ResponseEntity handleHandlerMethodValidationException(HandlerMethodValidationException ex) {
+ log.warn("Validation error during handler method validation: {}", ex.getMessage());
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), "Validation failed");
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleGenericException(Exception ex) {
+ log.error("Unexpected error: {}", ex.getMessage(), ex);
+ ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected error occurred");
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
+ }
+}
diff --git a/src/main/java/preponderous/viron/exceptions/InvalidRequestException.java b/src/main/java/preponderous/viron/exceptions/InvalidRequestException.java
new file mode 100644
index 0000000..9995309
--- /dev/null
+++ b/src/main/java/preponderous/viron/exceptions/InvalidRequestException.java
@@ -0,0 +1,7 @@
+package preponderous.viron.exceptions;
+
+public class InvalidRequestException extends RuntimeException {
+ public InvalidRequestException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/preponderous/viron/mappers/EntityMapper.java b/src/main/java/preponderous/viron/mappers/EntityMapper.java
new file mode 100644
index 0000000..2ee4498
--- /dev/null
+++ b/src/main/java/preponderous/viron/mappers/EntityMapper.java
@@ -0,0 +1,14 @@
+package preponderous.viron.mappers;
+
+import org.mapstruct.Mapper;
+import preponderous.viron.dto.EntityDto;
+import preponderous.viron.models.Entity;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface EntityMapper {
+ EntityDto toDto(Entity entity);
+ Entity toEntity(EntityDto dto);
+ List toDtoList(List entities);
+}
diff --git a/src/main/java/preponderous/viron/mappers/EnvironmentMapper.java b/src/main/java/preponderous/viron/mappers/EnvironmentMapper.java
new file mode 100644
index 0000000..4af9fde
--- /dev/null
+++ b/src/main/java/preponderous/viron/mappers/EnvironmentMapper.java
@@ -0,0 +1,14 @@
+package preponderous.viron.mappers;
+
+import org.mapstruct.Mapper;
+import preponderous.viron.dto.EnvironmentDto;
+import preponderous.viron.models.Environment;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface EnvironmentMapper {
+ EnvironmentDto toDto(Environment environment);
+ Environment toEnvironment(EnvironmentDto dto);
+ List toDtoList(List environments);
+}
diff --git a/src/main/java/preponderous/viron/mappers/GridMapper.java b/src/main/java/preponderous/viron/mappers/GridMapper.java
new file mode 100644
index 0000000..05a9e7f
--- /dev/null
+++ b/src/main/java/preponderous/viron/mappers/GridMapper.java
@@ -0,0 +1,14 @@
+package preponderous.viron.mappers;
+
+import org.mapstruct.Mapper;
+import preponderous.viron.dto.GridDto;
+import preponderous.viron.models.Grid;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface GridMapper {
+ GridDto toDto(Grid grid);
+ Grid toGrid(GridDto dto);
+ List toDtoList(List grids);
+}
diff --git a/src/main/java/preponderous/viron/mappers/LocationMapper.java b/src/main/java/preponderous/viron/mappers/LocationMapper.java
new file mode 100644
index 0000000..80b6d3c
--- /dev/null
+++ b/src/main/java/preponderous/viron/mappers/LocationMapper.java
@@ -0,0 +1,14 @@
+package preponderous.viron.mappers;
+
+import org.mapstruct.Mapper;
+import preponderous.viron.dto.LocationDto;
+import preponderous.viron.models.Location;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface LocationMapper {
+ LocationDto toDto(Location location);
+ Location toLocation(LocationDto dto);
+ List toDtoList(List locations);
+}
diff --git a/src/test/java/preponderous/viron/controllers/DebugControllerTest.java b/src/test/java/preponderous/viron/controllers/DebugControllerTest.java
index 9305dc4..8b9c09a 100644
--- a/src/test/java/preponderous/viron/controllers/DebugControllerTest.java
+++ b/src/test/java/preponderous/viron/controllers/DebugControllerTest.java
@@ -1,43 +1,207 @@
package preponderous.viron.controllers;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.mock;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.web.servlet.MockMvc;
+import preponderous.viron.config.DbConfig;
+import preponderous.viron.database.DbInteractions;
+import preponderous.viron.dto.EntityDto;
+import preponderous.viron.dto.EnvironmentDto;
+import preponderous.viron.exceptions.ServiceException;
+import preponderous.viron.mappers.EntityMapper;
+import preponderous.viron.mappers.EnvironmentMapper;
+import preponderous.viron.models.Entity;
+import preponderous.viron.models.Environment;
+import preponderous.viron.models.Grid;
+import preponderous.viron.models.Location;
import preponderous.viron.services.EntityService;
import preponderous.viron.services.EnvironmentService;
import preponderous.viron.services.GridService;
import preponderous.viron.services.LocationService;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
@SpringBootTest
-public class DebugControllerTest {
+@AutoConfigureMockMvc
+@DirtiesContext
+class DebugControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
- @Mock
+ @MockBean
private EntityService entityService;
- @Mock
+ @MockBean
private EnvironmentService environmentService;
- @Mock
+ @MockBean
private GridService gridService;
- @Mock
+ @MockBean
private LocationService locationService;
- @InjectMocks
- private DebugController debugController;
+ @MockBean
+ private EntityMapper entityMapper;
+
+ @MockBean
+ private EnvironmentMapper environmentMapper;
+
+ @MockBean
+ private DbInteractions dbInteractions;
+
+ @MockBean
+ private DbConfig dbConfig;
+
+ // --- POST /api/v1/debug/create-sample-data ---
+
+ @Test
+ void createSampleData_Success() throws Exception {
+ Environment environment = new Environment(1, "Sample Environment", "2024-01-01");
+ Grid grid = new Grid(1, 10, 10);
+ List locations = buildLocationGrid(10, 10);
+
+ when(environmentService.createEnvironment("Sample Environment", 1, 10)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(1)).thenReturn(List.of(grid));
+ when(locationService.getLocationsInGrid(1)).thenReturn(locations);
+ when(entityService.createEntity(anyString())).thenAnswer(invocation -> {
+ String name = invocation.getArgument(0);
+ return new Entity(name.hashCode(), name, "2024-01-01");
+ });
+ doNothing().when(locationService).addEntityToLocation(anyInt(), anyInt());
+
+ EnvironmentDto dto = new EnvironmentDto(1, "Sample Environment", "2024-01-01");
+ when(environmentMapper.toDto(environment)).thenReturn(dto);
- @BeforeEach
- public void setUp() {
- entityService = mock(EntityService.class);
- environmentService = mock(EnvironmentService.class);
- gridService = mock(GridService.class);
- locationService = mock(LocationService.class);
- debugController = new DebugController(entityService, environmentService, gridService, locationService);
+ mockMvc.perform(post("/api/v1/debug/create-sample-data"))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.environmentId").value(1))
+ .andExpect(jsonPath("$.name").value("Sample Environment"))
+ .andExpect(jsonPath("$.creationDate").value("2024-01-01"));
+
+ verify(environmentService).createEnvironment("Sample Environment", 1, 10);
+ verify(gridService).getGridsInEnvironment(1);
+ verify(locationService).getLocationsInGrid(1);
+ verify(entityService, times(10)).createEntity(anyString());
+ verify(locationService, times(10)).addEntityToLocation(anyInt(), anyInt());
+ verify(environmentMapper).toDto(environment);
+ }
+
+ @Test
+ void createSampleData_NoGrids_Returns400() throws Exception {
+ Environment environment = new Environment(5, "NoGridEnv", "2024-05-01");
+
+ when(environmentService.createEnvironment("Sample Environment", 1, 10)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(5)).thenReturn(List.of());
+
+ mockMvc.perform(post("/api/v1/debug/create-sample-data"))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.status").value(400))
+ .andExpect(jsonPath("$.message").value("No grids found in environment: 5"));
}
- // TODO: implement tests for DebugController methods
+ // --- POST /api/v1/debug/create-world-and-place-entity/{environmentName} ---
+
+ @Test
+ void createWorldAndPlaceEntity_Success() throws Exception {
+ Environment environment = new Environment(2, "TestWorld", "2024-02-01");
+ Grid grid = new Grid(5, 5, 5);
+ List locations = buildLocationGrid(5, 5);
+
+ when(environmentService.createEnvironment("TestWorld", 1, 5)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(2)).thenReturn(List.of(grid));
+ when(locationService.getLocationsInGrid(5)).thenReturn(locations);
+
+ Entity entity = new Entity(10, "Tom", "2024-02-01");
+ when(entityService.createEntity(anyString())).thenReturn(entity);
+ doNothing().when(locationService).addEntityToLocation(anyInt(), anyInt());
+
+ EntityDto dto = new EntityDto(10, "Tom", "2024-02-01");
+ when(entityMapper.toDto(entity)).thenReturn(dto);
+
+ mockMvc.perform(post("/api/v1/debug/create-world-and-place-entity/TestWorld"))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.entityId").value(10))
+ .andExpect(jsonPath("$.name").value("Tom"))
+ .andExpect(jsonPath("$.creationDate").value("2024-02-01"));
+
+ verify(environmentService).createEnvironment("TestWorld", 1, 5);
+ verify(gridService).getGridsInEnvironment(2);
+ verify(entityService).createEntity(anyString());
+ verify(locationService).getLocationsInGrid(5);
+ verify(locationService).addEntityToLocation(eq(10), anyInt());
+ verify(entityMapper).toDto(entity);
+ }
+
+ @Test
+ void createWorldAndPlaceEntity_ServiceException_Returns500() throws Exception {
+ Environment environment = new Environment(3, "FailWorld", "2024-03-01");
+ Grid grid = new Grid(6, 5, 5);
+
+ when(environmentService.createEnvironment("FailWorld", 1, 5)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(3)).thenReturn(List.of(grid));
+ when(entityService.createEntity(anyString())).thenThrow(new ServiceException("Entity creation failed"));
+
+ mockMvc.perform(post("/api/v1/debug/create-world-and-place-entity/FailWorld"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").value("Entity creation failed"));
+ }
+
+ @Test
+ void createWorldAndPlaceEntity_NoGrids_Returns400() throws Exception {
+ Environment environment = new Environment(6, "NoGridWorld", "2024-06-01");
+
+ when(environmentService.createEnvironment("NoGridWorld", 1, 5)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(6)).thenReturn(List.of());
+
+ mockMvc.perform(post("/api/v1/debug/create-world-and-place-entity/NoGridWorld"))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.status").value(400))
+ .andExpect(jsonPath("$.message").value("No grids found in environment: 6"));
+ }
+
+ @Test
+ void createWorldAndPlaceEntity_NoValidLocation_Returns400() throws Exception {
+ Environment environment = new Environment(4, "EmptyWorld", "2024-04-01");
+ Grid grid = new Grid(7, 5, 5);
+
+ when(environmentService.createEnvironment("EmptyWorld", 1, 5)).thenReturn(environment);
+ when(gridService.getGridsInEnvironment(4)).thenReturn(List.of(grid));
+
+ Entity entity = new Entity(20, "Jerry", "2024-04-01");
+ when(entityService.createEntity(anyString())).thenReturn(entity);
+ // Return an empty location list so no valid location can be found
+ when(locationService.getLocationsInGrid(7)).thenReturn(List.of());
+
+ mockMvc.perform(post("/api/v1/debug/create-world-and-place-entity/EmptyWorld"))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.status").value(400))
+ .andExpect(jsonPath("$.message").isString());
+ }
+
+ /**
+ * Builds a list of locations covering all coordinates in a grid of the given size.
+ * Location IDs are assigned sequentially starting from 1.
+ */
+ private List buildLocationGrid(int rows, int columns) {
+ List locations = new ArrayList<>();
+ int id = 1;
+ for (int x = 0; x < rows; x++) {
+ for (int y = 0; y < columns; y++) {
+ locations.add(new Location(id++, x, y));
+ }
+ }
+ return locations;
+ }
}
\ No newline at end of file
diff --git a/src/test/java/preponderous/viron/controllers/EntityControllerTest.java b/src/test/java/preponderous/viron/controllers/EntityControllerTest.java
index f675be9..fdeee4b 100644
--- a/src/test/java/preponderous/viron/controllers/EntityControllerTest.java
+++ b/src/test/java/preponderous/viron/controllers/EntityControllerTest.java
@@ -1,236 +1,321 @@
package preponderous.viron.controllers;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.web.servlet.MockMvc;
+import preponderous.viron.config.DbConfig;
+import preponderous.viron.database.DbInteractions;
+import preponderous.viron.dto.EntityDto;
import preponderous.viron.exceptions.EntityCreationException;
import preponderous.viron.factories.EntityFactory;
+import preponderous.viron.mappers.EntityMapper;
import preponderous.viron.models.Entity;
import preponderous.viron.repositories.EntityRepository;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
+@AutoConfigureMockMvc
+@DirtiesContext
class EntityControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
private EntityRepository entityRepository;
+
+ @MockBean
private EntityFactory entityFactory;
- private EntityController entityController;
- @BeforeEach
- void setUp() {
- entityRepository = Mockito.mock(EntityRepository.class);
- entityFactory = Mockito.mock(EntityFactory.class);
- entityController = new EntityController(entityRepository, entityFactory);
- }
+ @MockBean
+ private EntityMapper entityMapper;
+
+ @MockBean
+ private DbInteractions dbInteractions;
+
+ @MockBean
+ private DbConfig dbConfig;
+
+ // --- GET /api/v1/entities ---
@Test
- void getAllEntities_Success() {
- // prepare
+ void getAllEntities_Success() throws Exception {
List entities = List.of(
new Entity(1, "Entity1", "2024-01-01"),
new Entity(2, "Entity2", "2024-01-01")
);
+ List dtos = List.of(
+ new EntityDto(1, "Entity1", "2024-01-01"),
+ new EntityDto(2, "Entity2", "2024-01-01")
+ );
when(entityRepository.findAll()).thenReturn(entities);
+ when(entityMapper.toDtoList(entities)).thenReturn(dtos);
- // execute
- ResponseEntity> response = entityController.getAllEntities();
+ mockMvc.perform(get("/api/v1/entities"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$[0].entityId").value(1))
+ .andExpect(jsonPath("$[0].name").value("Entity1"))
+ .andExpect(jsonPath("$[0].creationDate").value("2024-01-01"))
+ .andExpect(jsonPath("$[1].entityId").value(2))
+ .andExpect(jsonPath("$[1].name").value("Entity2"));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entities, response.getBody());
verify(entityRepository).findAll();
+ verify(entityMapper).toDtoList(entities);
}
@Test
- void getAllEntities_Exception() {
- // prepare
- when(entityRepository.findAll()).thenThrow(new RuntimeException("Database error"));
+ void getAllEntities_EmptyList() throws Exception {
+ when(entityRepository.findAll()).thenReturn(Collections.emptyList());
+ when(entityMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
+
+ mockMvc.perform(get("/api/v1/entities"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
+ }
- // execute
- ResponseEntity> response = entityController.getAllEntities();
+ @Test
+ void getAllEntities_RepositoryThrowsException() throws Exception {
+ when(entityRepository.findAll()).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/entities"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/entities/{id} ---
+
@Test
- void getEntityById_Success() {
- // prepare
+ void getEntityById_Success() throws Exception {
Entity entity = new Entity(1, "Entity1", "2024-01-01");
+ EntityDto dto = new EntityDto(1, "Entity1", "2024-01-01");
when(entityRepository.findById(1)).thenReturn(Optional.of(entity));
+ when(entityMapper.toDto(entity)).thenReturn(dto);
- // execute
- ResponseEntity response = entityController.getEntityById(1);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entity, response.getBody());
+ mockMvc.perform(get("/api/v1/entities/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.entityId").value(1))
+ .andExpect(jsonPath("$.name").value("Entity1"))
+ .andExpect(jsonPath("$.creationDate").value("2024-01-01"));
}
@Test
- void getEntityById_NotFound() {
- // prepare
- when(entityRepository.findById(anyInt())).thenReturn(Optional.empty());
+ void getEntityById_NotFound() throws Exception {
+ when(entityRepository.findById(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = entityController.getEntityById(1);
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
+ mockMvc.perform(get("/api/v1/entities/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Entity not found with id: 999"));
}
@Test
- void getEntitiesInEnvironment_Success() {
- // prepare
- List entities = new ArrayList<>();
- when(entityRepository.findByEnvironmentId(anyInt())).thenReturn(entities);
-
- // execute
- ResponseEntity> response = entityController.getEntitiesInEnvironment(1);
+ void getEntityById_RepositoryThrowsException() throws Exception {
+ when(entityRepository.findById(1)).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entities, response.getBody());
+ mockMvc.perform(get("/api/v1/entities/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/entities/environment/{environmentId} ---
+
@Test
- void getEntitiesInGrid_Success() {
- // prepare
- List entities = new ArrayList<>();
- when(entityRepository.findByGridId(anyInt())).thenReturn(entities);
+ void getEntitiesInEnvironment_Success() throws Exception {
+ List entities = List.of(new Entity(1, "Entity1", "2024-01-01"));
+ List dtos = List.of(new EntityDto(1, "Entity1", "2024-01-01"));
+ when(entityRepository.findByEnvironmentId(1)).thenReturn(entities);
+ when(entityMapper.toDtoList(entities)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/entities/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].entityId").value(1));
+ }
- // execute
- ResponseEntity> response = entityController.getEntitiesInGrid(1);
+ @Test
+ void getEntitiesInEnvironment_EmptyList() throws Exception {
+ when(entityRepository.findByEnvironmentId(1)).thenReturn(Collections.emptyList());
+ when(entityMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entities, response.getBody());
+ mockMvc.perform(get("/api/v1/entities/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
}
+ // --- GET /api/v1/entities/grid/{gridId} ---
+
@Test
- void getEntitiesInLocation_Success() {
- // prepare
- List entities = new ArrayList<>();
- when(entityRepository.findByLocationId(anyInt())).thenReturn(entities);
+ void getEntitiesInGrid_Success() throws Exception {
+ List entities = List.of(new Entity(2, "GridEntity", "2024-02-01"));
+ List dtos = List.of(new EntityDto(2, "GridEntity", "2024-02-01"));
+ when(entityRepository.findByGridId(5)).thenReturn(entities);
+ when(entityMapper.toDtoList(entities)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/entities/grid/5"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].entityId").value(2))
+ .andExpect(jsonPath("$[0].name").value("GridEntity"));
+ }
- // execute
- ResponseEntity> response = entityController.getEntitiesInLocation(1);
+ // --- GET /api/v1/entities/location/{locationId} ---
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entities, response.getBody());
+ @Test
+ void getEntitiesInLocation_Success() throws Exception {
+ List entities = List.of(new Entity(3, "LocEntity", "2024-03-01"));
+ List dtos = List.of(new EntityDto(3, "LocEntity", "2024-03-01"));
+ when(entityRepository.findByLocationId(10)).thenReturn(entities);
+ when(entityMapper.toDtoList(entities)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/entities/location/10"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].entityId").value(3))
+ .andExpect(jsonPath("$[0].name").value("LocEntity"));
}
+ // --- GET /api/v1/entities/unassigned ---
+
@Test
- void getEntitiesNotInAnyLocation_Success() {
- // prepare
- List entities = new ArrayList<>();
+ void getEntitiesNotInAnyLocation_Success() throws Exception {
+ List entities = List.of(new Entity(4, "Unassigned", "2024-04-01"));
+ List dtos = List.of(new EntityDto(4, "Unassigned", "2024-04-01"));
when(entityRepository.findEntitiesNotInAnyLocation()).thenReturn(entities);
+ when(entityMapper.toDtoList(entities)).thenReturn(dtos);
- // execute
- ResponseEntity> response = entityController.getEntitiesNotInAnyLocation();
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entities, response.getBody());
+ mockMvc.perform(get("/api/v1/entities/unassigned"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].entityId").value(4))
+ .andExpect(jsonPath("$[0].name").value("Unassigned"));
}
@Test
- void createEntity_Success() throws EntityCreationException {
- // prepare
- Entity entity = new Entity(1, "New Entity", "2024-01-01");
- when(entityFactory.createEntity(anyString())).thenReturn(entity);
+ void getEntitiesNotInAnyLocation_EmptyList() throws Exception {
+ when(entityRepository.findEntitiesNotInAnyLocation()).thenReturn(Collections.emptyList());
+ when(entityMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // execute
- ResponseEntity response = entityController.createEntity("New Entity");
+ mockMvc.perform(get("/api/v1/entities/unassigned"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
+ }
+
+ // --- POST /api/v1/entities/{name} ---
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(entity, response.getBody());
+ @Test
+ void createEntity_ReturnsCreated() throws Exception {
+ Entity entity = new Entity(1, "NewEntity", "2024-01-01");
+ EntityDto dto = new EntityDto(1, "NewEntity", "2024-01-01");
+ when(entityFactory.createEntity("NewEntity")).thenReturn(entity);
+ when(entityMapper.toDto(entity)).thenReturn(dto);
+
+ mockMvc.perform(post("/api/v1/entities/NewEntity"))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.entityId").value(1))
+ .andExpect(jsonPath("$.name").value("NewEntity"))
+ .andExpect(jsonPath("$.creationDate").value("2024-01-01"));
}
@Test
- void createEntity_EntityCreationException() throws EntityCreationException {
- // prepare
- when(entityFactory.createEntity(anyString()))
+ void createEntity_FactoryThrowsEntityCreationException() throws Exception {
+ when(entityFactory.createEntity("BadEntity"))
.thenThrow(new EntityCreationException("Creation failed"));
- // execute
- ResponseEntity response = entityController.createEntity("New Entity");
-
- // verify
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
+ mockMvc.perform(post("/api/v1/entities/BadEntity"))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.status").value(400))
+ .andExpect(jsonPath("$.message").value("Creation failed"));
}
@Test
- void deleteEntity_Success() {
- // prepare
- when(entityRepository.deleteById(anyInt())).thenReturn(true);
-
- // execute
- ResponseEntity response = entityController.deleteEntity(1);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
+ void createEntity_FactoryThrowsRuntimeException() throws Exception {
+ when(entityFactory.createEntity("ErrorEntity"))
+ .thenThrow(new RuntimeException("Unexpected error"));
+
+ mockMvc.perform(post("/api/v1/entities/ErrorEntity"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
- @Test
- void deleteEntity_NotFound() {
- // prepare
- when(entityRepository.deleteById(anyInt())).thenReturn(false);
+ // --- DELETE /api/v1/entities/{id} ---
- // execute
- ResponseEntity response = entityController.deleteEntity(1);
+ @Test
+ void deleteEntity_ReturnsNoContent() throws Exception {
+ when(entityRepository.findById(1)).thenReturn(Optional.of(new Entity(1, "Entity1", "2024-01-01")));
+ when(entityRepository.deleteById(1)).thenReturn(true);
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
+ mockMvc.perform(delete("/api/v1/entities/1"))
+ .andExpect(status().isNoContent());
}
@Test
- void updateEntityName_Success() {
- // prepare
- when(entityRepository.updateName(anyInt(), anyString())).thenReturn(true);
+ void deleteEntity_NotFound() throws Exception {
+ when(entityRepository.findById(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = entityController.updateEntityName(1, "New Name");
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
+ mockMvc.perform(delete("/api/v1/entities/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Entity not found with id: 999"));
}
@Test
- void updateEntityName_NotFound() {
- // prepare
- when(entityRepository.updateName(anyInt(), anyString())).thenReturn(false);
+ void deleteEntity_RepositoryThrowsException() throws Exception {
+ when(entityRepository.findById(1)).thenReturn(Optional.of(new Entity(1, "Entity1", "2024-01-01")));
+ when(entityRepository.deleteById(1)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(delete("/api/v1/entities/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
+ }
- // execute
- ResponseEntity response = entityController.updateEntityName(1, "New Name");
+ // --- PATCH /api/v1/entities/{id}/name/{name} ---
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
+ @Test
+ void updateEntityName_Success() throws Exception {
+ when(entityRepository.findById(1)).thenReturn(Optional.of(new Entity(1, "OldName", "2024-01-01")));
+ when(entityRepository.updateName(1, "UpdatedName")).thenReturn(true);
+
+ mockMvc.perform(patch("/api/v1/entities/1/name/UpdatedName"))
+ .andExpect(status().isOk());
}
@Test
- void testExceptionHandling_InternalServerError() {
- // prepare
- when(entityRepository.findAll()).thenThrow(new RuntimeException("Unexpected error"));
+ void updateEntityName_NotFound() throws Exception {
+ when(entityRepository.findById(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity> response = entityController.getAllEntities();
+ mockMvc.perform(patch("/api/v1/entities/999/name/UpdatedName"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Entity not found with id: 999"));
+ }
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ @Test
+ void updateEntityName_RepositoryThrowsException() throws Exception {
+ when(entityRepository.findById(1)).thenReturn(Optional.of(new Entity(1, "OldName", "2024-01-01")));
+ when(entityRepository.updateName(1, "Name")).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(patch("/api/v1/entities/1/name/Name"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
}
\ No newline at end of file
diff --git a/src/test/java/preponderous/viron/controllers/EnvironmentControllerTest.java b/src/test/java/preponderous/viron/controllers/EnvironmentControllerTest.java
index 019d353..1e89233 100644
--- a/src/test/java/preponderous/viron/controllers/EnvironmentControllerTest.java
+++ b/src/test/java/preponderous/viron/controllers/EnvironmentControllerTest.java
@@ -1,211 +1,240 @@
package preponderous.viron.controllers;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.web.servlet.MockMvc;
+import preponderous.viron.config.DbConfig;
+import preponderous.viron.database.DbInteractions;
+import preponderous.viron.dto.EnvironmentDto;
import preponderous.viron.exceptions.EnvironmentCreationException;
import preponderous.viron.factories.EnvironmentFactory;
+import preponderous.viron.mappers.EnvironmentMapper;
import preponderous.viron.models.Environment;
import preponderous.viron.repositories.EnvironmentRepository;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.hamcrest.Matchers.*;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
+@AutoConfigureMockMvc
+@DirtiesContext
class EnvironmentControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
private EnvironmentRepository environmentRepository;
+
+ @MockBean
private EnvironmentFactory environmentFactory;
- private EnvironmentController environmentController;
- @BeforeEach
- void setUp() {
- environmentRepository = Mockito.mock(EnvironmentRepository.class);
- environmentFactory = Mockito.mock(EnvironmentFactory.class);
- environmentController = new EnvironmentController(environmentRepository, environmentFactory);
- }
+ @MockBean
+ private EnvironmentMapper environmentMapper;
+
+ @MockBean
+ private DbInteractions dbInteractions;
+
+ @MockBean
+ private DbConfig dbConfig;
@Test
- void getAllEnvironments_Success() {
- // setup
+ void getAllEnvironments_Success() throws Exception {
List environments = Arrays.asList(
new Environment(1, "Env1", "2023-01-01"),
new Environment(2, "Env2", "2023-01-02")
);
+ List dtos = Arrays.asList(
+ new EnvironmentDto(1, "Env1", "2023-01-01"),
+ new EnvironmentDto(2, "Env2", "2023-01-02")
+ );
when(environmentRepository.findAll()).thenReturn(environments);
+ when(environmentMapper.toDtoList(environments)).thenReturn(dtos);
- // execute
- ResponseEntity> response = environmentController.getAllEnvironments();
+ mockMvc.perform(get("/api/v1/environments"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$[0].environmentId", is(1)))
+ .andExpect(jsonPath("$[0].name", is("Env1")))
+ .andExpect(jsonPath("$[0].creationDate", is("2023-01-01")))
+ .andExpect(jsonPath("$[1].environmentId", is(2)))
+ .andExpect(jsonPath("$[1].name", is("Env2")));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- assertEquals(2, response.getBody().size());
verify(environmentRepository).findAll();
+ verify(environmentMapper).toDtoList(environments);
}
@Test
- void getAllEnvironments_ThrowsException() {
- // setup
- when(environmentRepository.findAll()).thenThrow(new RuntimeException("Database error"));
+ void getAllEnvironments_EmptyList() throws Exception {
+ when(environmentRepository.findAll()).thenReturn(Collections.emptyList());
+ when(environmentMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // execute
- ResponseEntity> response = environmentController.getAllEnvironments();
+ mockMvc.perform(get("/api/v1/environments"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
verify(environmentRepository).findAll();
}
@Test
- void getEnvironmentById_Success() {
- // setup
+ void getAllEnvironments_ThrowsException() throws Exception {
+ when(environmentRepository.findAll()).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(get("/api/v1/environments"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status", is(500)))
+ .andExpect(jsonPath("$.message", is("An unexpected error occurred")));
+ }
+
+ @Test
+ void getEnvironmentById_Success() throws Exception {
Environment environment = new Environment(1, "Env1", "2023-01-01");
+ EnvironmentDto dto = new EnvironmentDto(1, "Env1", "2023-01-01");
when(environmentRepository.findById(1)).thenReturn(Optional.of(environment));
+ when(environmentMapper.toDto(environment)).thenReturn(dto);
- // execute
- ResponseEntity response = environmentController.getEnvironmentById(1);
+ mockMvc.perform(get("/api/v1/environments/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.environmentId", is(1)))
+ .andExpect(jsonPath("$.name", is("Env1")))
+ .andExpect(jsonPath("$.creationDate", is("2023-01-01")));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- assertEquals("Env1", response.getBody().getName());
verify(environmentRepository).findById(1);
+ verify(environmentMapper).toDto(environment);
}
@Test
- void getEnvironmentById_NotFound() {
- // setup
+ void getEnvironmentById_NotFound() throws Exception {
when(environmentRepository.findById(1)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = environmentController.getEnvironmentById(1);
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
- verify(environmentRepository).findById(1);
+ mockMvc.perform(get("/api/v1/environments/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status", is(404)))
+ .andExpect(jsonPath("$.message", is("Environment not found with id: 1")));
}
@Test
- void getEnvironmentById_ThrowsException() {
- // setup
+ void getEnvironmentById_ThrowsException() throws Exception {
when(environmentRepository.findById(1)).thenThrow(new RuntimeException("Database error"));
- // execute
- ResponseEntity response = environmentController.getEnvironmentById(1);
-
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
- verify(environmentRepository).findById(1);
+ mockMvc.perform(get("/api/v1/environments/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status", is(500)))
+ .andExpect(jsonPath("$.message", is("An unexpected error occurred")));
}
@Test
- void getEnvironmentByName_Success() {
- // setup
+ void getEnvironmentByName_Success() throws Exception {
Environment environment = new Environment(1, "Env1", "2023-01-01");
+ EnvironmentDto dto = new EnvironmentDto(1, "Env1", "2023-01-01");
when(environmentRepository.findByName("Env1")).thenReturn(Optional.of(environment));
+ when(environmentMapper.toDto(environment)).thenReturn(dto);
- // execute
- ResponseEntity response = environmentController.getEnvironmentByName("Env1");
+ mockMvc.perform(get("/api/v1/environments/name/Env1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.environmentId", is(1)))
+ .andExpect(jsonPath("$.name", is("Env1")))
+ .andExpect(jsonPath("$.creationDate", is("2023-01-01")));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- assertEquals("Env1", response.getBody().getName());
verify(environmentRepository).findByName("Env1");
+ verify(environmentMapper).toDto(environment);
}
@Test
- void getEnvironmentByName_NotFound() {
- // setup
+ void getEnvironmentByName_NotFound() throws Exception {
when(environmentRepository.findByName("NonExistent")).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = environmentController.getEnvironmentByName("NonExistent");
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
- verify(environmentRepository).findByName("NonExistent");
+ mockMvc.perform(get("/api/v1/environments/name/NonExistent"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status", is(404)))
+ .andExpect(jsonPath("$.message", is("Environment not found with name: NonExistent")));
}
@Test
- void getEnvironmentOfEntity_Success() {
- // setup
+ void getEnvironmentOfEntity_Success() throws Exception {
Environment environment = new Environment(1, "Env1", "2023-01-01");
+ EnvironmentDto dto = new EnvironmentDto(1, "Env1", "2023-01-01");
when(environmentRepository.findByEntityId(1)).thenReturn(Optional.of(environment));
+ when(environmentMapper.toDto(environment)).thenReturn(dto);
- // execute
- ResponseEntity response = environmentController.getEnvironmentOfEntity(1);
+ mockMvc.perform(get("/api/v1/environments/entity/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.environmentId", is(1)))
+ .andExpect(jsonPath("$.name", is("Env1")))
+ .andExpect(jsonPath("$.creationDate", is("2023-01-01")));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- assertEquals("Env1", response.getBody().getName());
verify(environmentRepository).findByEntityId(1);
+ verify(environmentMapper).toDto(environment);
}
@Test
- void getEnvironmentOfEntity_NotFound() {
- // setup
+ void getEnvironmentOfEntity_NotFound() throws Exception {
when(environmentRepository.findByEntityId(1)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = environmentController.getEnvironmentOfEntity(1);
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
- verify(environmentRepository).findByEntityId(1);
+ mockMvc.perform(get("/api/v1/environments/entity/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status", is(404)))
+ .andExpect(jsonPath("$.message", is("Environment not found for entity: 1")));
}
@Test
- void createEnvironment_Success() throws EnvironmentCreationException {
- // setup
+ void createEnvironment_Success() throws Exception {
Environment environment = new Environment(1, "NewEnv", "2023-01-01");
+ EnvironmentDto dto = new EnvironmentDto(1, "NewEnv", "2023-01-01");
when(environmentFactory.createEnvironment("NewEnv", 5, 10)).thenReturn(environment);
+ when(environmentMapper.toDto(environment)).thenReturn(dto);
- // execute
- ResponseEntity response = environmentController.createEnvironment("NewEnv", 5, 10);
+ mockMvc.perform(post("/api/v1/environments/NewEnv/5/10"))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.environmentId", is(1)))
+ .andExpect(jsonPath("$.name", is("NewEnv")))
+ .andExpect(jsonPath("$.creationDate", is("2023-01-01")));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertNotNull(response.getBody());
- assertEquals("NewEnv", response.getBody().getName());
verify(environmentFactory).createEnvironment("NewEnv", 5, 10);
+ verify(environmentMapper).toDto(environment);
}
@Test
- void createEnvironment_CreationException() throws EnvironmentCreationException {
- // setup
+ void createEnvironment_CreationException() throws Exception {
when(environmentFactory.createEnvironment("NewEnv", 5, 10))
.thenThrow(new EnvironmentCreationException("Creation failed"));
- // execute
- ResponseEntity response = environmentController.createEnvironment("NewEnv", 5, 10);
+ mockMvc.perform(post("/api/v1/environments/NewEnv/5/10"))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.status", is(400)))
+ .andExpect(jsonPath("$.message", is("Creation failed")));
+ }
- // verify
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertNull(response.getBody());
- verify(environmentFactory).createEnvironment("NewEnv", 5, 10);
+ @Test
+ void createEnvironment_ThrowsException() throws Exception {
+ when(environmentFactory.createEnvironment("NewEnv", 5, 10))
+ .thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(post("/api/v1/environments/NewEnv/5/10"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status", is(500)))
+ .andExpect(jsonPath("$.message", is("An unexpected error occurred")));
}
@Test
- void deleteEnvironment_Success() {
- // setup
- when(environmentRepository.findById(1)).thenReturn(Optional.of(new Environment(1, "Env1", "2023-01-01")));
- when(environmentRepository.findEntityIdsByEnvironmentId(1)).thenReturn(Arrays.asList(1, 2));
- when(environmentRepository.findLocationIdsByEnvironmentId(1)).thenReturn(Arrays.asList(3, 4));
- when(environmentRepository.findGridIdsByEnvironmentId(1)).thenReturn(Arrays.asList(5, 6));
+ void deleteEnvironment_Success() throws Exception {
+ Environment env = new Environment(1, "Env1", "2023-01-01");
+ when(environmentRepository.findById(1)).thenReturn(Optional.of(env));
+ when(environmentRepository.findEntityIdsByEnvironmentId(1)).thenReturn(List.of(1, 2));
+ when(environmentRepository.findLocationIdsByEnvironmentId(1)).thenReturn(List.of(3, 4));
+ when(environmentRepository.findGridIdsByEnvironmentId(1)).thenReturn(List.of(5));
when(environmentRepository.deleteEntityLocation(anyInt())).thenReturn(true);
when(environmentRepository.deleteLocationGrid(anyInt())).thenReturn(true);
when(environmentRepository.deleteGridEnvironment(anyInt())).thenReturn(true);
@@ -214,65 +243,55 @@ void deleteEnvironment_Success() {
when(environmentRepository.deleteGrid(anyInt())).thenReturn(true);
when(environmentRepository.deleteById(1)).thenReturn(true);
- // execute
- ResponseEntity response = environmentController.deleteEnvironment(1);
+ mockMvc.perform(delete("/api/v1/environments/1"))
+ .andExpect(status().isNoContent());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
verify(environmentRepository).deleteById(1);
}
@Test
- void deleteEnvironment_NotFound() {
- // setup
+ void deleteEnvironment_NotFound() throws Exception {
when(environmentRepository.findById(1)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = environmentController.deleteEnvironment(1);
+ mockMvc.perform(delete("/api/v1/environments/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status", is(404)))
+ .andExpect(jsonPath("$.message", is("Environment not found with id: 1")));
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
verify(environmentRepository, never()).deleteById(anyInt());
}
@Test
- void updateEnvironmentName_Success() {
- // setup
+ void updateEnvironmentName_Success() throws Exception {
when(environmentRepository.findById(1)).thenReturn(Optional.of(new Environment(1, "OldName", "2023-01-01")));
when(environmentRepository.updateName(1, "NewName")).thenReturn(true);
- // execute
- ResponseEntity response = environmentController.updateEnvironmentName(1, "NewName");
+ mockMvc.perform(patch("/api/v1/environments/1/name/NewName"))
+ .andExpect(status().isOk());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
verify(environmentRepository).updateName(1, "NewName");
}
@Test
- void updateEnvironmentName_NotFound() {
- // setup
+ void updateEnvironmentName_NotFound() throws Exception {
when(environmentRepository.findById(1)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = environmentController.updateEnvironmentName(1, "NewName");
+ mockMvc.perform(patch("/api/v1/environments/1/name/NewName"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status", is(404)))
+ .andExpect(jsonPath("$.message", is("Environment not found with id: 1")));
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
verify(environmentRepository, never()).updateName(anyInt(), anyString());
}
@Test
- void updateEnvironmentName_ThrowsException() {
- // setup
+ void updateEnvironmentName_ThrowsException() throws Exception {
when(environmentRepository.findById(1)).thenReturn(Optional.of(new Environment(1, "OldName", "2023-01-01")));
when(environmentRepository.updateName(1, "NewName")).thenThrow(new RuntimeException("Database error"));
- // execute
- ResponseEntity response = environmentController.updateEnvironmentName(1, "NewName");
-
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- verify(environmentRepository).updateName(1, "NewName");
+ mockMvc.perform(patch("/api/v1/environments/1/name/NewName"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status", is(500)))
+ .andExpect(jsonPath("$.message", is("An unexpected error occurred")));
}
}
\ No newline at end of file
diff --git a/src/test/java/preponderous/viron/controllers/GridControllerTest.java b/src/test/java/preponderous/viron/controllers/GridControllerTest.java
index 48eef5d..47ae6c9 100644
--- a/src/test/java/preponderous/viron/controllers/GridControllerTest.java
+++ b/src/test/java/preponderous/viron/controllers/GridControllerTest.java
@@ -1,190 +1,202 @@
package preponderous.viron.controllers;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.web.servlet.MockMvc;
+import preponderous.viron.config.DbConfig;
+import preponderous.viron.database.DbInteractions;
+import preponderous.viron.dto.GridDto;
+import preponderous.viron.mappers.GridMapper;
import preponderous.viron.models.Grid;
import preponderous.viron.repositories.GridRepository;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.when;
+import static org.hamcrest.Matchers.*;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
-public class GridControllerTest {
+@AutoConfigureMockMvc
+@DirtiesContext
+class GridControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
private GridRepository gridRepository;
- private GridController gridController;
- @BeforeEach
- void setUp() {
- gridRepository = Mockito.mock(GridRepository.class);
- gridController = new GridController(gridRepository);
- }
+ @MockBean
+ private GridMapper gridMapper;
+
+ @MockBean
+ private DbInteractions dbInteractions;
+
+ @MockBean
+ private DbConfig dbConfig;
+
+ // --- GET /api/v1/grids ---
@Test
- void testGetAllGrids_Success() {
- // setup
- Grid grid1 = new Grid(1, 1, 1);
- Grid grid2 = new Grid(2, 2, 2);
- List expectedGrids = Arrays.asList(grid1, grid2);
- when(gridRepository.findAll()).thenReturn(expectedGrids);
-
- // execute
- ResponseEntity> response = gridController.getAllGrids();
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(expectedGrids, response.getBody());
+ void getAllGrids_Success() throws Exception {
+ List grids = List.of(
+ new Grid(1, 10, 20),
+ new Grid(2, 30, 40)
+ );
+ List dtos = List.of(
+ new GridDto(1, 10, 20),
+ new GridDto(2, 30, 40)
+ );
+ when(gridRepository.findAll()).thenReturn(grids);
+ when(gridMapper.toDtoList(grids)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/grids"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$[0].gridId").value(1))
+ .andExpect(jsonPath("$[0].rows").value(10))
+ .andExpect(jsonPath("$[0].columns").value(20))
+ .andExpect(jsonPath("$[1].gridId").value(2))
+ .andExpect(jsonPath("$[1].rows").value(30))
+ .andExpect(jsonPath("$[1].columns").value(40));
+
+ verify(gridRepository).findAll();
+ verify(gridMapper).toDtoList(grids);
}
@Test
- void testGetAllGrids_Exception() {
- // setup
- when(gridRepository.findAll()).thenThrow(new RuntimeException("Test Exception"));
+ void getAllGrids_RepositoryThrowsException() throws Exception {
+ when(gridRepository.findAll()).thenThrow(new RuntimeException("Database error"));
- // execute
- ResponseEntity> response = gridController.getAllGrids();
-
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/grids/{id} ---
+
@Test
- void testGetGridById_Success() {
- // setup
- int gridId = 1;
- Grid expectedGrid = new Grid(gridId, 1, 1);
- when(gridRepository.findById(gridId)).thenReturn(Optional.of(expectedGrid));
-
- // execute
- ResponseEntity response = gridController.getGridById(gridId);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(expectedGrid, response.getBody());
+ void getGridById_Success() throws Exception {
+ Grid grid = new Grid(1, 10, 20);
+ GridDto dto = new GridDto(1, 10, 20);
+ when(gridRepository.findById(1)).thenReturn(Optional.of(grid));
+ when(gridMapper.toDto(grid)).thenReturn(dto);
+
+ mockMvc.perform(get("/api/v1/grids/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.gridId").value(1))
+ .andExpect(jsonPath("$.rows").value(10))
+ .andExpect(jsonPath("$.columns").value(20));
+
+ verify(gridRepository).findById(1);
+ verify(gridMapper).toDto(grid);
}
@Test
- void testGetGridById_NotFound() {
- // setup
- int gridId = 1;
- when(gridRepository.findById(gridId)).thenReturn(Optional.empty());
+ void getGridById_NotFound() throws Exception {
+ when(gridRepository.findById(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = gridController.getGridById(gridId);
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Grid not found with id: 999"));
}
@Test
- void testGetGridById_Exception() {
- // setup
- int gridId = 1;
- when(gridRepository.findById(gridId)).thenThrow(new RuntimeException("Test Exception"));
-
- // execute
- ResponseEntity response = gridController.getGridById(gridId);
+ void getGridById_RepositoryThrowsException() throws Exception {
+ when(gridRepository.findById(1)).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/grids/environment/{environmentId} ---
+
@Test
- void testGetGridsInEnvironment_Success() {
- // setup
- int environmentId = 1;
- Grid grid1 = new Grid(1, 1, 1);
- Grid grid2 = new Grid(2, 2, 2);
- List expectedGrids = Arrays.asList(grid1, grid2);
- when(gridRepository.findByEnvironmentId(environmentId)).thenReturn(expectedGrids);
-
- // execute
- ResponseEntity> response = gridController.getGridsInEnvironment(environmentId);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(expectedGrids, response.getBody());
+ void getGridsInEnvironment_Success() throws Exception {
+ List grids = List.of(new Grid(1, 10, 20));
+ List dtos = List.of(new GridDto(1, 10, 20));
+ when(gridRepository.findByEnvironmentId(1)).thenReturn(grids);
+ when(gridMapper.toDtoList(grids)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/grids/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].gridId").value(1))
+ .andExpect(jsonPath("$[0].rows").value(10))
+ .andExpect(jsonPath("$[0].columns").value(20));
+
+ verify(gridRepository).findByEnvironmentId(1);
+ verify(gridMapper).toDtoList(grids);
}
@Test
- void testGetGridsInEnvironment_EmptyList() {
- // setup
- int environmentId = 1;
- when(gridRepository.findByEnvironmentId(environmentId)).thenReturn(Collections.emptyList());
-
- // execute
- ResponseEntity> response = gridController.getGridsInEnvironment(environmentId);
+ void getGridsInEnvironment_EmptyList() throws Exception {
+ when(gridRepository.findByEnvironmentId(1)).thenReturn(Collections.emptyList());
+ when(gridMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertTrue(response.getBody().isEmpty());
+ mockMvc.perform(get("/api/v1/grids/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
}
@Test
- void testGetGridsInEnvironment_Exception() {
- // setup
- int environmentId = 1;
- when(gridRepository.findByEnvironmentId(environmentId)).thenThrow(new RuntimeException("Test Exception"));
+ void getGridsInEnvironment_RepositoryThrowsException() throws Exception {
+ when(gridRepository.findByEnvironmentId(1)).thenThrow(new RuntimeException("Database error"));
- // execute
- ResponseEntity> response = gridController.getGridsInEnvironment(environmentId);
-
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids/environment/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/grids/entity/{entityId} ---
+
@Test
- void testGetGridOfEntity_Success() {
- // setup
- int entityId = 1;
- Grid expectedGrid = new Grid(1, 1, 1);
- when(gridRepository.findByEntityId(entityId)).thenReturn(Optional.of(expectedGrid));
-
- // execute
- ResponseEntity response = gridController.getGridOfEntity(entityId);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(expectedGrid, response.getBody());
+ void getGridOfEntity_Success() throws Exception {
+ Grid grid = new Grid(5, 15, 25);
+ GridDto dto = new GridDto(5, 15, 25);
+ when(gridRepository.findByEntityId(1)).thenReturn(Optional.of(grid));
+ when(gridMapper.toDto(grid)).thenReturn(dto);
+
+ mockMvc.perform(get("/api/v1/grids/entity/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.gridId").value(5))
+ .andExpect(jsonPath("$.rows").value(15))
+ .andExpect(jsonPath("$.columns").value(25));
+
+ verify(gridRepository).findByEntityId(1);
+ verify(gridMapper).toDto(grid);
}
@Test
- void testGetGridOfEntity_NotFound() {
- // setup
- int entityId = 1;
- when(gridRepository.findByEntityId(entityId)).thenReturn(Optional.empty());
+ void getGridOfEntity_NotFound() throws Exception {
+ when(gridRepository.findByEntityId(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = gridController.getGridOfEntity(entityId);
-
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids/entity/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Grid not found for entity: 999"));
}
@Test
- void testGetGridOfEntity_Exception() {
- // setup
- int entityId = 1;
- when(gridRepository.findByEntityId(entityId)).thenThrow(new RuntimeException("Test Exception"));
-
- // execute
- ResponseEntity response = gridController.getGridOfEntity(entityId);
+ void getGridOfEntity_RepositoryThrowsException() throws Exception {
+ when(gridRepository.findByEntityId(1)).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
+ mockMvc.perform(get("/api/v1/grids/entity/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
}
\ No newline at end of file
diff --git a/src/test/java/preponderous/viron/controllers/LocationControllerTest.java b/src/test/java/preponderous/viron/controllers/LocationControllerTest.java
index 351adac..eaf5d0f 100644
--- a/src/test/java/preponderous/viron/controllers/LocationControllerTest.java
+++ b/src/test/java/preponderous/viron/controllers/LocationControllerTest.java
@@ -1,267 +1,343 @@
package preponderous.viron.controllers;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.web.servlet.MockMvc;
+import preponderous.viron.config.DbConfig;
+import preponderous.viron.database.DbInteractions;
+import preponderous.viron.dto.LocationDto;
+import preponderous.viron.mappers.LocationMapper;
import preponderous.viron.models.Location;
import preponderous.viron.repositories.LocationRepository;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
+@AutoConfigureMockMvc
class LocationControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
private LocationRepository locationRepository;
- private LocationController locationController;
- @BeforeEach
- void setUp() {
- locationRepository = Mockito.mock(LocationRepository.class);
- locationController = new LocationController(locationRepository);
- }
+ @MockBean
+ private LocationMapper locationMapper;
+
+ @MockBean
+ private DbInteractions dbInteractions;
+
+ @MockBean
+ private DbConfig dbConfig;
+
+ // --- GET /api/v1/locations ---
@Test
- void getAllLocations_Success() {
- // setup
- List locations = Arrays.asList(
- new Location(1, 10, 20)
+ void getAllLocations_Success() throws Exception {
+ List locations = List.of(
+ new Location(1, 10, 20),
+ new Location(2, 30, 40)
+ );
+ List dtos = List.of(
+ new LocationDto(1, 10, 20),
+ new LocationDto(2, 30, 40)
);
when(locationRepository.findAll()).thenReturn(locations);
+ when(locationMapper.toDtoList(locations)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/locations"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(2)))
+ .andExpect(jsonPath("$[0].locationId").value(1))
+ .andExpect(jsonPath("$[0].x").value(10))
+ .andExpect(jsonPath("$[0].y").value(20))
+ .andExpect(jsonPath("$[1].locationId").value(2))
+ .andExpect(jsonPath("$[1].x").value(30))
+ .andExpect(jsonPath("$[1].y").value(40));
- // execute
- ResponseEntity> response = locationController.getAllLocations();
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(locations, response.getBody());
verify(locationRepository).findAll();
+ verify(locationMapper).toDtoList(locations);
}
@Test
- void getAllLocations_Exception() {
- // setup
- when(locationRepository.findAll()).thenThrow(new RuntimeException("Database error"));
+ void getAllLocations_EmptyList() throws Exception {
+ when(locationRepository.findAll()).thenReturn(Collections.emptyList());
+ when(locationMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // execute
- ResponseEntity> response = locationController.getAllLocations();
+ mockMvc.perform(get("/api/v1/locations"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
+ }
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
- verify(locationRepository).findAll();
+ @Test
+ void getAllLocations_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findAll()).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(get("/api/v1/locations"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/locations/{id} ---
+
@Test
- void getLocationById_Success() {
- // setup
+ void getLocationById_Success() throws Exception {
Location location = new Location(1, 10, 20);
+ LocationDto dto = new LocationDto(1, 10, 20);
when(locationRepository.findById(1)).thenReturn(Optional.of(location));
+ when(locationMapper.toDto(location)).thenReturn(dto);
- // execute
- ResponseEntity response = locationController.getLocationById(1);
+ mockMvc.perform(get("/api/v1/locations/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.locationId").value(1))
+ .andExpect(jsonPath("$.x").value(10))
+ .andExpect(jsonPath("$.y").value(20));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(location, response.getBody());
verify(locationRepository).findById(1);
+ verify(locationMapper).toDto(location);
}
@Test
- void getLocationById_NotFound() {
- // setup
- when(locationRepository.findById(1)).thenReturn(Optional.empty());
+ void getLocationById_NotFound() throws Exception {
+ when(locationRepository.findById(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = locationController.getLocationById(1);
+ mockMvc.perform(get("/api/v1/locations/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Location not found with id: 999"));
+ }
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
- verify(locationRepository).findById(1);
+ @Test
+ void getLocationById_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findById(1)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(get("/api/v1/locations/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/locations/environment/{environmentId} ---
+
@Test
- void getLocationsInEnvironment_Success() {
- // setup
- List locations = Arrays.asList(new Location(1, 10, 20));
+ void getLocationsInEnvironment_Success() throws Exception {
+ List locations = List.of(new Location(1, 10, 20));
+ List dtos = List.of(new LocationDto(1, 10, 20));
when(locationRepository.findByEnvironmentId(1)).thenReturn(locations);
+ when(locationMapper.toDtoList(locations)).thenReturn(dtos);
- // execute
- ResponseEntity> response = locationController.getLocationsInEnvironment(1);
+ mockMvc.perform(get("/api/v1/locations/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].locationId").value(1))
+ .andExpect(jsonPath("$[0].x").value(10))
+ .andExpect(jsonPath("$[0].y").value(20));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(locations, response.getBody());
verify(locationRepository).findByEnvironmentId(1);
+ verify(locationMapper).toDtoList(locations);
}
@Test
- void getLocationsInEnvironment_Exception() {
- // setup
- when(locationRepository.findByEnvironmentId(1)).thenThrow(new RuntimeException());
+ void getLocationsInEnvironment_EmptyList() throws Exception {
+ when(locationRepository.findByEnvironmentId(1)).thenReturn(Collections.emptyList());
+ when(locationMapper.toDtoList(Collections.emptyList())).thenReturn(Collections.emptyList());
- // execute
- ResponseEntity> response = locationController.getLocationsInEnvironment(1);
-
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
- verify(locationRepository).findByEnvironmentId(1);
+ mockMvc.perform(get("/api/v1/locations/environment/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(0)));
}
@Test
- void getLocationsInGrid_Success() {
- // setup
- List locations = Arrays.asList(new Location(1, 10, 20));
- when(locationRepository.findByGridId(1)).thenReturn(locations);
-
- // execute
- ResponseEntity> response = locationController.getLocationsInGrid(1);
-
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(locations, response.getBody());
- verify(locationRepository).findByGridId(1);
+ void getLocationsInEnvironment_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findByEnvironmentId(1)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(get("/api/v1/locations/environment/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/locations/grid/{gridId} ---
+
@Test
- void getLocationsInGrid_Exception() {
- // setup
- when(locationRepository.findByGridId(1)).thenThrow(new RuntimeException());
+ void getLocationsInGrid_Success() throws Exception {
+ List locations = List.of(new Location(5, 50, 60));
+ List dtos = List.of(new LocationDto(5, 50, 60));
+ when(locationRepository.findByGridId(3)).thenReturn(locations);
+ when(locationMapper.toDtoList(locations)).thenReturn(dtos);
+
+ mockMvc.perform(get("/api/v1/locations/grid/3"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].locationId").value(5))
+ .andExpect(jsonPath("$[0].x").value(50))
+ .andExpect(jsonPath("$[0].y").value(60));
+
+ verify(locationRepository).findByGridId(3);
+ verify(locationMapper).toDtoList(locations);
+ }
- // execute
- ResponseEntity> response = locationController.getLocationsInGrid(1);
+ @Test
+ void getLocationsInGrid_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findByGridId(1)).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- assertNull(response.getBody());
- verify(locationRepository).findByGridId(1);
+ mockMvc.perform(get("/api/v1/locations/grid/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- GET /api/v1/locations/entity/{entityId} ---
+
@Test
- void getLocationOfEntity_Success() {
- // setup
+ void getLocationOfEntity_Success() throws Exception {
Location location = new Location(1, 10, 20);
+ LocationDto dto = new LocationDto(1, 10, 20);
when(locationRepository.findByEntityId(1)).thenReturn(Optional.of(location));
+ when(locationMapper.toDto(location)).thenReturn(dto);
- // execute
- ResponseEntity response = locationController.getLocationOfEntity(1);
+ mockMvc.perform(get("/api/v1/locations/entity/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.locationId").value(1))
+ .andExpect(jsonPath("$.x").value(10))
+ .andExpect(jsonPath("$.y").value(20));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(location, response.getBody());
verify(locationRepository).findByEntityId(1);
+ verify(locationMapper).toDto(location);
}
@Test
- void getLocationOfEntity_NotFound() {
- // setup
- when(locationRepository.findByEntityId(1)).thenReturn(Optional.empty());
-
- // execute
- ResponseEntity response = locationController.getLocationOfEntity(1);
+ void getLocationOfEntity_NotFound() throws Exception {
+ when(locationRepository.findByEntityId(999)).thenReturn(Optional.empty());
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- assertNull(response.getBody());
- verify(locationRepository).findByEntityId(1);
+ mockMvc.perform(get("/api/v1/locations/entity/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Location not found for entity: 999"));
}
@Test
- void addEntityToLocation_Success() {
- // setup
- when(locationRepository.addEntityToLocation(1, 1)).thenReturn(true);
-
- // execute
- ResponseEntity response = locationController.addEntityToLocation(1, 1);
+ void getLocationOfEntity_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findByEntityId(1)).thenThrow(new RuntimeException("Database error"));
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- verify(locationRepository).addEntityToLocation(1, 1);
+ mockMvc.perform(get("/api/v1/locations/entity/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- PUT /api/v1/locations/{locationId}/entity/{entityId} ---
+
@Test
- void addEntityToLocation_NotFound() {
- // setup
- when(locationRepository.addEntityToLocation(1, 1)).thenReturn(false);
+ void addEntityToLocation_Success() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.of(new Location(2, 10, 20)));
+ when(locationRepository.addEntityToLocation(1, 2)).thenReturn(true);
- // execute
- ResponseEntity response = locationController.addEntityToLocation(1, 1);
+ mockMvc.perform(put("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isOk());
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- verify(locationRepository).addEntityToLocation(1, 1);
+ verify(locationRepository).addEntityToLocation(1, 2);
}
@Test
- void addEntityToLocation_Exception() {
- // setup
- when(locationRepository.addEntityToLocation(1, 1)).thenThrow(new RuntimeException());
+ void addEntityToLocation_NotFound() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = locationController.addEntityToLocation(1, 1);
+ mockMvc.perform(put("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Location not found with id: 2"));
+ }
- // verify
- assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
- verify(locationRepository).addEntityToLocation(1, 1);
+ @Test
+ void addEntityToLocation_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.of(new Location(2, 10, 20)));
+ when(locationRepository.addEntityToLocation(1, 2)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(put("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- DELETE /api/v1/locations/{locationId}/entity/{entityId} ---
+
@Test
- void removeEntityFromLocation_Success() {
- // setup
- when(locationRepository.removeEntityFromLocation(1, 1)).thenReturn(true);
+ void removeEntityFromLocation_Success() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.of(new Location(2, 10, 20)));
+ when(locationRepository.removeEntityFromLocation(1, 2)).thenReturn(true);
- // execute
- ResponseEntity response = locationController.removeEntityFromLocation(1, 1);
+ mockMvc.perform(delete("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isNoContent());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
- verify(locationRepository).removeEntityFromLocation(1, 1);
+ verify(locationRepository).removeEntityFromLocation(1, 2);
}
@Test
- void removeEntityFromLocation_NotFound() {
- // setup
- when(locationRepository.removeEntityFromLocation(1, 1)).thenReturn(false);
+ void removeEntityFromLocation_NotFound() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = locationController.removeEntityFromLocation(1, 1);
+ mockMvc.perform(delete("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Location not found with id: 2"));
+ }
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- verify(locationRepository).removeEntityFromLocation(1, 1);
+ @Test
+ void removeEntityFromLocation_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findById(2)).thenReturn(Optional.of(new Location(2, 10, 20)));
+ when(locationRepository.removeEntityFromLocation(1, 2)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(delete("/api/v1/locations/2/entity/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
+ // --- DELETE /api/v1/locations/entity/{entityId} ---
+
@Test
- void removeEntityFromCurrentLocation_Success() {
- // setup
+ void removeEntityFromCurrentLocation_Success() throws Exception {
+ when(locationRepository.findByEntityId(1)).thenReturn(Optional.of(new Location(5, 10, 20)));
when(locationRepository.removeEntityFromCurrentLocation(1)).thenReturn(true);
- // execute
- ResponseEntity response = locationController.removeEntityFromCurrentLocation(1);
+ mockMvc.perform(delete("/api/v1/locations/entity/1"))
+ .andExpect(status().isNoContent());
- // verify
- assertEquals(HttpStatus.OK, response.getStatusCode());
verify(locationRepository).removeEntityFromCurrentLocation(1);
}
@Test
- void removeEntityFromCurrentLocation_NotFound() {
- // setup
- when(locationRepository.removeEntityFromCurrentLocation(1)).thenReturn(false);
+ void removeEntityFromCurrentLocation_NotFound() throws Exception {
+ when(locationRepository.findByEntityId(999)).thenReturn(Optional.empty());
- // execute
- ResponseEntity response = locationController.removeEntityFromCurrentLocation(1);
+ mockMvc.perform(delete("/api/v1/locations/entity/999"))
+ .andExpect(status().isNotFound())
+ .andExpect(jsonPath("$.status").value(404))
+ .andExpect(jsonPath("$.message").value("Location not found for entity: 999"));
+ }
- // verify
- assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
- verify(locationRepository).removeEntityFromCurrentLocation(1);
+ @Test
+ void removeEntityFromCurrentLocation_RepositoryThrowsException() throws Exception {
+ when(locationRepository.findByEntityId(1)).thenReturn(Optional.of(new Location(5, 10, 20)));
+ when(locationRepository.removeEntityFromCurrentLocation(1)).thenThrow(new RuntimeException("Database error"));
+
+ mockMvc.perform(delete("/api/v1/locations/entity/1"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(jsonPath("$.status").value(500))
+ .andExpect(jsonPath("$.message").isString());
}
}
\ No newline at end of file