package de.otto.wickettester; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; public class ComponentMatchers { public static class ComponentMatcherBuilder<T extends Component> { static class CollectingComponentMatcher<T extends Component, R> implements ComponentMatcher<T, R> { private final List<R> bucket; private final ComponentMatcher<T, R> componentMatcher; public CollectingComponentMatcher(final ComponentMatcher<T, R> matcher) { componentMatcher = matcher; bucket = new ArrayList<R>(); } public void addToBucket(final R element) { bucket.add(element); } public List<R> getBucket() { return bucket; } @Override public R match(final T component) { final R visited = componentMatcher.match(component); if (visited != null) { addToBucket(visited); } return null; } @Override public String criterionAsString() { return "a list of components"; } } private static class JoiningComponentMatcher<T extends Component> implements ComponentMatcher<T, T> { private final List<ComponentMatcher<T, T>> componentMatchers = new LinkedList<ComponentMatcher<T, T>>( Collections.singleton(new AllComponentMatcher<T>())); public JoiningComponentMatcher(final ComponentMatcher<T, T>... componentMatchers) { this.componentMatchers.addAll(Arrays.asList(componentMatchers)); } @Override public T match(final T component) { for (final ComponentMatcher<T, T> visitor : componentMatchers) { final T visited = visitor.match(component); if (visited == null) { return null; } } return component; } @Override public String criterionAsString() { final List<String> criteria = new LinkedList<String>(); for (final ComponentMatcher<T, T> visitor : componentMatchers) { criteria.add(visitor.criterionAsString()); } return StringUtils.join(criteria, " and "); } } private static class AllComponentMatcher<T extends Component> implements ComponentMatcher<T, T> { @Override public T match(final T component) { return component; } @Override public String criterionAsString() { return "being a component"; } } private final List<ComponentMatcher<T, T>> visitors = new LinkedList<ComponentMatcher<T, T>>(); public ComponentMatcherBuilder<T> wicketId(final String wicketId) { this.visitors.add(new WicketIdComponentMatcher<T>(wicketId)); return this; } public ComponentMatcherBuilder<T> visible() { this.visitors.add(new VisibleComponentMatcher<T>()); return this; } public ComponentMatcherBuilder<T> enabled() { this.visitors.add(new EnabledComponentMatcher<T>()); return this; } public ComponentMatcherBuilder<T> type(final Class<T> componentClass) { this.visitors.add(new TypeComponentMatcher<T>(componentClass)); return this; } public ComponentMatcherBuilder<T> visitedBy(final ComponentMatcher<T, T> visitor) { this.visitors.add(visitor); return this; } public <MT extends Component> ComponentMatcherBuilder<T> havingChild(final ComponentMatcherBuilder<MT> builder) { this.visitors.add(new HavingChildComponentMatcher<T, MT>(builder.build())); return this; } public <MT extends Component> ComponentMatcherBuilder<T> havingDirectChild(final ComponentMatcherBuilder<MT> builder) { this.visitors.add(new HavingDirectChildComponentMatcher<T, MT>(builder.build())); return this; } public <MT extends Component> ComponentMatcherBuilder<T> havingSibling(final ComponentMatcherBuilder<MT> builder) { this.visitors.add(new HavingSiblingComponentMatcher<T, MT>(builder.build())); return this; } public <MT extends MarkupContainer> ComponentMatcherBuilder<T> havingDirectParent( final ComponentMatcherBuilder<MT> builder) { this.visitors.add(new HavingDirectParentComponentMatcher<T, MT>(builder.build())); return this; } public ComponentMatcherBuilder<T> modelObject(final Object modelObject) { this.visitors.add(new ModelObjectComponentMatcher<T>(modelObject)); return this; } public ComponentMatcherBuilder<T> not(final ComponentMatcherBuilder<T> builder) { this.visitors.add(new NegatingComponentMatcher<T>(builder.build())); return this; } @SuppressWarnings("unchecked") public ComponentMatcher<T, T> build() { return new JoiningComponentMatcher<T>(visitors.toArray(new ComponentMatcher[visitors.size()])); } public CollectingComponentMatcher<T, T> buildCollecting() { return new CollectingComponentMatcher<T, T>(build()); } public Object criteriaAsString() { final List<String> criteria = new LinkedList<String>(); for (final ComponentMatcher<T, T> visitor : visitors) { criteria.add(visitor.criterionAsString()); } return StringUtils.join(criteria, " and "); } } public static <T extends Component> ComponentMatcherBuilder<T> builder() { return new ComponentMatcherBuilder<T>(); } public static <T extends Component> ComponentMatcherBuilder<T> type(final Class<T> componentClass) { return ComponentMatchers.<T> builder().type(componentClass); } }