|
1 | 1 | package com.tngtech.archunit.library.freeze; |
2 | 2 |
|
3 | 3 | import java.io.File; |
| 4 | +import java.io.FileInputStream; |
4 | 5 | import java.io.IOException; |
5 | 6 | import java.nio.file.Path; |
6 | 7 | import java.util.ArrayList; |
@@ -53,8 +54,11 @@ public class FreezingArchRuleTest { |
53 | 54 |
|
54 | 55 | private static final String STORE_PROPERTY_NAME = "freeze.store"; |
55 | 56 | private static final String STORE_DEFAULT_PATH_PROPERTY_NAME = "freeze.store.default.path"; |
| 57 | + private static final String FREEZE_REFREEZE = "freeze.refreeze"; |
56 | 58 | private static final String ALLOW_STORE_CREATION_PROPERTY_NAME = "freeze.store.default.allowStoreCreation"; |
57 | 59 | private static final String ALLOW_STORE_UPDATE_PROPERTY_NAME = "freeze.store.default.allowStoreUpdate"; |
| 60 | + private static final String DELETE_EMPTY_RULE_VIOLATION_PROPERTY_NAME = "freeze.store.default.deleteEmptyRuleViolation"; |
| 61 | + private static final String WARN_EMPTY_RULE_VIOLATION_PROPERTY_NAME = "freeze.store.default.warnEmptyRuleViolation"; |
58 | 62 | private static final String LINE_MATCHER_PROPERTY_NAME = "freeze.lineMatcher"; |
59 | 63 |
|
60 | 64 | @Rule |
@@ -152,13 +156,13 @@ public void allows_to_overwrite_frozen_violations_if_configured() { |
152 | 156 | ArchRule anotherViolation = rule("some description").withViolations("first violation", "second violation").create(); |
153 | 157 | ArchRule frozenWithNewViolation = freeze(anotherViolation).persistIn(violationStore); |
154 | 158 |
|
155 | | - ArchConfiguration.get().setProperty("freeze.refreeze", Boolean.TRUE.toString()); |
| 159 | + ArchConfiguration.get().setProperty(FREEZE_REFREEZE, Boolean.TRUE.toString()); |
156 | 160 |
|
157 | 161 | assertThatRule(frozenWithNewViolation) |
158 | 162 | .checking(importClasses(getClass())) |
159 | 163 | .hasNoViolation(); |
160 | 164 |
|
161 | | - ArchConfiguration.get().setProperty("freeze.refreeze", Boolean.FALSE.toString()); |
| 165 | + ArchConfiguration.get().setProperty(FREEZE_REFREEZE, Boolean.FALSE.toString()); |
162 | 166 |
|
163 | 167 | assertThatRule(frozenWithNewViolation) |
164 | 168 | .checking(importClasses(getClass())) |
@@ -482,6 +486,72 @@ public void can_prevent_default_ViolationStore_from_updating_existing_rules() th |
482 | 486 | expectStoreUpdateDisabledException(() -> frozenRule.check(importClasses(getClass()))); |
483 | 487 | } |
484 | 488 |
|
| 489 | + @Test |
| 490 | + public void warns_when_default_ViolationStore_is_empty() throws IOException { |
| 491 | + useTemporaryDefaultStorePath(); |
| 492 | + ArchConfiguration.get().setProperty(ALLOW_STORE_CREATION_PROPERTY_NAME, "true"); |
| 493 | + ArchConfiguration.get().setProperty(FREEZE_REFREEZE, "true"); |
| 494 | + FreezingArchRule frozenRule = freeze(rule("some description").withoutViolations().create()); |
| 495 | + frozenRule.check(importClasses(getClass())); |
| 496 | + |
| 497 | + // disallowing empty violation file should throw |
| 498 | + ArchConfiguration.get().setProperty(WARN_EMPTY_RULE_VIOLATION_PROPERTY_NAME, "true"); |
| 499 | + assertThatThrownBy(() -> frozenRule.check(importClasses(getClass()))) |
| 500 | + .isInstanceOf(StoreEmptyException.class) |
| 501 | + .hasMessageContaining("Saving empty violations for freezing rule is disabled (enable by configuration " + WARN_EMPTY_RULE_VIOLATION_PROPERTY_NAME + "=true)"); |
| 502 | + } |
| 503 | + |
| 504 | + @Test |
| 505 | + public void warns_when_default_ViolationStore_gets_empty() throws IOException { |
| 506 | + useTemporaryDefaultStorePath(); |
| 507 | + ArchConfiguration.get().setProperty(ALLOW_STORE_CREATION_PROPERTY_NAME, "true"); |
| 508 | + RuleCreator someRule = rule("some description"); |
| 509 | + freeze(someRule.withViolations("remaining", "will be solved").create()).check(importClasses(getClass())); |
| 510 | + |
| 511 | + // disallowing empty violation file should throw |
| 512 | + ArchConfiguration.get().setProperty(WARN_EMPTY_RULE_VIOLATION_PROPERTY_NAME, "true"); |
| 513 | + FreezingArchRule frozenRule = freeze(someRule.withoutViolations().create()); |
| 514 | + assertThatThrownBy(() -> frozenRule.check(importClasses(getClass()))) |
| 515 | + .isInstanceOf(StoreEmptyException.class) |
| 516 | + .hasMessageContaining("Saving empty violations for freezing rule is disabled (enable by configuration " + WARN_EMPTY_RULE_VIOLATION_PROPERTY_NAME + "=true)"); |
| 517 | + } |
| 518 | + |
| 519 | + @Test |
| 520 | + public void can_skip_default_ViolationStore_creation_for_empty_violations() throws IOException { |
| 521 | + File storeFolder = useTemporaryDefaultStorePath(); |
| 522 | + ArchConfiguration.get().setProperty(STORE_PROPERTY_NAME, MyTextFileBasedViolationStore.class.getName()); |
| 523 | + ArchConfiguration.get().setProperty(ALLOW_STORE_CREATION_PROPERTY_NAME, "true"); |
| 524 | + ArchConfiguration.get().setProperty(DELETE_EMPTY_RULE_VIOLATION_PROPERTY_NAME, "true"); |
| 525 | + |
| 526 | + ArchRule rule = rule("some description").withoutViolations().create(); |
| 527 | + freeze(rule).check(importClasses(getClass())); |
| 528 | + |
| 529 | + assertThat(storeFolder.list()).containsOnly("stored.rules"); |
| 530 | + Properties properties = readProperties(storeFolder.toPath().resolve("stored.rules").toFile()); |
| 531 | + assertThat(properties).isEmpty(); |
| 532 | + } |
| 533 | + |
| 534 | + @Test |
| 535 | + public void can_delete_default_ViolationStore_rule_file_for_empty_violations() throws IOException { |
| 536 | + // given |
| 537 | + File storeFolder = useTemporaryDefaultStorePath(); |
| 538 | + ArchConfiguration.get().setProperty(STORE_PROPERTY_NAME, MyTextFileBasedViolationStore.class.getName()); |
| 539 | + ArchConfiguration.get().setProperty(ALLOW_STORE_CREATION_PROPERTY_NAME, "true"); |
| 540 | + ArchConfiguration.get().setProperty(DELETE_EMPTY_RULE_VIOLATION_PROPERTY_NAME, "true"); |
| 541 | + |
| 542 | + freeze(rule("some description").withViolations("violation 1").create()).check(importClasses(getClass())); |
| 543 | + assertThat(storeFolder.list()).containsOnly("stored.rules", "some description test"); |
| 544 | + |
| 545 | + // when |
| 546 | + ArchRule rule = rule("some description").withoutViolations().create(); |
| 547 | + freeze(rule).check(importClasses(getClass())); |
| 548 | + |
| 549 | + // then |
| 550 | + assertThat(storeFolder.list()).containsOnly("stored.rules"); |
| 551 | + Properties properties = readProperties(storeFolder.toPath().resolve("stored.rules").toFile()); |
| 552 | + assertThat(properties).isEmpty(); |
| 553 | + } |
| 554 | + |
485 | 555 | @Test |
486 | 556 | public void allows_to_adjust_default_store_file_names_via_delegation() throws IOException { |
487 | 557 | // GIVEN |
@@ -538,6 +608,14 @@ private File useTemporaryDefaultStorePath() throws IOException { |
538 | 608 | return folder; |
539 | 609 | } |
540 | 610 |
|
| 611 | + private Properties readProperties(File file) throws IOException { |
| 612 | + Properties properties = new Properties(); |
| 613 | + try (FileInputStream inputStream = new FileInputStream(file)) { |
| 614 | + properties.load(inputStream); |
| 615 | + } |
| 616 | + return properties; |
| 617 | + } |
| 618 | + |
541 | 619 | private static RuleCreator rule(String description) { |
542 | 620 | return new RuleCreator(description); |
543 | 621 | } |
|
0 commit comments