From 2526bf7875404fb54123458afb5cb3f3b86b2832 Mon Sep 17 00:00:00 2001 From: Kamil Sulejewski Date: Mon, 3 Mar 2025 21:10:35 +0100 Subject: [PATCH 1/2] feat: validate and generated dedicated-meta-schema.json. Created endpoint and refactor dedicated services methods. --- .../CommitCraftTemplateController.java | 25 +++-- .../CommitDedicatedTemplateValidator.java | 85 ++++++++++----- .../craft/template/CommitTemplateService.java | 57 +++++++++- .../template/TemplateOperationResult.java | 4 + .../craft/template/ValidationResult.java | 57 ++++++++++ .../CommitTemplateGenerateController.java | 6 ++ .../CommitTemplateGenerateService.java | 102 ++++++++++++------ .../templates/dedicated-meta-schema.json | 15 ++- .../CommitTemplateGenerateServiceTest.java | 46 ++++++-- .../resources/test-dedicated-meta-schema.json | 22 +++- 10 files changed, 338 insertions(+), 81 deletions(-) create mode 100644 src/main/java/pl/commit/craft/template/TemplateOperationResult.java create mode 100644 src/main/java/pl/commit/craft/template/ValidationResult.java diff --git a/src/main/java/pl/commit/craft/template/CommitCraftTemplateController.java b/src/main/java/pl/commit/craft/template/CommitCraftTemplateController.java index d046db0..305e3bc 100644 --- a/src/main/java/pl/commit/craft/template/CommitCraftTemplateController.java +++ b/src/main/java/pl/commit/craft/template/CommitCraftTemplateController.java @@ -3,9 +3,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -30,18 +32,23 @@ public ResponseEntity> getAllTemplates() throws IOExce summary = "Create a dedicated commit template", description = "Creates a new dedicated commit template if the pattern and model scope are valid.", responses = { - @ApiResponse(responseCode = "200", description = "Template added successfully"), - @ApiResponse(responseCode = "400", description = "Template already exists") + @ApiResponse(responseCode = "201", description = "Template created successfully"), + @ApiResponse(responseCode = "400", description = "Invalid template format or template already exists") } ) @PostMapping("/dedicated") - public ResponseEntity createDedicatedTemplate(@RequestBody CommitCraftTemplate template) throws IOException { - boolean patternAndModelScope = CommitDedicatedTemplateValidator.validatePatternAndModelScope(template); - if (patternAndModelScope) { - commitTemplateService.createDedicatedTemplate(template); - return ResponseEntity.ok("Template added successfully."); - } - return ResponseEntity.badRequest().body("Template already exists."); + public ResponseEntity> createDedicatedTemplate(@RequestBody CommitCraftTemplate template) throws IOException { + TemplateOperationResult result = commitTemplateService.createDedicatedTemplate(template); + + if (result.success()) { + return ResponseEntity + .status(HttpStatus.CREATED) + .body(Collections.singletonMap("message", result.message())); + } + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(Collections.singletonMap("error", result.message())); } @Operation( diff --git a/src/main/java/pl/commit/craft/template/CommitDedicatedTemplateValidator.java b/src/main/java/pl/commit/craft/template/CommitDedicatedTemplateValidator.java index bf80671..b4ba3b4 100644 --- a/src/main/java/pl/commit/craft/template/CommitDedicatedTemplateValidator.java +++ b/src/main/java/pl/commit/craft/template/CommitDedicatedTemplateValidator.java @@ -1,42 +1,79 @@ package pl.commit.craft.template; import lombok.extern.slf4j.Slf4j; -import java.util.Map; +import java.util.HashSet; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; @Slf4j class CommitDedicatedTemplateValidator { - private static final String PATTERN_VALIDATE_MODEL = "\\{(\\w+)\\}(-\\{(\\w+)\\})*"; + private static final String PLACEHOLDER_REGEX = "\\{(\\w+)\\}"; + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(PLACEHOLDER_REGEX); - static boolean validatePatternAndModelScope(CommitCraftTemplate template) { - log.info("Validating pattern and model scope starting"); - String pattern = template.getPattern(); - Map model = template.getModel(); + /** + * For backward compatibility + */ + public static boolean validatePatternAndModelScope(CommitCraftTemplate template) { + return validatePatternAndModelScopeDetailed(template).isValid(); + } - Set modelKeys = model.keySet(); + /** + * Validates that all keys in the model exist in the pattern and vice versa. + * + * @param template The commit template to validate + * @return result of validation with details about any mismatches + */ + public static ValidationResult validatePatternAndModelScopeDetailed(CommitCraftTemplate template) { + log.info("Validating pattern and model scope starting for template: {}", template.getName()); - boolean matches = true; - for (String key : modelKeys) { - if (!pattern.contains(key)) { - log.warn("Pattern is missing key: {}", key); - matches = false; - } - } + Set modelKeys = template.getModel().keySet(); + Set patternKeys = extractPlaceholdersFromPattern(template.getPattern()); - String[] patternWords = pattern.split(PATTERN_VALIDATE_MODEL); - for (String word : patternWords) { - if (!modelKeys.contains(word)) { - log.warn("Pattern contains an extra key not in the model: {}", word); - matches = false; - } - } + Set missingInPattern = findMissingKeys(modelKeys, patternKeys); + Set extraInPattern = findMissingKeys(patternKeys, modelKeys); + + boolean isValid = missingInPattern.isEmpty() && extraInPattern.isEmpty(); - if (matches) { + if (isValid) { log.info("Pattern matches the model keys."); + return ValidationResult.valid(); } else { - log.warn("Pattern does not match the model keys."); + if (!missingInPattern.isEmpty()) { + log.warn("Pattern is missing keys: {}", missingInPattern); + } + if (!extraInPattern.isEmpty()) { + log.warn("Pattern contains extra keys not in the model: {}", extraInPattern); + } + return ValidationResult.invalid(missingInPattern, extraInPattern); } + } + + + /** + * Extracts all placeholder keys from the pattern string. + * + * @param pattern The pattern string containing placeholders + * @return A set of placeholder keys + */ + private static Set extractPlaceholdersFromPattern(String pattern) { + Set patternKeys = new HashSet<>(); + Matcher matcher = PLACEHOLDER_PATTERN.matcher(pattern); + + while (matcher.find()) { + patternKeys.add(matcher.group(1)); + } + + return patternKeys; + } - return matches; + /** + * Finds keys that are in the first set but not in the second set + */ + private static Set findMissingKeys(Set sourceKeys, Set targetKeys) { + return sourceKeys.stream() + .filter(key -> !targetKeys.contains(key)) + .collect(Collectors.toSet()); } } diff --git a/src/main/java/pl/commit/craft/template/CommitTemplateService.java b/src/main/java/pl/commit/craft/template/CommitTemplateService.java index 3ce7d8e..9e3e1f7 100644 --- a/src/main/java/pl/commit/craft/template/CommitTemplateService.java +++ b/src/main/java/pl/commit/craft/template/CommitTemplateService.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.io.File; import java.io.IOException; @@ -14,6 +15,7 @@ import java.util.List; import java.util.Map; +@Slf4j @Service @RequiredArgsConstructor class CommitTemplateService { @@ -78,10 +80,57 @@ public List readTemplates() throws IOException { }); } - public void createDedicatedTemplate(CommitCraftTemplate newTemplate) throws IOException { - List templates = readTemplates(); - templates.add(newTemplate); - saveTemplates(templates); + /** + * Creates a dedicated template after validating it. + * + * @param template The template to create + * @return Result containing success/failure status and a message + * @throws IOException If there's an issue accessing the template storage + */ + public TemplateOperationResult createDedicatedTemplate(CommitCraftTemplate template) throws IOException { + ValidationResult validationResult = + CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(template); + + if (!validationResult.isValid()) { + String errorMessage = validationResult.getErrorMessage(); + log.warn("Template validation failed: {}", errorMessage); + return new TemplateOperationResult(false, errorMessage); + } + + if (templateExists(template.getName())) { + log.warn("Template with name '{}' already exists", template.getName()); + return new TemplateOperationResult(false, "Template with name '" + template.getName() + "' already exists"); + } + + saveTemplate(template); + log.info("Template '{}' created successfully", template.getName()); + return new TemplateOperationResult(true, "Template created successfully"); + } + + /** + * Checks if a template with the given name already exists + * + * @param templateName Name of the template to check + * @return true if the template exists, false otherwise + * @throws IOException If there's an issue accessing the template storage + */ + private boolean templateExists(String templateName) throws IOException { + List existingTemplates = getAllTemplates(); + return existingTemplates.stream() + .anyMatch(template -> template.getName().equals(templateName)); + } + + /** + * Saves a new template to the dedicated templates file + * + * @param template The template to save + * @throws IOException If there's an issue accessing or writing to the template storage + */ + private void saveTemplate(CommitCraftTemplate template) throws IOException { + List existingTemplates = readTemplates(); + existingTemplates.add(template); + saveTemplates(existingTemplates); + log.debug("Template saved successfully: {}", template.getName()); } public void removeDedicatedTemplate(String dedicatedTemplateName) throws IOException { diff --git a/src/main/java/pl/commit/craft/template/TemplateOperationResult.java b/src/main/java/pl/commit/craft/template/TemplateOperationResult.java new file mode 100644 index 0000000..0813ec9 --- /dev/null +++ b/src/main/java/pl/commit/craft/template/TemplateOperationResult.java @@ -0,0 +1,4 @@ +package pl.commit.craft.template; + +record TemplateOperationResult(boolean success, String message) { +} diff --git a/src/main/java/pl/commit/craft/template/ValidationResult.java b/src/main/java/pl/commit/craft/template/ValidationResult.java new file mode 100644 index 0000000..0cd92f5 --- /dev/null +++ b/src/main/java/pl/commit/craft/template/ValidationResult.java @@ -0,0 +1,57 @@ +package pl.commit.craft.template; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Set; + +@AllArgsConstructor +class ValidationResult { + @Getter + private final boolean valid; + private final Set missingInPattern; + private final Set extraInPattern; + + /** + * Creates a successful validation result + */ + public static ValidationResult valid() { + return new ValidationResult(true, Set.of(), Set.of()); + } + + /** + * Creates a validation result with errors + */ + public static ValidationResult invalid(Set missingInPattern, Set extraInPattern) { + return new ValidationResult(false, missingInPattern, extraInPattern); + } + + /** + * Generates a detailed error message for invalid templates + */ + public String getErrorMessage() { + if (valid) { + return "Template is valid"; + } + + StringBuilder message = new StringBuilder("Invalid template format: "); + + if (!missingInPattern.isEmpty()) { + message.append("Keys missing in pattern: [") + .append(String.join(", ", missingInPattern)) + .append("]"); + + if (!extraInPattern.isEmpty()) { + message.append("; "); + } + } + + if (!extraInPattern.isEmpty()) { + message.append("Missing keys in model: [") + .append(String.join(", ", extraInPattern)) + .append("]"); + } + + return message.toString(); + } +} diff --git a/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateController.java b/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateController.java index 9cc74f2..2d70536 100644 --- a/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateController.java +++ b/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateController.java @@ -18,4 +18,10 @@ public ResponseEntity generateCommit(@RequestParam String templateName, String commitMessage = service.generateCommit(templateName, commitData); return ResponseEntity.ok(commitMessage); } + + @PostMapping("/generate-dedicated") + public ResponseEntity generateDedicatedCommit(@RequestParam String templateName, @RequestBody JsonNode commitData) throws IOException { + String commitMessage = service.generateDedicatedCommit(templateName, commitData); + return ResponseEntity.ok(commitMessage); + } } diff --git a/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateService.java b/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateService.java index a6aa33b..2fd5aca 100644 --- a/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateService.java +++ b/src/main/java/pl/commit/craft/template/generate/CommitTemplateGenerateService.java @@ -10,41 +10,75 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.StreamSupport; @Service @RequiredArgsConstructor class CommitTemplateGenerateService { + private static final String ROOT_TEMPLATE_NAME = "templates"; + private static final String ROOT_DEDICATED_NAME = "dedicated"; + private static final String TEMPLATES_SCHEMA_PATH = "src/main/resources/templates/meta-schema.json"; + private static final String DEDICATED_SCHEMA_PATH = "src/main/resources/templates/dedicated-meta-schema.json"; private final ObjectMapper objectMapper; - private static final String RESOURCES_TEMPLATES_META_SCHEMA_JSON = "src/main/resources/templates/meta-schema.json"; + /** + * Generates a commit message using a standard template + */ String generateCommit(String templateName, JsonNode commitData) throws IOException { - JsonNode rootNode = objectMapper.readTree(new File(RESOURCES_TEMPLATES_META_SCHEMA_JSON)); - JsonNode templatesArray = rootNode.path("templates"); + return generateCommitFromSchema( + TEMPLATES_SCHEMA_PATH, + ROOT_TEMPLATE_NAME, + templateName, + commitData + ); + } + + /** + * Generates a commit message using a dedicated template + */ + String generateDedicatedCommit(String templateName, JsonNode commitData) throws IOException { + return generateCommitFromSchema( + DEDICATED_SCHEMA_PATH, + ROOT_DEDICATED_NAME, + templateName, + commitData + ); + } - Optional matchingTemplate = findTemplateByName(templatesArray, templateName); + /** + * Core method for generating commit messages from any schema + */ + private String generateCommitFromSchema( + String schemaPath, + String rootNodeName, + String templateName, + JsonNode commitData) throws IOException { - if (matchingTemplate.isEmpty()) { - throw new IllegalArgumentException("Template with name " + templateName + " not found"); - } + JsonNode rootNode = objectMapper.readTree(new File(schemaPath)); + JsonNode templatesArray = rootNode.path(rootNodeName); + + JsonNode template = findTemplateByName(templatesArray, templateName) + .orElseThrow(() -> new IllegalArgumentException("Template with name " + templateName + " not found")); - JsonNode template = matchingTemplate.get(); validateCommitData(template.path("model"), commitData); String pattern = template.path("pattern").asText(); return fillPatternWithData(pattern, commitData); } + /** + * Finds a template by name in the templates array + */ private Optional findTemplateByName(JsonNode templatesArray, String templateName) { - for (Iterator it = templatesArray.elements(); it.hasNext(); ) { - JsonNode template = it.next(); - if (templateName.equals(template.path("name").asText())) { - return Optional.of(template); - } - } - return Optional.empty(); + return StreamSupport.stream(templatesArray.spliterator(), false) + .filter(template -> templateName.equals(template.path("name").asText())) + .findFirst(); } + /** + * Validates the commit data against the template model + */ private void validateCommitData(JsonNode model, JsonNode commitData) { List missingFields = new ArrayList<>(); @@ -60,43 +94,41 @@ private void validateCommitData(JsonNode model, JsonNode commitData) { }); if (!missingFields.isEmpty()) { - throw new IllegalArgumentException("Missing required fields: " + missingFields); + throw new IllegalArgumentException("Missing required fields: " + String.join(", ", missingFields)); } } + /** + * Validates that field values match allowed values in the model + */ private void validateArrayField(String fieldName, JsonNode fieldModel, JsonNode commitData) { JsonNode valueNode = commitData.path(fieldName); - if (valueNode.isTextual()) { - String value = valueNode.asText(); - boolean isValid = false; + if (!valueNode.isTextual()) { + throw new IllegalArgumentException("Field '" + fieldName + "' should be a string"); + } - for (JsonNode allowedValue : fieldModel) { - if (allowedValue.asText().equals(value)) { - isValid = true; - break; - } - } + String value = valueNode.asText(); + boolean isValid = StreamSupport.stream(fieldModel.spliterator(), false) + .anyMatch(allowedValue -> allowedValue.asText().equals(value)); - if (!isValid) { - throw new IllegalArgumentException("Invalid value for field '" + fieldName + "': " + value); - } - } else { - throw new IllegalArgumentException("Field '" + fieldName + "' should be a string"); + if (!isValid) { + throw new IllegalArgumentException("Invalid value for field '" + fieldName + "': " + value); } } + /** + * Fills the template pattern with the commit data + */ private String fillPatternWithData(String pattern, JsonNode commitData) { String result = pattern; Iterator fieldNames = commitData.fieldNames(); while (fieldNames.hasNext()) { String fieldName = fieldNames.next(); - String placeholder = "{" + fieldName + "}"; - if (result.contains(placeholder)) { - String value = commitData.path(fieldName).asText(); - result = result.replace(placeholder, value); - } + String placeholder = "\\{" + fieldName + "\\}"; + String value = commitData.path(fieldName).asText(); + result = result.replaceAll(placeholder, value); } return result.trim(); diff --git a/src/main/resources/templates/dedicated-meta-schema.json b/src/main/resources/templates/dedicated-meta-schema.json index 02c2457..83f352c 100644 --- a/src/main/resources/templates/dedicated-meta-schema.json +++ b/src/main/resources/templates/dedicated-meta-schema.json @@ -1 +1,14 @@ -{"dedicated":[]} \ No newline at end of file +{ + "dedicated" : [ { + "name" : "apilia-project", + "description" : "Dedykowany dla projektu coś tam", + "pattern" : "{ticket_id} {type}({scope}):{message}-{details}", + "model" : { + "ticket_id" : "Numer powiązanego zadania w JIRA", + "type" : [ "feat", "fix", "junk", "chore", "test" ], + "scope" : "[moduł lub komponent]", + "message" : "Krótki opis zmiany", + "details" : "Szczegóły zmian w treści commit message" + } + } ] +} \ No newline at end of file diff --git a/src/test/java/pl/commit/craft/template/generate/CommitTemplateGenerateServiceTest.java b/src/test/java/pl/commit/craft/template/generate/CommitTemplateGenerateServiceTest.java index 128b319..6fec68b 100644 --- a/src/test/java/pl/commit/craft/template/generate/CommitTemplateGenerateServiceTest.java +++ b/src/test/java/pl/commit/craft/template/generate/CommitTemplateGenerateServiceTest.java @@ -13,10 +13,11 @@ import java.io.IOException; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class CommitTemplateGenerateServiceTest { - public static final String TEMPLATES_META_SCHEMA_JSON = "src/main/resources/templates/meta-schema.json"; + private static final String TEMPLATES_META_SCHEMA_JSON = "src/main/resources/templates/meta-schema.json"; @InjectMocks private CommitTemplateGenerateService service; @@ -30,9 +31,9 @@ class CommitTemplateGenerateServiceTest { .put("field1", "value1") .put("field2", "value2"); + @Test void shouldGenerateCommitWhenTemplateAndDataAreValid() throws IOException { - // Mock JSON template structure JsonNode templateNode = JsonNodeFactory.instance.objectNode() .put("name", TEMPLATE_NAME) .put("pattern", VALID_PATTERN) @@ -47,10 +48,8 @@ void shouldGenerateCommitWhenTemplateAndDataAreValid() throws IOException { Mockito.when(objectMapper.readTree(new File(TEMPLATES_META_SCHEMA_JSON))) .thenReturn(rootNode); - // Execute method String result = service.generateCommit(TEMPLATE_NAME, VALID_COMMIT_DATA); - // Verify result assertEquals("Commit: value1, value2", result); } @@ -73,7 +72,6 @@ void shouldThrowExceptionWhenTemplateNotFound() throws IOException { @Test void shouldThrowExceptionWhenRequiredFieldsAreMissing() throws IOException { - // Mock JSON template structure with required fields JsonNode modelNode = JsonNodeFactory.instance.objectNode() .put("field1", true) .put("field2", true); @@ -94,12 +92,46 @@ void shouldThrowExceptionWhenRequiredFieldsAreMissing() throws IOException { JsonNode incompleteCommitData = JsonNodeFactory.instance.objectNode().put("field1", "value1"); - // Execute method and expect exception Exception exception = assertThrows(IllegalArgumentException.class, () -> service.generateCommit(TEMPLATE_NAME, incompleteCommitData)); - assertEquals("Missing required fields: [field2]", exception.getMessage()); + assertEquals("Missing required fields: field2", exception.getMessage()); } + @Test + void shouldGenerateDedicatedCommitWhenTemplateAndDataAreValid() throws IOException { + // Mock JSON template structure + JsonNode templateNode = JsonNodeFactory.instance.objectNode() + .put("name", "test-project") + .put("description", "Dedykowany dla projektu coś tam") + .put("pattern", "{ticket_id} {type}({scope}): {message}") + .set("model", JsonNodeFactory.instance.objectNode() + .put("ticket_id", "Numer powiązanego zadania w JIRA") + .set("type", JsonNodeFactory.instance.arrayNode() + .add("feat") + .add("fix") + .add("junk") + .add("chore") + .add("test")) + ); + + JsonNode templatesNode = JsonNodeFactory.instance.objectNode() + .set("dedicated", JsonNodeFactory.instance.arrayNode().add(templateNode)); + + // Mock ObjectMapper behavior using the same path as in production code + when(objectMapper.readTree(new File("src/main/resources/templates/dedicated-meta-schema.json"))) + .thenReturn(templatesNode); + + JsonNode validCommitData = JsonNodeFactory.instance.objectNode() + .put("ticket_id", "JIRA-123") + .put("type", "feat") + .put("scope", "auth-module") + .put("message", "Dodano obsługę OAuth2"); + + // Execute method + String result = service.generateDedicatedCommit("test-project", validCommitData); + // Verify result + assertEquals("JIRA-123 feat(auth-module): Dodano obsługę OAuth2", result); + } } \ No newline at end of file diff --git a/src/test/resources/test-dedicated-meta-schema.json b/src/test/resources/test-dedicated-meta-schema.json index 02c2457..67339e9 100644 --- a/src/test/resources/test-dedicated-meta-schema.json +++ b/src/test/resources/test-dedicated-meta-schema.json @@ -1 +1,21 @@ -{"dedicated":[]} \ No newline at end of file +{ + "dedicated": [ + { + "name": "test-project", + "description": "Dedykowany dla projektu coś tam", + "pattern": "{ticket_id} {type}({scope}): {message}", + "model": { + "ticket_id": "Numer powiązanego zadania w JIRA", + "type": [ + "feat", + "fix", + "junk", + "chore", + "test" + ], + "scope": "[moduł lub komponent]", + "message": "Krótki opis zmiany" + } + } + ] +} \ No newline at end of file From c2297048bf75bd0b70d9dc2e70aad5d458d0ebd9 Mon Sep 17 00:00:00 2001 From: Kamil Sulejewski Date: Mon, 3 Mar 2025 21:50:34 +0100 Subject: [PATCH 2/2] test: corrected tests and removed empty line. --- .../craft/template/ValidationResult.java | 1 - .../CommitDedicatedTemplateValidatorTest.java | 65 +++++++++---------- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/main/java/pl/commit/craft/template/ValidationResult.java b/src/main/java/pl/commit/craft/template/ValidationResult.java index 0cd92f5..fa5b4aa 100644 --- a/src/main/java/pl/commit/craft/template/ValidationResult.java +++ b/src/main/java/pl/commit/craft/template/ValidationResult.java @@ -2,7 +2,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; - import java.util.Set; @AllArgsConstructor diff --git a/src/test/java/pl/commit/craft/template/CommitDedicatedTemplateValidatorTest.java b/src/test/java/pl/commit/craft/template/CommitDedicatedTemplateValidatorTest.java index 9ab1f2e..b694e29 100644 --- a/src/test/java/pl/commit/craft/template/CommitDedicatedTemplateValidatorTest.java +++ b/src/test/java/pl/commit/craft/template/CommitDedicatedTemplateValidatorTest.java @@ -1,77 +1,72 @@ package pl.commit.craft.template; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; class CommitDedicatedTemplateValidatorTest { - private static final Logger log = LoggerFactory.getLogger(CommitDedicatedTemplateValidator.class); - @InjectMocks - private CommitDedicatedTemplateValidator validator; - - private ListAppender listAppender; + @Test + void shouldValidatePatternAndModelScope_Success() { + Map model = Map.of( + "scope", "core", + "message", "message" + ); + CommitCraftTemplate validTemplate = new CommitCraftTemplate("feat-{scope}-{message}", "Standard commit", "feat-{scope}-{message}", model); - @BeforeEach - void setUp() { - listAppender = new ListAppender<>(); - listAppender.start(); + ValidationResult result = CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(validTemplate); - ((ch.qos.logback.classic.Logger) log).addAppender(listAppender); + assertTrue(result.isValid()); + assertEquals("Template is valid", result.getErrorMessage()); } @Test - void testValidatePatternAndModelScope_success() { + void shouldValidatePatternAndModelScope_MissingModelKey() { Map model = Map.of( "type", "feat", - "scope", "core", - "message", "message" + "message", "message", + "scope", "core" ); - CommitCraftTemplate validTemplate = new CommitCraftTemplate("feat-{scope}", "Standard commit", "feat-{scope}", model); + CommitCraftTemplate invalidTemplate = new CommitCraftTemplate("feat-{scope}-{message}", "Invalid commit", "feat-{scope}-{message}", model); - boolean result = CommitDedicatedTemplateValidator.validatePatternAndModelScope(validTemplate); + ValidationResult result = CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(invalidTemplate); - assertFalse(result); - assertFalse(listAppender.list.stream().anyMatch(event -> event.getMessage().contains("Pattern matches the model keys."))); + assertFalse(result.isValid()); + assertEquals("Invalid template format: Keys missing in pattern: [type]", result.getErrorMessage()); } @Test - void testValidatePatternAndModelScope_missingModelKey() { + void shouldValidatePatternAndModelScope_ExtraModelKey() { Map model = Map.of( "type", "feat", - "scope", "core" + "scope", "core", + "extraKey", "extra" ); - CommitCraftTemplate invalidTemplate = new CommitCraftTemplate("feat-{scope}-{extraKey}", "Invalid commit", "feat-{scope}-{extraKey}", model); + CommitCraftTemplate invalidTemplate = new CommitCraftTemplate("feat-{scope}", "Invalid commit", "feat-{scope}", model); - boolean result = CommitDedicatedTemplateValidator.validatePatternAndModelScope(invalidTemplate); + ValidationResult result = CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(invalidTemplate); - assertFalse(result); - assertFalse(listAppender.list.stream().anyMatch(event -> event.getMessage().contains("Pattern contains an extra key not in the model: extraKey"))); + assertFalse(result.isValid()); + assertEquals("Invalid template format: Keys missing in pattern: [extraKey, type]", result.getErrorMessage()); } @Test - void testValidatePatternAndModelScope_extraModelKey() { + void shouldValidatePatternAndModelScope_BothMissingAndExtraKeys() { Map model = Map.of( "type", "feat", "scope", "core", - "message", "extra" + "extraKey", "extra" ); - CommitCraftTemplate invalidTemplate = new CommitCraftTemplate("feat-{scope}", "Invalid commit", "feat-{scope}", model); + CommitCraftTemplate invalidTemplate = new CommitCraftTemplate("feat-{scope}-{message}", "Invalid commit", "feat-{scope}-{message}", model); - boolean result = CommitDedicatedTemplateValidator.validatePatternAndModelScope(invalidTemplate); + ValidationResult result = CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(invalidTemplate); - assertFalse(result); - assertFalse(listAppender.list.stream().anyMatch(event -> event.getMessage().contains("Pattern is missing key: message"))); + assertFalse(result.isValid()); + assertEquals("Invalid template format: Keys missing in pattern: [extraKey, type]; Missing keys in model: [message]", result.getErrorMessage()); } } \ No newline at end of file