PageRenderTime 71ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/testing/src/main/java/com/atlassian/streams/testing/matchers/Matchers.java

https://bitbucket.org/atlassian/atlassian-streams
Java | 1266 lines | 1075 code | 186 blank | 5 comment | 65 complexity | e81b60f5a91172b3a4a2553ef4e75e68 MD5 | raw file
  1. package com.atlassian.streams.testing.matchers;
  2. import java.util.Collection;
  3. import java.util.Date;
  4. import java.util.List;
  5. import javax.xml.namespace.QName;
  6. import com.atlassian.streams.api.StreamsEntry;
  7. import com.google.common.base.Predicate;
  8. import com.google.common.collect.ImmutableList;
  9. import com.google.common.collect.Ordering;
  10. import org.apache.abdera.ext.thread.InReplyTo;
  11. import org.apache.abdera.model.Category;
  12. import org.apache.abdera.model.Element;
  13. import org.apache.abdera.model.Entry;
  14. import org.apache.abdera.model.ExtensibleElement;
  15. import org.apache.abdera.model.Link;
  16. import org.apache.abdera.model.Person;
  17. import org.apache.abdera.model.Text;
  18. import org.apache.abdera.parser.stax.FOMGenerator;
  19. import org.apache.abdera.util.Constants;
  20. import org.hamcrest.Description;
  21. import org.hamcrest.Matcher;
  22. import org.hamcrest.TypeSafeDiagnosingMatcher;
  23. import org.hamcrest.TypeSafeMatcher;
  24. import org.joda.time.DateTime;
  25. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.ACTIVITY_OBJECT;
  26. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.ACTIVITY_OBJECT_TYPE;
  27. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.ACTIVITY_TARGET;
  28. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.ACTIVITY_VERB;
  29. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.ATLASSIAN_APPLICATION;
  30. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.IN_REPLY_TO;
  31. import static com.atlassian.streams.testing.matchers.Matchers.AtomConstants.USR_USERNAME;
  32. import static com.google.common.collect.Collections2.filter;
  33. import static com.google.common.collect.Iterables.any;
  34. import static com.google.common.collect.Iterables.getOnlyElement;
  35. import static com.google.common.collect.Iterables.isEmpty;
  36. import static com.google.common.collect.Iterables.size;
  37. import static java.util.Arrays.asList;
  38. import static org.hamcrest.Matchers.allOf;
  39. import static org.hamcrest.Matchers.contains;
  40. import static org.hamcrest.Matchers.containsInAnyOrder;
  41. import static org.hamcrest.Matchers.everyItem;
  42. import static org.hamcrest.Matchers.hasItem;
  43. public abstract class Matchers
  44. {
  45. public static Matcher<Iterable<? extends Entry>> hasNoEntries()
  46. {
  47. return org.hamcrest.Matchers.emptyIterable();
  48. }
  49. public static Matcher<Iterable<? extends Entry>> allEntries(Matcher<Entry> matchers)
  50. {
  51. return everyItem(matchers);
  52. }
  53. public static Matcher<? super Iterable<? super Entry>> hasEntry(Matcher<? super Entry> matcher)
  54. {
  55. return hasItem(matcher);
  56. }
  57. @SuppressWarnings("unchecked")
  58. public static Matcher<? super Iterable<? super Entry>> hasEntry(Matcher<? super Entry> m1, Matcher<? super Entry> m2)
  59. {
  60. return hasItem(allOf(m1, m2));
  61. }
  62. @SuppressWarnings("unchecked")
  63. public static Matcher<? super Iterable<? super Entry>> hasEntry(Matcher<? super Entry> m1, Matcher<? super Entry> m2, Matcher<? super Entry> m3)
  64. {
  65. return hasItem(allOf(m1, m2, m3));
  66. }
  67. public static Matcher<? super Iterable<? super Entry>> hasEntry(Matcher<? super Entry>... matchers)
  68. {
  69. return hasItem(allOf(matchers));
  70. }
  71. public static Matcher<Iterable<? extends Entry>> hasEntries(Matcher<? super Entry> m)
  72. {
  73. return hasEntries(ImmutableList.of(m));
  74. }
  75. public static Matcher<Iterable<? extends Entry>> hasEntries(Matcher<? super Entry> m1, Matcher<? super Entry> m2)
  76. {
  77. return hasEntries(ImmutableList.<Matcher<? super Entry>>of(m1, m2));
  78. }
  79. public static Matcher<Iterable<? extends Entry>> hasEntries(Matcher<? super Entry> m1, Matcher<? super Entry> m2, Matcher<? super Entry> m3)
  80. {
  81. return hasEntries(ImmutableList.<Matcher<? super Entry>>of(m1, m2, m3));
  82. }
  83. public static Matcher<Iterable<? extends Entry>> hasEntries(Matcher<? super Entry> m1, Matcher<? super Entry> m2, Matcher<? super Entry> m3, Matcher<? super Entry> m4)
  84. {
  85. return hasEntries(ImmutableList.<Matcher<? super Entry>>of(m1, m2, m3, m4));
  86. }
  87. public static Matcher<Iterable<? extends Entry>> hasEntries(Matcher<? super Entry>... matchers)
  88. {
  89. return hasEntries(asList(matchers));
  90. }
  91. public static Matcher<Iterable<? extends Entry>> hasEntries(List<Matcher<? super Entry>> matchers)
  92. {
  93. return contains(matchers);
  94. }
  95. public static Matcher<Iterable<? extends Element>> hasElements(Matcher<? super Element> matcher)
  96. {
  97. return hasElements(ImmutableList.of(matcher));
  98. }
  99. public static Matcher<Iterable<? extends Element>> hasElements(Matcher<? super Element> m1, Matcher<? super Element> m2)
  100. {
  101. return hasElements(ImmutableList.<Matcher<? super Element>>of(m1, m2));
  102. }
  103. public static Matcher<Iterable<? extends Element>> hasElements(Matcher<? super Element> m1, Matcher<? super Element> m2, Matcher<? super Element> m3)
  104. {
  105. return hasElements(ImmutableList.<Matcher<? super Element>>of(m1, m2, m3));
  106. }
  107. public static Matcher<Iterable<? extends Entry>> hasEntriesInAnyOrder(Matcher<? super Entry>... matchers)
  108. {
  109. return hasEntriesInAnyOrder(asList(matchers));
  110. }
  111. public static Matcher<Iterable<? extends Entry>> hasEntriesInAnyOrder(List<Matcher<? super Entry>> matchers)
  112. {
  113. return containsInAnyOrder(matchers);
  114. }
  115. public static Matcher<Iterable<? extends Element>> hasElements(Matcher<? super Element>... matchers)
  116. {
  117. return hasElements(ImmutableList.copyOf(matchers));
  118. }
  119. public static Matcher<Iterable<? extends Element>> hasElements(List<Matcher<? super Element>> matchers)
  120. {
  121. return contains(matchers);
  122. }
  123. public static Matcher<Iterable<? extends ExtensibleElement>> hasActivityObjects(Matcher<? super ExtensibleElement> matcher)
  124. {
  125. return hasActivityObjects(ImmutableList.of(matcher));
  126. }
  127. public static Matcher<Iterable<? extends ExtensibleElement>> hasActivityObjects(Matcher<? super ExtensibleElement> m1, Matcher<? super ExtensibleElement> m2)
  128. {
  129. return hasActivityObjects(ImmutableList.<Matcher<? super ExtensibleElement>>of(m1, m2));
  130. }
  131. public static Matcher<Iterable<? extends ExtensibleElement>> hasActivityObjects(Matcher<? super ExtensibleElement> m1, Matcher<? super ExtensibleElement> m2, Matcher<? super ExtensibleElement> m3)
  132. {
  133. return hasActivityObjects(ImmutableList.<Matcher<? super ExtensibleElement>>of(m1, m2, m3));
  134. }
  135. public static Matcher<Iterable<? extends ExtensibleElement>> hasActivityObjects(Matcher<? super ExtensibleElement>... matchers)
  136. {
  137. return hasActivityObjects(ImmutableList.copyOf(matchers));
  138. }
  139. public static Matcher<Iterable<? extends ExtensibleElement>> hasActivityObjects(List<Matcher<? super ExtensibleElement>> matchers)
  140. {
  141. return contains(matchers);
  142. }
  143. public static Matcher<Entry> hasTarget(Matcher<? super ExtensibleElement> matcher)
  144. {
  145. return new HasTarget(matcher);
  146. }
  147. private static final class HasTarget extends TypeSafeDiagnosingMatcher<Entry>
  148. {
  149. private final Matcher<? super ExtensibleElement> matcher;
  150. public HasTarget(Matcher<? super ExtensibleElement> matcher)
  151. {
  152. this.matcher = matcher;
  153. }
  154. @Override
  155. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  156. {
  157. Iterable<ExtensibleElement> targets = entry.getExtensions(ACTIVITY_TARGET);
  158. if (isEmpty(targets))
  159. {
  160. mismatchDescription.appendText("no activity target");
  161. return false;
  162. }
  163. if (!matcher.matches(getOnlyElement(targets)))
  164. {
  165. mismatchDescription.appendText("target ");
  166. matcher.describeMismatch(getOnlyElement(targets), mismatchDescription);
  167. return false;
  168. }
  169. return true;
  170. }
  171. public void describeTo(Description description)
  172. {
  173. description.appendText("target where ").appendDescriptionOf(matcher);
  174. }
  175. }
  176. public static Matcher<Entry> withPublishedDate(Matcher<? super DateTime> matcher)
  177. {
  178. return new WithPublishedDate(matcher);
  179. }
  180. private static final class WithPublishedDate extends TypeSafeDiagnosingMatcher<Entry>
  181. {
  182. private final Matcher<? super DateTime> matcher;
  183. public WithPublishedDate(Matcher<? super DateTime> matcher)
  184. {
  185. this.matcher = matcher;
  186. }
  187. @Override
  188. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  189. {
  190. if (!matcher.matches(new DateTime(entry.getPublished())))
  191. {
  192. mismatchDescription.appendText("publishedDate ");
  193. matcher.describeMismatch(entry.getPublished(), mismatchDescription);
  194. return false;
  195. }
  196. return true;
  197. }
  198. public void describeTo(Description description)
  199. {
  200. description.appendText("publishedDate ").appendDescriptionOf(matcher);
  201. }
  202. }
  203. private static final class IsTitleHtml extends TypeSafeDiagnosingMatcher<Entry>
  204. {
  205. @Override
  206. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  207. {
  208. if (entry.getTitleType() == Text.Type.HTML)
  209. {
  210. return true;
  211. }
  212. mismatchDescription.appendText("title type is not HTML");
  213. return false;
  214. }
  215. public void describeTo(Description description)
  216. {
  217. description.appendText("title is html");
  218. }
  219. }
  220. public static Matcher<Entry> withTitle(Matcher<? super String> matcher)
  221. {
  222. return new WithTitle(matcher);
  223. }
  224. public static Matcher<Entry> withHtmlTitle(Matcher<? super String> matcher)
  225. {
  226. return allOf(new IsTitleHtml(), new WithTitle(matcher));
  227. }
  228. public static Matcher<Entry> withCategory(Matcher<Category> matcher)
  229. {
  230. return new WithCategory(matcher);
  231. }
  232. public static Matcher<Category> withTerm(Matcher<? super String> matcher)
  233. {
  234. return new WithTerm(matcher);
  235. }
  236. public static Matcher<Entry> hasAuthor(Matcher<Element> matcher)
  237. {
  238. return new HasAuthor(matcher);
  239. }
  240. private static final class HasAuthor extends TypeSafeDiagnosingMatcher<Entry>
  241. {
  242. private final Matcher<Element> matcher;
  243. public HasAuthor(Matcher<Element> matcher)
  244. {
  245. this.matcher = matcher;
  246. }
  247. @Override
  248. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  249. {
  250. if (entry.getAuthor() == null)
  251. {
  252. mismatchDescription.appendText("no author");
  253. return false;
  254. }
  255. if (!matcher.matches(entry.getAuthor()))
  256. {
  257. mismatchDescription.appendText("author ");
  258. matcher.describeMismatch(entry.getAuthor(), mismatchDescription);
  259. return false;
  260. }
  261. return true;
  262. }
  263. public void describeTo(Description description)
  264. {
  265. description.appendText("author ").appendDescriptionOf(matcher);
  266. }
  267. }
  268. public static Matcher<Element> withLink(Matcher<Link> matcher)
  269. {
  270. return new WithLink(matcher);
  271. }
  272. private static final class WithLink extends TypeSafeDiagnosingMatcher<Element>
  273. {
  274. private final Matcher<Link> matcher;
  275. public WithLink(Matcher<Link> matcher)
  276. {
  277. this.matcher = matcher;
  278. }
  279. @Override
  280. protected boolean matchesSafely(Element element, Description mismatchDescription)
  281. {
  282. Collection<Element> linkElements = filter(element.getElements(), linkPredicate);
  283. if (linkElements.size() != 0)
  284. {
  285. for (Element linkElement : linkElements)
  286. {
  287. Link link = (Link) linkElement;
  288. if (!matcher.matches(link))
  289. {
  290. mismatchDescription.appendText("link ");
  291. matcher.describeMismatch(link, mismatchDescription);
  292. return false;
  293. }
  294. }
  295. }
  296. return true;
  297. }
  298. public void describeTo(Description description)
  299. {
  300. description.appendText("link ").appendDescriptionOf(matcher);
  301. }
  302. }
  303. private static final Predicate<Element> linkPredicate = new Predicate<Element>()
  304. {
  305. public boolean apply(Element element)
  306. {
  307. return element instanceof Link;
  308. }
  309. };
  310. public static Matcher<Link> whereRel(Matcher<? super String> matcher)
  311. {
  312. return new WhereRel(matcher);
  313. }
  314. private static final class WhereRel extends TypeSafeDiagnosingMatcher<Link>
  315. {
  316. private final Matcher<? super String> matcher;
  317. public WhereRel(Matcher<? super String> matcher)
  318. {
  319. this.matcher = matcher;
  320. }
  321. @Override
  322. protected boolean matchesSafely(Link link, Description mismatchDescription)
  323. {
  324. if (link == null)
  325. {
  326. mismatchDescription.appendText("no link");
  327. return false;
  328. }
  329. if (!matcher.matches(link.getRel()))
  330. {
  331. mismatchDescription.appendText("rel ");
  332. matcher.describeMismatch(link.getRel(), mismatchDescription);
  333. return false;
  334. }
  335. return true;
  336. }
  337. public void describeTo(Description description)
  338. {
  339. description.appendText("rel ").appendDescriptionOf(matcher);
  340. }
  341. }
  342. public static Matcher<Link> whereHref(Matcher<? super String> matcher)
  343. {
  344. return new WhereHref(matcher);
  345. }
  346. private static final class WhereHref extends TypeSafeDiagnosingMatcher<Link>
  347. {
  348. private final Matcher<? super String> matcher;
  349. public WhereHref(Matcher<? super String> matcher)
  350. {
  351. this.matcher = matcher;
  352. }
  353. @Override
  354. protected boolean matchesSafely(Link link, Description mismatchDescription)
  355. {
  356. if (link == null)
  357. {
  358. mismatchDescription.appendText("no link");
  359. return false;
  360. }
  361. if (!matcher.matches(link.getHref().toASCIIString()))
  362. {
  363. mismatchDescription.appendText("href ");
  364. matcher.describeMismatch(link.getHref(), mismatchDescription);
  365. return false;
  366. }
  367. return true;
  368. }
  369. public void describeTo(Description description)
  370. {
  371. description.appendText("href ").appendDescriptionOf(matcher);
  372. }
  373. }
  374. private static final class WithTitle extends TypeSafeDiagnosingMatcher<Entry>
  375. {
  376. private final Matcher<? super String> matcher;
  377. private WithTitle(Matcher<? super String> matcher)
  378. {
  379. this.matcher = matcher;
  380. }
  381. @Override
  382. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  383. {
  384. if (!matcher.matches(entry.getTitle()))
  385. {
  386. mismatchDescription.appendText("title ");
  387. matcher.describeMismatch(entry.getTitle(), mismatchDescription);
  388. return false;
  389. }
  390. return true;
  391. }
  392. public void describeTo(Description description)
  393. {
  394. description.appendText("title is").appendDescriptionOf(matcher);
  395. }
  396. }
  397. private static final class WithCategory extends TypeSafeDiagnosingMatcher<Entry>
  398. {
  399. private final Matcher<Category> matcher;
  400. private WithCategory(Matcher<Category> matcher)
  401. {
  402. this.matcher = matcher;
  403. }
  404. @Override
  405. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  406. {
  407. for (Category category : entry.getCategories())
  408. {
  409. if (matcher.matches(category))
  410. {
  411. return true;
  412. }
  413. }
  414. //this point is only reached upon failures
  415. mismatchDescription.appendText("category ");
  416. matcher.describeMismatch(entry.getCategories(), mismatchDescription);
  417. return false;
  418. }
  419. public void describeTo(Description description)
  420. {
  421. description.appendText("category has").appendDescriptionOf(matcher);
  422. }
  423. }
  424. private static final class WithTerm extends TypeSafeDiagnosingMatcher<Category>
  425. {
  426. private final Matcher<? super String> matcher;
  427. private WithTerm(Matcher<? super String> matcher)
  428. {
  429. this.matcher = matcher;
  430. }
  431. @Override
  432. protected boolean matchesSafely(Category category, Description mismatchDescription)
  433. {
  434. if (!matcher.matches(category.getTerm()))
  435. {
  436. mismatchDescription.appendText("term ");
  437. matcher.describeMismatch(category.getTerm(), mismatchDescription);
  438. return false;
  439. }
  440. return true;
  441. }
  442. public void describeTo(Description description)
  443. {
  444. description.appendText("term is").appendDescriptionOf(matcher);
  445. }
  446. }
  447. public static Matcher<? super Element> withText(Matcher<? super String> matcher)
  448. {
  449. return new WithText(matcher);
  450. }
  451. private static final class WithText extends TypeSafeDiagnosingMatcher<Element>
  452. {
  453. private final Matcher<? super String> matcher;
  454. private WithText(Matcher<? super String> matcher)
  455. {
  456. this.matcher = matcher;
  457. }
  458. @Override
  459. protected boolean matchesSafely(Element element, Description mismatchDescription)
  460. {
  461. if (!matcher.matches(element.getText()))
  462. {
  463. mismatchDescription.appendText("title ");
  464. matcher.describeMismatch(element.getText(), mismatchDescription);
  465. return false;
  466. }
  467. return true;
  468. }
  469. public void describeTo(Description description)
  470. {
  471. description.appendText("text is ").appendDescriptionOf(matcher);
  472. }
  473. }
  474. public static Matcher<? super ExtensibleElement> withId(Matcher<? super String> matcher)
  475. {
  476. return new WithId(matcher);
  477. }
  478. private static final class WithId extends TypeSafeDiagnosingMatcher<ExtensibleElement>
  479. {
  480. private final Matcher<? super String> matcher;
  481. private WithId(Matcher<? super String> matcher)
  482. {
  483. this.matcher = matcher;
  484. }
  485. @Override
  486. protected boolean matchesSafely(ExtensibleElement element, Description mismatchDescription)
  487. {
  488. if (!matcher.matches(element.getSimpleExtension(Constants.ID)))
  489. {
  490. mismatchDescription.appendText("id ");
  491. matcher.describeMismatch(element.getSimpleExtension(Constants.ID), mismatchDescription);
  492. return false;
  493. }
  494. return true;
  495. }
  496. public void describeTo(Description description)
  497. {
  498. description.appendText("id is ").appendDescriptionOf(matcher);
  499. }
  500. }
  501. public static Matcher<? super ExtensibleElement> withType(Matcher<? super String> matcher)
  502. {
  503. return new WithType(matcher);
  504. }
  505. private static final class WithType extends TypeSafeDiagnosingMatcher<ExtensibleElement>
  506. {
  507. private final Matcher<? super String> matcher;
  508. private WithType(Matcher<? super String> matcher)
  509. {
  510. this.matcher = matcher;
  511. }
  512. @Override
  513. protected boolean matchesSafely(ExtensibleElement element, Description mismatchDescription)
  514. {
  515. if (!matcher.matches(element.getSimpleExtension(ACTIVITY_OBJECT_TYPE)))
  516. {
  517. mismatchDescription.appendText("activity:object-type ");
  518. matcher.describeMismatch(element.getSimpleExtension(ACTIVITY_OBJECT_TYPE), mismatchDescription);
  519. return false;
  520. }
  521. return true;
  522. }
  523. public void describeTo(Description description)
  524. {
  525. description.appendText("activity:object-type is ").appendDescriptionOf(matcher);
  526. }
  527. }
  528. public static Matcher<? super Entry> withSummary(Matcher<? super String> matcher)
  529. {
  530. return new WithSummary(matcher);
  531. }
  532. private static final class WithSummary extends TypeSafeDiagnosingMatcher<Entry>
  533. {
  534. private final Matcher<? super String> matcher;
  535. public WithSummary(Matcher<? super String> matcher)
  536. {
  537. this.matcher = matcher;
  538. }
  539. @Override
  540. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  541. {
  542. if (entry.getSummary() == null)
  543. {
  544. mismatchDescription.appendText("no summary");
  545. return false;
  546. }
  547. if (!matcher.matches(entry.getSummary()))
  548. {
  549. mismatchDescription.appendText("summary ");
  550. matcher.describeMismatch(entry.getSummary(), mismatchDescription);
  551. return false;
  552. }
  553. return true;
  554. }
  555. public void describeTo(Description description)
  556. {
  557. description.appendText("summary ").appendDescriptionOf(matcher);
  558. }
  559. }
  560. public static Matcher<Entry> withEmptyContent()
  561. {
  562. return new WithEmptyContent();
  563. }
  564. private static final class WithEmptyContent extends TypeSafeDiagnosingMatcher<Entry>
  565. {
  566. @Override
  567. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  568. {
  569. if (entry.getContent() == null)
  570. {
  571. return true;
  572. }
  573. mismatchDescription.appendText("content is not empty");
  574. return false;
  575. }
  576. public void describeTo(Description description)
  577. {
  578. description.appendText("content is empty");
  579. }
  580. }
  581. public static Matcher<Entry> withContent(Matcher<? super String> matcher)
  582. {
  583. return new WithContent(matcher);
  584. }
  585. private static final class WithContent extends TypeSafeDiagnosingMatcher<Entry>
  586. {
  587. private final Matcher<? super String> matcher;
  588. public WithContent(Matcher<? super String> matcher)
  589. {
  590. this.matcher = matcher;
  591. }
  592. @Override
  593. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  594. {
  595. if (entry.getContent() == null)
  596. {
  597. mismatchDescription.appendText("no content");
  598. return false;
  599. }
  600. if (!matcher.matches(entry.getContent()))
  601. {
  602. mismatchDescription.appendText("content ");
  603. matcher.describeMismatch(entry.getContent(), mismatchDescription);
  604. return false;
  605. }
  606. return true;
  607. }
  608. public void describeTo(Description description)
  609. {
  610. description.appendText("content ").appendDescriptionOf(matcher);
  611. }
  612. }
  613. public static Matcher<Entry> withUpdatedDate(Matcher<? super Date> matcher)
  614. {
  615. return new WithUpdatedDate(matcher);
  616. }
  617. private static final class WithUpdatedDate extends TypeSafeDiagnosingMatcher<Entry>
  618. {
  619. private final Matcher<? super Date> matcher;
  620. public WithUpdatedDate(Matcher<? super Date> matcher)
  621. {
  622. this.matcher = matcher;
  623. }
  624. @Override
  625. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  626. {
  627. if (entry.getUpdated() == null)
  628. {
  629. mismatchDescription.appendText("no updated date");
  630. return false;
  631. }
  632. if (!matcher.matches(entry.getUpdated()))
  633. {
  634. mismatchDescription.appendText("updated date ");
  635. matcher.describeMismatch(entry.getUpdated(), mismatchDescription);
  636. return false;
  637. }
  638. return true;
  639. }
  640. public void describeTo(Description description)
  641. {
  642. description.appendText("updated date ").appendDescriptionOf(matcher);
  643. }
  644. }
  645. public static Matcher<Entry> haveAtomSourceElement()
  646. {
  647. return new HaveAtomSourceElement();
  648. }
  649. private static final class HaveAtomSourceElement extends TypeSafeDiagnosingMatcher<Entry>
  650. {
  651. @Override
  652. protected boolean matchesSafely(Entry item, Description mismatchDescription)
  653. {
  654. if (item.getExtension(Constants.SOURCE) == null)
  655. {
  656. mismatchDescription.appendText("no atom:source element");
  657. return false;
  658. }
  659. return true;
  660. }
  661. public void describeTo(Description description)
  662. {
  663. description.appendText("an atom:source element");
  664. }
  665. }
  666. public static Matcher<Entry> haveAtlassianApplicationElement(Matcher<? super String> matcher)
  667. {
  668. return new HaveAtlassianApplicationElement(matcher);
  669. }
  670. private static final class HaveAtlassianApplicationElement extends TypeSafeDiagnosingMatcher<Entry>
  671. {
  672. private final Matcher<? super String> matcher;
  673. private HaveAtlassianApplicationElement(Matcher<? super String> matcher)
  674. {
  675. this.matcher = matcher;
  676. }
  677. @Override
  678. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  679. {
  680. String appType = entry.getSimpleExtension(ATLASSIAN_APPLICATION);
  681. if (appType == null)
  682. {
  683. mismatchDescription.appendText("no atlassian:application element");
  684. return false;
  685. }
  686. else if (!matcher.matches(appType))
  687. {
  688. mismatchDescription.appendText("atlassian:application element ");
  689. matcher.describeMismatch(appType, mismatchDescription);
  690. return false;
  691. }
  692. return true;
  693. }
  694. public void describeTo(Description description)
  695. {
  696. description.appendText("an atlassian:application element with ").appendDescriptionOf(matcher);
  697. }
  698. }
  699. public static Matcher<Entry> haveAtomGeneratorElement(Matcher<String> matcher)
  700. {
  701. return new HaveAtomGeneratorElement(matcher);
  702. }
  703. private static final class HaveAtomGeneratorElement extends TypeSafeDiagnosingMatcher<Entry>
  704. {
  705. private final Matcher<String> matcher;
  706. private HaveAtomGeneratorElement(Matcher<String> matcher)
  707. {
  708. this.matcher = matcher;
  709. }
  710. @Override
  711. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  712. {
  713. String generatorUri = getAtomGeneratorUri(entry).getUri().toASCIIString();
  714. if (!matcher.matches(generatorUri))
  715. {
  716. mismatchDescription.appendText("does not contain a generator element with value of ");
  717. matcher.describeMismatch(generatorUri, mismatchDescription);
  718. return false;
  719. }
  720. return true;
  721. }
  722. public void describeTo(Description description)
  723. {
  724. description.appendText("contains a generator element with value of ").appendDescriptionOf(matcher);
  725. }
  726. }
  727. private static FOMGenerator getAtomGeneratorUri(Entry entry)
  728. {
  729. return entry.getExtension(Constants.GENERATOR);
  730. }
  731. public static Matcher<Entry> haveLink(Matcher<Link> matcher)
  732. {
  733. return new EntryLinkMatcher(matcher);
  734. }
  735. private static final class EntryLinkMatcher extends TypeSafeDiagnosingMatcher<Entry>
  736. {
  737. private final Matcher<Link> matcher;
  738. private final Predicate<Link> matches = new Predicate<Link>()
  739. {
  740. public boolean apply(Link l)
  741. {
  742. return matcher.matches(l);
  743. }
  744. };
  745. public EntryLinkMatcher(Matcher<Link> matcher)
  746. {
  747. this.matcher = matcher;
  748. }
  749. public void describeTo(Description description)
  750. {
  751. description.appendText("entry has link ").appendDescriptionOf(matcher);
  752. }
  753. @Override
  754. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  755. {
  756. if (any(entry.getLinks(), matches))
  757. {
  758. return true;
  759. }
  760. mismatchDescription.appendText("entry has no links matching ").appendDescriptionOf(matcher);
  761. return false;
  762. }
  763. }
  764. public static Matcher<Iterable<? super Link>> hasLink(Matcher<Link> m1, Matcher<Link> m2)
  765. {
  766. return hasLink(ImmutableList.of(m1, m2));
  767. }
  768. public static Matcher<Iterable<? super Link>> hasLink(Iterable<Matcher<? super Link>> matchers)
  769. {
  770. return hasItem(allOf(matchers));
  771. }
  772. public static Matcher<? super Entry> withAuthorElement(Matcher<? super String> matcher)
  773. {
  774. return new WithAuthorElement(matcher);
  775. }
  776. private static final class WithAuthorElement extends TypeSafeDiagnosingMatcher<Entry>
  777. {
  778. private final Matcher<? super String> matcher;
  779. private WithAuthorElement(Matcher<? super String> matcher)
  780. {
  781. this.matcher = matcher;
  782. }
  783. @Override
  784. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  785. {
  786. List<Person> people = entry.getAuthors();
  787. for (Person person : people)
  788. {
  789. if (matcher.matches(person.getSimpleExtension(USR_USERNAME)))
  790. {
  791. return true;
  792. }
  793. mismatchDescription.appendText("user ");
  794. matcher.describeMismatch(person.getSimpleExtension(USR_USERNAME), mismatchDescription);
  795. }
  796. return false;
  797. }
  798. public void describeTo(Description description)
  799. {
  800. description.appendText("user is ").appendDescriptionOf(matcher);
  801. }
  802. }
  803. public static Matcher<? super Entry> withAuthorLink(Matcher<Link> matcher)
  804. {
  805. return new WithAuthorLink(matcher);
  806. }
  807. private static final class WithAuthorLink extends TypeSafeDiagnosingMatcher<Entry>
  808. {
  809. private final Matcher<Link> matcher;
  810. private WithAuthorLink(Matcher<Link> matcher)
  811. {
  812. this.matcher = matcher;
  813. }
  814. @Override
  815. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  816. {
  817. List<Person> people = entry.getAuthors();
  818. for (Person person : people)
  819. {
  820. Collection<Element> linkElements = filter(person.getElements(), linkPredicate);
  821. for (Element linkElement : linkElements)
  822. {
  823. Link link = (Link)linkElement;
  824. if (matcher.matches(link))
  825. {
  826. return true;
  827. }
  828. }
  829. }
  830. mismatchDescription.appendText("link ");
  831. return false;
  832. }
  833. public void describeTo(Description description)
  834. {
  835. description.appendText("user link is ").appendDescriptionOf(matcher);
  836. }
  837. }
  838. public static Matcher<Entry> withVerbElement(Matcher<? super String> matcher)
  839. {
  840. return new WithVerbElement(matcher);
  841. }
  842. private static final class WithVerbElement extends TypeSafeDiagnosingMatcher<Entry>
  843. {
  844. private final Matcher<? super String> matcher;
  845. private WithVerbElement(Matcher<? super String> matcher)
  846. {
  847. this.matcher = matcher;
  848. }
  849. @Override
  850. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  851. {
  852. List<Element> verbs = entry.getExtensions(ACTIVITY_VERB);
  853. for (Element verb : verbs)
  854. {
  855. if (matcher.matches(verb.getText()))
  856. {
  857. return true;
  858. }
  859. mismatchDescription.appendText("activity:verb ");
  860. matcher.describeMismatch(verb.getText(), mismatchDescription);
  861. }
  862. return false;
  863. }
  864. public void describeTo(Description description)
  865. {
  866. description.appendText("activity:verb is ").appendDescriptionOf(matcher);
  867. }
  868. }
  869. public static Matcher<Entry> withActivityObjectElement(Matcher<? super ExtensibleElement> matcher)
  870. {
  871. return new WithActivityObjectElement(matcher);
  872. }
  873. private static final class WithActivityObjectElement extends TypeSafeDiagnosingMatcher<Entry>
  874. {
  875. private final Matcher<? super ExtensibleElement> matcher;
  876. private WithActivityObjectElement(Matcher<? super ExtensibleElement> matcher)
  877. {
  878. this.matcher = matcher;
  879. }
  880. @Override
  881. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  882. {
  883. List<ExtensibleElement> activityObjects = entry.getExtensions(ACTIVITY_OBJECT);
  884. for (ExtensibleElement activityObject : activityObjects)
  885. {
  886. if (matcher.matches(activityObject))
  887. {
  888. return true;
  889. }
  890. mismatchDescription.appendText("activity:object ");
  891. matcher.describeMismatch(activityObject, mismatchDescription);
  892. }
  893. return false;
  894. }
  895. public void describeTo(Description description)
  896. {
  897. description.appendText("activity:object ").appendDescriptionOf(matcher);
  898. }
  899. }
  900. public static Matcher<? super Entry> withInReplyToElement(Matcher<? super String> matcher)
  901. {
  902. return new WithInReplyToElement(matcher);
  903. }
  904. private static final class WithInReplyToElement extends TypeSafeDiagnosingMatcher<Entry>
  905. {
  906. private final Matcher<? super String> matcher;
  907. private WithInReplyToElement(Matcher<? super String> matcher)
  908. {
  909. this.matcher = matcher;
  910. }
  911. @Override
  912. protected boolean matchesSafely(Entry entry, Description mismatchDescription)
  913. {
  914. String inReplyTo = getInReplyToRef(entry);
  915. if (!matcher.matches(inReplyTo))
  916. {
  917. mismatchDescription.appendText("in-reply-to ");
  918. matcher.describeMismatch(inReplyTo, mismatchDescription);
  919. return false;
  920. }
  921. return true;
  922. }
  923. public void describeTo(Description description)
  924. {
  925. description.appendText("in-reply-to is ").appendDescriptionOf(matcher);
  926. }
  927. }
  928. private static String getInReplyToRef(Entry entry)
  929. {
  930. InReplyTo inReplyTo = entry.getExtension(IN_REPLY_TO);
  931. if (inReplyTo != null && inReplyTo.getRef() != null)
  932. {
  933. return inReplyTo.getRef().toASCIIString();
  934. }
  935. return null;
  936. }
  937. public static Matcher<Iterable<Entry>> inDescendingOrder()
  938. {
  939. return new InDescendingOrder();
  940. }
  941. private static final class InDescendingOrder extends TypeSafeDiagnosingMatcher<Iterable<Entry>>
  942. {
  943. private static Ordering<Entry> descending = new Ordering<Entry>()
  944. {
  945. public int compare(Entry entry1, Entry entry2)
  946. {
  947. return entry2.getPublished().compareTo(entry1.getPublished());
  948. }
  949. };
  950. @Override
  951. protected boolean matchesSafely(Iterable<Entry> entries, Description mismatchDescription)
  952. {
  953. if (!descending.isOrdered(entries))
  954. {
  955. mismatchDescription.appendText("was ").appendValueList("[", ", ", "]", entries);
  956. return false;
  957. }
  958. return true;
  959. }
  960. public void describeTo(Description description)
  961. {
  962. description.appendText("dates sorted in descending order");
  963. }
  964. }
  965. public static Matcher<Iterable<Entry>> hasEntryCount(Matcher<? super Integer> matcher)
  966. {
  967. return new EntryCount(matcher);
  968. }
  969. private static final class EntryCount extends TypeSafeDiagnosingMatcher<Iterable<Entry>>
  970. {
  971. private final Matcher<? super Integer> matcher;
  972. public EntryCount(Matcher<? super Integer> matcher)
  973. {
  974. this.matcher = matcher;
  975. }
  976. @Override
  977. protected boolean matchesSafely(Iterable<Entry> entries, Description mismatchDescription)
  978. {
  979. int size = size(entries);
  980. if (!matcher.matches(size))
  981. {
  982. mismatchDescription.appendText("entries count ");
  983. matcher.describeMismatch(size, mismatchDescription);
  984. return false;
  985. }
  986. return true;
  987. }
  988. public void describeTo(Description description)
  989. {
  990. description.appendText("entries count is ").appendDescriptionOf(matcher);
  991. }
  992. }
  993. public static Matcher<Iterable<? super StreamsEntry.Link>> hasStreamsLink(Matcher<? super StreamsEntry.Link> matcher)
  994. {
  995. return hasItem(matcher);
  996. }
  997. public static Matcher<StreamsEntry.Link> whereStreamsRel(Matcher<? super String> matcher)
  998. {
  999. return new WhereStreamsRel(matcher);
  1000. }
  1001. private static final class WhereStreamsRel extends TypeSafeDiagnosingMatcher<StreamsEntry.Link>
  1002. {
  1003. private final Matcher<? super String> matcher;
  1004. public WhereStreamsRel(Matcher<? super String> matcher)
  1005. {
  1006. this.matcher = matcher;
  1007. }
  1008. @Override
  1009. protected boolean matchesSafely(StreamsEntry.Link link, Description mismatchDescription)
  1010. {
  1011. if (link == null)
  1012. {
  1013. mismatchDescription.appendText("no link");
  1014. return false;
  1015. }
  1016. if (!matcher.matches(link.getRel()))
  1017. {
  1018. mismatchDescription.appendText("rel ");
  1019. matcher.describeMismatch(link.getRel(), mismatchDescription);
  1020. return false;
  1021. }
  1022. return true;
  1023. }
  1024. public void describeTo(Description description)
  1025. {
  1026. description.appendText("rel ").appendDescriptionOf(matcher);
  1027. }
  1028. }
  1029. public static Matcher<? super String> matchesRegEx(String regex)
  1030. {
  1031. return new RegexpMatcher(regex);
  1032. }
  1033. private final static class RegexpMatcher extends TypeSafeMatcher<String>
  1034. {
  1035. private final String regexp;
  1036. private RegexpMatcher(String regexp)
  1037. {
  1038. this.regexp = regexp;
  1039. }
  1040. @Override
  1041. protected boolean matchesSafely(String s)
  1042. {
  1043. return s != null && s.matches(regexp);
  1044. }
  1045. @Override
  1046. public void describeTo(Description description)
  1047. {
  1048. description.appendText("matches='" + regexp + "'");
  1049. }
  1050. }
  1051. static final class AtomConstants
  1052. {
  1053. // Prefixes
  1054. public static final String ACTIVITY_PREFIX = "activity";
  1055. public static final String ATLASSIAN_PREFIX = "atlassian";
  1056. public static final String USR_PREFIX = "usr";
  1057. public static final String THR_PREFIX = "thr";
  1058. // Namespaces
  1059. public static final String ACTIVITY_NS = "http://activitystrea.ms/spec/1.0/";
  1060. public static final String ATLASSIAN_NS = "http://streams.atlassian.com/syndication/general/1.0";
  1061. public static final String USR_NS = "http://streams.atlassian.com/syndication/username/1.0";
  1062. public static final String THR_NS = "http://purl.org/syndication/thread/1.0";
  1063. // Local parts
  1064. public static final String LN_OBJECT = "object";
  1065. public static final String LN_OBJECT_TYPE = "object-type";
  1066. public static final String LN_TARGET = "target";
  1067. public static final String LN_VERB = "verb";
  1068. public static final String LN_APPLICATION = "application";
  1069. public static final String LN_USERNAME = "username";
  1070. public static final String LN_INREPLYTO = "in-reply-to";
  1071. // Qualified Names
  1072. public static final QName ACTIVITY_VERB = new QName(ACTIVITY_NS, LN_VERB, ACTIVITY_PREFIX);
  1073. public static final QName ACTIVITY_OBJECT = new QName(ACTIVITY_NS, LN_OBJECT, ACTIVITY_PREFIX);
  1074. public static final QName ACTIVITY_TARGET = new QName(ACTIVITY_NS, LN_TARGET, ACTIVITY_PREFIX);
  1075. public static final QName ACTIVITY_OBJECT_TYPE = new QName(ACTIVITY_NS, LN_OBJECT_TYPE, ACTIVITY_PREFIX);
  1076. public static final QName ATLASSIAN_APPLICATION = new QName(ATLASSIAN_NS, LN_APPLICATION, ATLASSIAN_PREFIX);
  1077. public static final QName USR_USERNAME = new QName(USR_NS, LN_USERNAME, USR_PREFIX);
  1078. public static final QName IN_REPLY_TO = new QName(THR_NS, LN_INREPLYTO, THR_PREFIX);
  1079. }
  1080. }