test(project): remove brittle Lombok source audit
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
# Test Evidence: Targeted Project Lombok boilerplate
|
# Test Evidence: Targeted Project Lombok boilerplate
|
||||||
|
|
||||||
- **Test type:** Unit
|
- **Test type:** Temporary source audit (removed after GREEN)
|
||||||
- **Requirement IDs:** `ARC-002`, `ARC-005`, `ARC-006`, `TST-001`
|
- **Requirement IDs:** `ARC-002`, `ARC-005`, `ARC-006`, `TST-001`
|
||||||
- **Scenario IDs:** `AC-TST-001`
|
- **Scenario IDs:** `AC-TST-001`
|
||||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.repository.ProjectLombokBoilerplateTest#eligibleConstructorsUseTargetedLombokWithoutChangingDomainApis`
|
- **Test class/method:** N/A; the temporary source audit was removed after its RED/GREEN cycle
|
||||||
- **Implementation commit:** `e5639c1`
|
- **Implementation commit:** `e5639c1`
|
||||||
|
|
||||||
## Protected behavior
|
## Protected behavior
|
||||||
@@ -13,13 +13,15 @@ constructors assign required final dependencies. Project JPA entities use only p
|
|||||||
constructor generation. Records remain records, and entity identity, lazy associations, explicit
|
constructor generation. Records remain records, and entity identity, lazy associations, explicit
|
||||||
domain accessors, aggregate constructors, and mutation methods do not gain broad generated APIs.
|
domain accessors, aggregate constructors, and mutation methods do not gain broad generated APIs.
|
||||||
|
|
||||||
## Test method
|
## Temporary RED/GREEN method
|
||||||
|
|
||||||
The source-contract test inspects only `feature.project` production sources. It requires
|
The temporary source-contract test inspected only `feature.project` production sources. It required
|
||||||
`@RequiredArgsConstructor` on the three injection-only components, removes the stateless advice's
|
`@RequiredArgsConstructor` on the three injection-only components, removal of the stateless advice's
|
||||||
handwritten no-arg constructor, and requires protected `@NoArgsConstructor` on the three JPA
|
handwritten no-arg constructor, and protected `@NoArgsConstructor` on the three JPA entities. It also
|
||||||
entities. It also rejects broad entity Lombok annotations, confirms representative explicit domain
|
rejected broad entity Lombok annotations, confirmed representative explicit domain APIs remained,
|
||||||
APIs remain, and verifies every Project immutable DTO/value type remains a Java record.
|
and verified every Project immutable DTO/value type remained a Java record. It was deleted after
|
||||||
|
preserving the historical RED/GREEN below because exact imports, annotation spelling, and source
|
||||||
|
substrings are implementation details rather than a durable public contract.
|
||||||
|
|
||||||
## Hand-derived expected result
|
## Hand-derived expected result
|
||||||
|
|
||||||
@@ -80,8 +82,8 @@ export PATH="/opt/homebrew/opt/node@24/bin:$JAVA_HOME/bin:$PATH"
|
|||||||
./mvnw -DskipTests compile
|
./mvnw -DskipTests compile
|
||||||
[INFO] BUILD SUCCESS
|
[INFO] BUILD SUCCESS
|
||||||
|
|
||||||
./mvnw -Dtest=ProjectLombokBoilerplateTest,ProjectEntityTest,ProjectPersistenceStructureTest,ProjectTaskMutationContextTest test
|
./mvnw -Dtest=ProjectEntityTest,ProjectPersistenceStructureTest,ProjectTaskMutationContextTest test
|
||||||
[INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0
|
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
|
||||||
[INFO] BUILD SUCCESS
|
[INFO] BUILD SUCCESS
|
||||||
|
|
||||||
./mvnw -Dtest=ProjectControllerTest test
|
./mvnw -Dtest=ProjectControllerTest test
|
||||||
@@ -94,7 +96,7 @@ export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
|||||||
[INFO] BUILD SUCCESS
|
[INFO] BUILD SUCCESS
|
||||||
|
|
||||||
./mvnw -Dtest='Project*Test' test
|
./mvnw -Dtest='Project*Test' test
|
||||||
[INFO] Tests run: 45, Failures: 0, Errors: 0, Skipped: 0
|
[INFO] Tests run: 44, Failures: 0, Errors: 0, Skipped: 0
|
||||||
[INFO] BUILD SUCCESS
|
[INFO] BUILD SUCCESS
|
||||||
|
|
||||||
./mvnw -DskipTests -Dmaven.javadoc.failOnWarnings=true -Ddoclint=all \
|
./mvnw -DskipTests -Dmaven.javadoc.failOnWarnings=true -Ddoclint=all \
|
||||||
@@ -107,9 +109,9 @@ git diff --check
|
|||||||
|
|
||||||
## External-test boundaries
|
## External-test boundaries
|
||||||
|
|
||||||
The source audit does not by itself prove Lombok annotation processing, Spring constructor
|
The removed source audit did not prove Lombok annotation processing, Spring constructor injection,
|
||||||
injection, Hibernate materialization, PostgreSQL mappings, Thymeleaf behavior, Project authorization,
|
Hibernate materialization, PostgreSQL mappings, Thymeleaf behavior, Project authorization, locking,
|
||||||
locking, or aggregate lifecycle rules. Those boundaries are covered by the compile, scoped
|
or aggregate lifecycle rules. Those durable boundaries are covered by the compile, scoped
|
||||||
Javadoc/doclint, Project unit/web, and PostgreSQL 18.4 integration gates above. The first sandboxed
|
Javadoc/doclint, Project unit/web, and PostgreSQL 18.4 integration gates above. The first sandboxed
|
||||||
unit-suite attempt could not attach Mockito's Byte Buddy agent; the unchanged command passed after
|
unit-suite attempt could not attach Mockito's Byte Buddy agent; the unchanged command passed after
|
||||||
approved execution outside that sandbox. Browser E2E behavior remains outside this unit milestone.
|
approved execution outside that sandbox. Browser E2E behavior remains outside this unit milestone.
|
||||||
|
|||||||
-77
@@ -1,77 +0,0 @@
|
|||||||
package com.lab.labtimesheet.feature.project.repository;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class ProjectLombokBoilerplateTest {
|
|
||||||
|
|
||||||
private static final Path PROJECT_SOURCE =
|
|
||||||
Path.of("src/main/java/com/lab/labtimesheet/feature/project");
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void eligibleConstructorsUseTargetedLombokWithoutChangingDomainApis() throws IOException {
|
|
||||||
assertRequiredArgsConstructor("controller/ProjectController.java", "ProjectController");
|
|
||||||
assertRequiredArgsConstructor("service/ProjectService.java", "ProjectService");
|
|
||||||
assertRequiredArgsConstructor("service/ProjectQueryService.java", "ProjectQueryService");
|
|
||||||
|
|
||||||
String advice = source("exception/ProjectControllerAdvice.java");
|
|
||||||
assertThat(advice).doesNotContain("public ProjectControllerAdvice()");
|
|
||||||
|
|
||||||
assertProtectedJpaConstructor("model/entity/ProjectEntity.java", "ProjectEntity");
|
|
||||||
assertProtectedJpaConstructor(
|
|
||||||
"model/entity/ProjectLeadershipTermEntity.java", "ProjectLeadershipTermEntity");
|
|
||||||
assertProtectedJpaConstructor(
|
|
||||||
"model/entity/ProjectMembershipEntity.java", "ProjectMembershipEntity");
|
|
||||||
|
|
||||||
assertThat(source("model/entity/ProjectEntity.java"))
|
|
||||||
.contains("public static ProjectEntity plan(", "public ProjectMembershipEntity addMember(")
|
|
||||||
.doesNotContain("@Getter", "@Setter", "@Data", "@EqualsAndHashCode", "@ToString");
|
|
||||||
assertThat(source("model/entity/ProjectLeadershipTermEntity.java"))
|
|
||||||
.contains("public long internUserId()", "Instant end(Instant at, long mentorUserId)")
|
|
||||||
.doesNotContain("@Getter", "@Setter", "@Data", "@EqualsAndHashCode", "@ToString");
|
|
||||||
assertThat(source("model/entity/ProjectMembershipEntity.java"))
|
|
||||||
.contains("public long internUserId()", "public boolean isCurrent()")
|
|
||||||
.doesNotContain("@Getter", "@Setter", "@Data", "@EqualsAndHashCode", "@ToString");
|
|
||||||
|
|
||||||
for (String recordSource : List.of(
|
|
||||||
"model/ProjectInternEligibility.java",
|
|
||||||
"model/ProjectLeaderChange.java",
|
|
||||||
"model/dto/ProjectActorView.java",
|
|
||||||
"model/dto/ProjectCreateCommand.java",
|
|
||||||
"model/dto/ProjectCreateForm.java",
|
|
||||||
"model/dto/ProjectDashboardSummary.java",
|
|
||||||
"model/dto/ProjectDetail.java",
|
|
||||||
"model/dto/ProjectLeadershipTermView.java",
|
|
||||||
"model/dto/ProjectMemberForm.java",
|
|
||||||
"model/dto/ProjectMemberView.java",
|
|
||||||
"model/dto/ProjectSummary.java",
|
|
||||||
"model/dto/ProjectTaskContext.java",
|
|
||||||
"model/dto/ProjectTaskMemberView.java")) {
|
|
||||||
assertThat(source(recordSource)).contains(" record ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertRequiredArgsConstructor(String relativePath, String typeName) throws IOException {
|
|
||||||
assertThat(source(relativePath))
|
|
||||||
.contains("import lombok.RequiredArgsConstructor;", "@RequiredArgsConstructor")
|
|
||||||
.doesNotContain("public " + typeName + "(");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertProtectedJpaConstructor(String relativePath, String typeName) throws IOException {
|
|
||||||
assertThat(source(relativePath))
|
|
||||||
.contains(
|
|
||||||
"import lombok.AccessLevel;",
|
|
||||||
"import lombok.NoArgsConstructor;",
|
|
||||||
"@NoArgsConstructor(access = AccessLevel.PROTECTED)")
|
|
||||||
.doesNotContain("protected " + typeName + "()");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String source(String relativePath) throws IOException {
|
|
||||||
return Files.readString(PROJECT_SOURCE.resolve(relativePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user