PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/plugin/src/test/java/com/atlassian/upm/test/osgi/PropertyMatchers.java

https://bitbucket.org/atlassian/atlassian-universal-plugin-manager
Java | 320 lines | 271 code | 48 blank | 1 comment | 7 complexity | bb74d569ae3643aef4d86f8cf390689b MD5 | raw file
  1. package com.atlassian.upm.test.osgi;
  2. import java.util.List;
  3. import java.util.Map;
  4. import java.util.Map.Entry;
  5. import javax.annotation.Nullable;
  6. import com.atlassian.upm.Functions;
  7. import com.google.common.base.Function;
  8. import org.hamcrest.Description;
  9. import org.hamcrest.Matcher;
  10. import org.hamcrest.SelfDescribing;
  11. import org.hamcrest.TypeSafeDiagnosingMatcher;
  12. import static com.atlassian.upm.Functions.applyEach;
  13. import static com.atlassian.upm.test.osgi.MatcherFunctions.MatcherFactory;
  14. import static com.atlassian.upm.test.osgi.MatcherFunctions.MatcherFactoryTransformer;
  15. import static com.google.common.collect.ImmutableList.copyOf;
  16. import static java.util.Arrays.asList;
  17. import static org.hamcrest.Matchers.equalTo;
  18. public final class PropertyMatchers
  19. {
  20. public static final class PropertyExtractor<Parent, Child> implements Function<Parent, Child>, SelfDescribing
  21. {
  22. private final String name;
  23. private final Function<Parent, Child> propertyFn;
  24. public PropertyExtractor(String name, Function<Parent, Child> propertyFn)
  25. {
  26. this.name = name;
  27. this.propertyFn = propertyFn;
  28. }
  29. public Child apply(@Nullable Parent parent)
  30. {
  31. return propertyFn.apply(parent);
  32. }
  33. public void describeTo(Description description)
  34. {
  35. description.appendText(name);
  36. }
  37. }
  38. public static final class Property<Parent, OuterChild, InnerChild> implements MatcherFactory<Parent>
  39. {
  40. private final PropertyTransformer<Parent, OuterChild> propertyTransformer;
  41. private final MatcherFactoryTransformer<InnerChild, OuterChild> transformer;
  42. private Property(PropertyExtractor<Parent, OuterChild> extractor,
  43. MatcherFactoryTransformer<InnerChild, OuterChild> transformer)
  44. {
  45. this.propertyTransformer = new PropertyTransformer<Parent, OuterChild>(extractor);
  46. this.transformer = transformer;
  47. }
  48. public RefinedProperty<Parent, OuterChild, InnerChild> by(MatcherFactory<InnerChild>... subProperties)
  49. {
  50. return new RefinedProperty<Parent, OuterChild, InnerChild>(propertyTransformer, transformer, subProperties);
  51. }
  52. public Matcher<? super Parent> apply(@Nullable Parent expected)
  53. {
  54. return propertyTransformer.apply(
  55. transformer.apply(
  56. new EqualToFactory<InnerChild>())).apply(expected);
  57. }
  58. }
  59. public static final class RefinedProperty<Parent, OuterChild, InnerChild> implements MatcherFactory<Parent>
  60. {
  61. private final PropertyTransformer<Parent, OuterChild> propertyTransformer;
  62. private final MatcherFactoryTransformer<InnerChild, OuterChild> transformer;
  63. private final Iterable<MatcherFactory<InnerChild>> subProperties;
  64. private RefinedProperty(PropertyTransformer<Parent, OuterChild> propertyTransformer,
  65. MatcherFactoryTransformer<InnerChild, OuterChild> transformer,
  66. MatcherFactory<InnerChild>... subProperties)
  67. {
  68. this.propertyTransformer = propertyTransformer;
  69. this.transformer = transformer;
  70. this.subProperties = copyOf(asList(subProperties));
  71. }
  72. public Matcher<? super Parent> apply(@Nullable Parent expected)
  73. {
  74. return propertyTransformer.apply(
  75. transformer.apply(
  76. new SubPropertyMatcherFactory<InnerChild>(subProperties))).apply(expected);
  77. }
  78. }
  79. private static final class PropertyMatcher<Parent, Child> extends TypeSafeDiagnosingMatcher<Parent>
  80. {
  81. private final PropertyExtractor<Parent, Child> extractor;
  82. private final Matcher<? super Child> childMatcher;
  83. private PropertyMatcher(PropertyExtractor<Parent, Child> extractor, Matcher<? super Child> childMatcher)
  84. {
  85. this.extractor = extractor;
  86. this.childMatcher = childMatcher;
  87. }
  88. protected boolean matchesSafely(Parent item, Description mismatchDescription)
  89. {
  90. Child actual = extractor.apply(item);
  91. if (!childMatcher.matches(actual))
  92. {
  93. childMatcher.describeMismatch(actual,
  94. mismatchDescription
  95. .appendDescriptionOf(extractor)
  96. .appendText(" "));
  97. return false;
  98. }
  99. return true;
  100. }
  101. public void describeTo(Description description)
  102. {
  103. description
  104. .appendDescriptionOf(extractor)
  105. .appendText(" ")
  106. .appendDescriptionOf(childMatcher);
  107. }
  108. }
  109. private static final class PropertyMatcherFactory<Parent, Child> implements MatcherFactory<Parent>
  110. {
  111. private final PropertyExtractor<Parent, Child> extractor;
  112. private final MatcherFactory<Child> childMatcherFactory;
  113. private PropertyMatcherFactory(PropertyExtractor<Parent, Child> extractor, MatcherFactory<Child> childMatcherFactory)
  114. {
  115. this.extractor = extractor;
  116. this.childMatcherFactory = childMatcherFactory;
  117. }
  118. public Matcher<? super Parent> apply(@Nullable Parent expected)
  119. {
  120. return new PropertyMatcher<Parent, Child>(extractor, childMatcherFactory.apply(extractor.apply(expected)));
  121. }
  122. }
  123. private static final class PropertyTransformer<Parent, Child> implements MatcherFactoryTransformer<Child, Parent>
  124. {
  125. private final PropertyExtractor<Parent, Child> extractor;
  126. private PropertyTransformer(PropertyExtractor<Parent, Child> extractor)
  127. {
  128. this.extractor = extractor;
  129. }
  130. public MatcherFactory<Parent> apply(@Nullable MatcherFactory<Child> childMatcherFactory)
  131. {
  132. return new PropertyMatcherFactory<Parent, Child>(extractor, childMatcherFactory);
  133. }
  134. }
  135. private static final class EqualToFactory<T> implements MatcherFactory<T>
  136. {
  137. public Matcher<? super T> apply(@Nullable T expected)
  138. {
  139. return equalTo(expected);
  140. }
  141. }
  142. private static final class SubPropertyMatcher<Child> extends TypeSafeDiagnosingMatcher<Child>
  143. {
  144. private final List<Matcher<? super Child>> subPropertyMatchers;
  145. private SubPropertyMatcher(@Nullable Child expected,
  146. Iterable<MatcherFactory<Child>> subProperties)
  147. {
  148. this.subPropertyMatchers = copyOf(applyEach(subProperties, expected));
  149. }
  150. protected boolean matchesSafely(Child item, Description mismatchDescription)
  151. {
  152. boolean matches = true;
  153. for (org.hamcrest.Matcher<? super Child> subPropertyMatcher : subPropertyMatchers)
  154. {
  155. if (!subPropertyMatcher.matches(item))
  156. {
  157. if (!matches)
  158. {
  159. mismatchDescription.appendText(", ");
  160. }
  161. subPropertyMatcher.describeMismatch(item, mismatchDescription);
  162. matches = false;
  163. }
  164. }
  165. return matches;
  166. }
  167. public void describeTo(Description description)
  168. {
  169. for (int i = 0; i < subPropertyMatchers.size(); ++i)
  170. {
  171. if (i != 0)
  172. {
  173. description.appendText(i < subPropertyMatchers.size() - 1 ? ", " : " and ");
  174. }
  175. description.appendDescriptionOf(subPropertyMatchers.get(i));
  176. }
  177. }
  178. }
  179. private static final class SubPropertyMatcherFactory<Child> implements MatcherFactory<Child>
  180. {
  181. private final Iterable<MatcherFactory<Child>> subProperties;
  182. private SubPropertyMatcherFactory(Iterable<MatcherFactory<Child>> subProperties)
  183. {
  184. this.subProperties = subProperties;
  185. }
  186. public Matcher<? super Child> apply(@Nullable Child expected)
  187. {
  188. return new SubPropertyMatcher<Child>(expected, subProperties);
  189. }
  190. }
  191. public static final class Binder<T>
  192. {
  193. private final String name;
  194. private final T expected;
  195. private Binder(String name, T expected)
  196. {
  197. this.name = name;
  198. this.expected = expected;
  199. }
  200. public Matcher<? super T> by(MatcherFactory<T>... properties)
  201. {
  202. return property(name, com.google.common.base.Functions.<T>identity()).by(properties).apply(expected);
  203. }
  204. }
  205. public static <Parent, Child> Property<Parent, Child, Child> property(String name, Function<Parent, Child> propertyFn)
  206. {
  207. return new Property<Parent, Child, Child>(
  208. new PropertyExtractor<Parent, Child>(name, propertyFn),
  209. MatcherFunctions.<Child> identity());
  210. }
  211. public static <Parent, Child> Property<Parent, Child, Child> property(String name)
  212. {
  213. return property(name, Functions.<Parent, Child> getter(name));
  214. }
  215. public static <Parent, Child> Property<Parent, Iterable<Child>, Child> iterableProperty(String name, Function<Parent, Iterable<Child>> propertyFn)
  216. {
  217. return new Property<Parent, Iterable<Child>, Child>(
  218. new PropertyExtractor<Parent, Iterable<Child>>(name, propertyFn),
  219. MatcherFunctions.<Child> iterable());
  220. }
  221. public static <Parent, Child> Property<Parent, Iterable<Child>, Child> iterableProperty(String name)
  222. {
  223. return iterableProperty(name, Functions.<Parent, Iterable<Child>> getter(name));
  224. }
  225. public static <K, V> Property<Entry<K, V>, K, K> key(String name)
  226. {
  227. return property(name, new Function<Entry<K, V>, K>()
  228. {
  229. public K apply(@Nullable Entry<K, V> entry)
  230. {
  231. return entry.getKey();
  232. }
  233. });
  234. }
  235. public static <K, V> Property<Entry<K, V>, V, V> value(String name)
  236. {
  237. return property(name, new Function<Entry<K, V>, V>()
  238. {
  239. public V apply(@Nullable Entry<K, V> entry)
  240. {
  241. return entry.getValue();
  242. }
  243. });
  244. }
  245. // ewww, i need a better way to compose this stuff
  246. public static <K, V> Property<Entry<K, Iterable<V>>, Iterable<V>, V> iterableValue(String name)
  247. {
  248. return iterableProperty(name, new Function<Entry<K, Iterable<V>>, Iterable<V>>()
  249. {
  250. public Iterable<V> apply(@Nullable Entry<K, Iterable<V>> entry)
  251. {
  252. return entry.getValue();
  253. }
  254. });
  255. }
  256. public static <Parent, K, V> Property<Parent, Map<K, V>, Entry<K, V>>
  257. mapProperty(String name, Function<Parent, Map<K, V>> propertyFn)
  258. {
  259. return new Property<Parent, Map<K, V>, Entry<K, V>>(
  260. new PropertyExtractor<Parent, Map<K, V>>(name, propertyFn),
  261. MatcherFunctions.<K, V> map());
  262. }
  263. public static <Parent, K, V> Property<Parent, Map<K, V>, Entry<K, V>>
  264. mapProperty(String name)
  265. {
  266. return mapProperty(name, Functions.<Parent, Map<K, V>> getter(name));
  267. }
  268. public static <T> Binder<T> matches(String name, T expected)
  269. {
  270. return new Binder<T>(name, expected);
  271. }
  272. }