Skip to content

Commit

Permalink
A few tweaks to the component finder strategy, and how it's exposed v…
Browse files Browse the repository at this point in the history
…ia the DSL.
  • Loading branch information
simonbrowndotje committed Sep 13, 2024
1 parent 09d7f89 commit becf089
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*
* Use the {@link ComponentFinderStrategyBuilder} to create an instance of this class.
*/
class ComponentFinderStrategy {
public final class ComponentFinderStrategy {

private final String technology;
private final TypeMatcher typeMatcher;
Expand Down Expand Up @@ -66,8 +66,12 @@ void visit(Component component) {
@Override
public String toString() {
return "ComponentFinderStrategy{" +
"typeMatcher=" + typeMatcher +
"technology=" + (technology == null ? null : "'" + technology + "'") +
", typeMatcher=" + typeMatcher +
", typeFilter=" + typeFilter +
", supportingTypesStrategy=" + supportingTypesStrategy +
", namingStrategy=" + namingStrategy +
", componentVisitor=" + componentVisitor +
'}';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.structurizr.component.supporting.SupportingTypesStrategy;
import com.structurizr.component.visitor.ComponentVisitor;
import com.structurizr.component.visitor.DefaultComponentVisitor;
import com.structurizr.util.StringUtils;

/**
* Provides a way to create a {@link ComponentFinderStrategy} instance.
Expand All @@ -17,53 +18,117 @@ public final class ComponentFinderStrategyBuilder {

private String technology;
private TypeMatcher typeMatcher;
private TypeFilter typeFilter = new DefaultTypeFilter();
private SupportingTypesStrategy supportingTypesStrategy = new DefaultSupportingTypesStrategy();
private NamingStrategy namingStrategy = new DefaultNamingStrategy();
private ComponentVisitor componentVisitor = new DefaultComponentVisitor();
private TypeFilter typeFilter;
private SupportingTypesStrategy supportingTypesStrategy;
private NamingStrategy namingStrategy;
private ComponentVisitor componentVisitor;

public ComponentFinderStrategyBuilder() {
}

public ComponentFinderStrategyBuilder matchedBy(TypeMatcher typeMatcher) {
if (typeMatcher == null) {
throw new IllegalArgumentException("A type matcher must be provided");
}

if (this.typeMatcher != null) {
throw new IllegalArgumentException("A type matcher has already been configured");
}

this.typeMatcher = typeMatcher;

return this;
}

public ComponentFinderStrategyBuilder filteredBy(TypeFilter typeFilter) {
if (typeFilter == null) {
throw new IllegalArgumentException("A type filter must be provided");
}

if (this.typeFilter != null) {
throw new IllegalArgumentException("A type filter has already been configured");
}

this.typeFilter = typeFilter;

return this;
}

public ComponentFinderStrategyBuilder supportedBy(SupportingTypesStrategy supportingTypesStrategy) {
if (supportingTypesStrategy == null) {
throw new IllegalArgumentException("A supporting types strategy must be provided");
}

if (this.supportingTypesStrategy != null) {
throw new IllegalArgumentException("A supporting types strategy has already been configured");
}

this.supportingTypesStrategy = supportingTypesStrategy;

return this;
}

public ComponentFinderStrategyBuilder namedBy(NamingStrategy namingStrategy) {
if (namingStrategy == null) {
throw new IllegalArgumentException("A naming strategy must be provided");
}

if (this.namingStrategy != null) {
throw new IllegalArgumentException("A naming strategy has already been configured");
}

this.namingStrategy = namingStrategy;

return this;
}

public ComponentFinderStrategyBuilder asTechnology(String technology) {
if (StringUtils.isNullOrEmpty(technology)) {
throw new IllegalArgumentException("A technology must be provided");
}

if (!StringUtils.isNullOrEmpty(this.technology)) {
throw new IllegalArgumentException("A technology has already been configured");
}

this.technology = technology;

return this;
}

public ComponentFinderStrategyBuilder forEach(ComponentVisitor componentVisitor) {
if (componentVisitor == null) {
throw new IllegalArgumentException("A component visitor must be provided");
}

if (this.componentVisitor != null) {
throw new IllegalArgumentException("A component visitor has already been configured");
}

this.componentVisitor = componentVisitor;

return this;
}

public ComponentFinderStrategy build() {
if (typeMatcher == null) {
throw new RuntimeException("A type matcher must be specified");
throw new RuntimeException("A type matcher must be provided");
}

if (typeFilter == null) {
typeFilter = new DefaultTypeFilter();
}

if (supportingTypesStrategy == null) {
supportingTypesStrategy = new DefaultSupportingTypesStrategy();
}

if (namingStrategy == null) {
namingStrategy = new DefaultNamingStrategy();
}

if (componentVisitor == null) {
componentVisitor = new DefaultComponentVisitor();
}

return new ComponentFinderStrategy(technology, typeMatcher, typeFilter, supportingTypesStrategy, namingStrategy, componentVisitor);
Expand All @@ -72,7 +137,7 @@ public ComponentFinderStrategy build() {
@Override
public String toString() {
return "ComponentFinderStrategyBuilder{" +
"technology='" + technology + '\'' +
"technology=" + (technology == null ? null : "'" + technology + "'") +
", typeMatcher=" + typeMatcher +
", typeFilter=" + typeFilter +
", supportingTypesStrategy=" + supportingTypesStrategy +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public boolean matches(Type type) {
@Override
public String toString() {
return "RegexTypeMatcher{" +
"regex=" + regex +
"regex='" + regex + "'" +
'}';
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package com.structurizr.component;

import com.structurizr.component.filter.ExcludeTypesByRegexFilter;
import com.structurizr.component.filter.IncludeTypesByRegexFilter;
import com.structurizr.component.matcher.NameSuffixTypeMatcher;
import com.structurizr.component.naming.FullyQualifiedNamingStrategy;
import com.structurizr.component.naming.SimpleNamingStrategy;
import com.structurizr.component.supporting.AllTypesInPackageSupportingTypesStrategy;
import com.structurizr.component.supporting.AllTypesUnderPackageSupportingTypesStrategy;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.*;

public class ComponentFinderStrategyBuilderTests {

Expand All @@ -11,4 +18,114 @@ void build_ThrowsAnException_WhenATypeMatcherHasNotBeenConfigured() {
assertThrowsExactly(RuntimeException.class, () -> new ComponentFinderStrategyBuilder().build());
}

@Test
void matchedBy_ThrowsAnException_WhenPassedNull() {
try {
new ComponentFinderStrategyBuilder().matchedBy(null);
fail();
} catch (Exception e) {
assertEquals("A type matcher must be provided", e.getMessage());
}
}

@Test
void matchedBy_ThrowsAnException_WhenCalledTwice() {
try {
new ComponentFinderStrategyBuilder().matchedBy(new NameSuffixTypeMatcher("X")).matchedBy(new NameSuffixTypeMatcher("Y"));
fail();
} catch (Exception e) {
assertEquals("A type matcher has already been configured", e.getMessage());
}
}

@Test
void filteredBy_ThrowsAnException_WhenPassedNull() {
try {
new ComponentFinderStrategyBuilder().filteredBy(null);
fail();
} catch (Exception e) {
assertEquals("A type filter must be provided", e.getMessage());
}
}

@Test
void filteredBy_ThrowsAnException_WhenCalledTwice() {
try {
new ComponentFinderStrategyBuilder().filteredBy(new IncludeTypesByRegexFilter(".*")).filteredBy(new ExcludeTypesByRegexFilter(".*"));
fail();
} catch (Exception e) {
assertEquals("A type filter has already been configured", e.getMessage());
}
}

@Test
void supportedBy_ThrowsAnException_WhenPassedNull() {
try {
new ComponentFinderStrategyBuilder().supportedBy(null);
fail();
} catch (Exception e) {
assertEquals("A supporting types strategy must be provided", e.getMessage());
}
}

@Test
void supportedBy_ThrowsAnException_WhenCalledTwice() {
try {
new ComponentFinderStrategyBuilder().supportedBy(new AllTypesInPackageSupportingTypesStrategy()).supportedBy(new AllTypesUnderPackageSupportingTypesStrategy());
fail();
} catch (Exception e) {
assertEquals("A supporting types strategy has already been configured", e.getMessage());
}
}

@Test
void namedBy_ThrowsAnException_WhenPassedNull() {
try {
new ComponentFinderStrategyBuilder().namedBy(null);
fail();
} catch (Exception e) {
assertEquals("A naming strategy must be provided", e.getMessage());
}
}

@Test
void namedBy_ThrowsAnException_WhenCalledTwice() {
try {
new ComponentFinderStrategyBuilder().namedBy(new SimpleNamingStrategy()).namedBy(new FullyQualifiedNamingStrategy());
fail();
} catch (Exception e) {
assertEquals("A naming strategy has already been configured", e.getMessage());
}
}

@Test
void asTechnology_ThrowsAnException_WhenPassedNull() {
try {
new ComponentFinderStrategyBuilder().asTechnology(null);
fail();
} catch (Exception e) {
assertEquals("A technology must be provided", e.getMessage());
}
}

@Test
void asTechnology_ThrowsAnException_WhenPassedAnEmptyString() {
try {
new ComponentFinderStrategyBuilder().asTechnology("");
fail();
} catch (Exception e) {
assertEquals("A technology must be provided", e.getMessage());
}
}

@Test
void asTechnology_ThrowsAnException_WhenCalledTwice() {
try {
new ComponentFinderStrategyBuilder().asTechnology("X").asTechnology("Y");
fail();
} catch (Exception e) {
assertEquals("A technology has already been configured", e.getMessage());
}
}

}
Loading

0 comments on commit becf089

Please sign in to comment.