1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.cache;
28
29 import java.time.Instant;
30 import java.time.temporal.ChronoUnit;
31 import java.util.Arrays;
32 import java.util.Iterator;
33 import java.util.Objects;
34 import java.util.Set;
35
36 import org.apache.hc.client5.http.cache.HttpCacheEntry;
37 import org.apache.hc.client5.http.cache.Resource;
38 import org.apache.hc.client5.http.cache.ResourceIOException;
39 import org.apache.hc.core5.http.Header;
40 import org.hamcrest.BaseMatcher;
41 import org.hamcrest.Description;
42 import org.hamcrest.Matcher;
43
44 public class HttpCacheEntryMatcher extends BaseMatcher<HttpCacheEntry> {
45
46 private final HttpCacheEntry expectedValue;
47
48 public HttpCacheEntryMatcher(final HttpCacheEntry expectedValue) {
49 this.expectedValue = expectedValue;
50 }
51
52 @Override
53 public boolean matches(final Object item) {
54 if (item instanceof HttpCacheEntry) {
55 try {
56 final HttpCacheEntry otherValue = (HttpCacheEntry) item;
57
58 if (!setEqual(expectedValue.getVariants(), otherValue.getVariants())) {
59 return false;
60 }
61 if (!Objects.equals(expectedValue.getRequestMethod(), otherValue.getRequestMethod())) {
62 return false;
63 }
64 if (!Objects.equals(expectedValue.getRequestURI(), otherValue.getRequestURI())) {
65 return false;
66 }
67 if (!headersEqual(expectedValue.requestHeaderIterator(), otherValue.requestHeaderIterator())) {
68 return false;
69 }
70 if (!instantEqual(expectedValue.getRequestInstant(), otherValue.getRequestInstant())) {
71 return false;
72 }
73 if (expectedValue.getStatus() != otherValue.getStatus()) {
74 return false;
75 }
76 if (!headersEqual(expectedValue.headerIterator(), otherValue.headerIterator())) {
77 return false;
78 }
79 if (!instantEqual(expectedValue.getResponseInstant(), otherValue.getResponseInstant())) {
80 return false;
81 }
82 final Resource expectedResource = expectedValue.getResource();
83 final byte[] expectedContent = expectedResource != null ? expectedResource.get() : null;
84 final Resource otherResource = otherValue.getResource();
85 final byte[] otherContent = otherResource != null ? otherResource.get() : null;
86 return Arrays.equals(expectedContent, otherContent);
87 } catch (final ResourceIOException ex) {
88 throw new RuntimeException(ex);
89 }
90 }
91 return false;
92 }
93
94 private static boolean instantEqual(final Instant expected, final Instant other) {
95 final Instant expectedMs = expected != null ? expected.truncatedTo(ChronoUnit.MILLIS) : null;
96 final Instant otherMs = other != null ? other.truncatedTo(ChronoUnit.MILLIS) : null;
97 return Objects.equals(expectedMs, otherMs);
98 }
99
100 private static boolean headersEqual(final Iterator<Header> expected, final Iterator<Header> other) {
101 while (expected.hasNext()) {
102 final Header h1 = expected.next();
103 if (!other.hasNext()) {
104 return false;
105 }
106 final Header h2 = other.next();
107 if (!h1.getName().equals(h2.getName()) || !Objects.equals(h1.getValue(), h2.getValue())) {
108 return false;
109 }
110 }
111 if (other.hasNext()) {
112 return false;
113 }
114 return true;
115 }
116
117 private static boolean setEqual(final Set<?> expected, final Set<?> actual) {
118 if (expected.size() != actual.size()) {
119 return false;
120 }
121 return actual.containsAll(expected);
122 }
123
124 @Override
125 public void describeTo(final Description description) {
126 description.appendValue(expectedValue);
127 }
128
129 public static Matcher<HttpCacheEntry> equivalent(final HttpCacheEntry target) {
130 return new HttpCacheEntryMatcher(target);
131 }
132
133 }