1818package org .apache .hadoop .hbase .io .hfile ;
1919
2020import static org .hamcrest .MatcherAssert .assertThat ;
21+ import static org .hamcrest .Matchers .allOf ;
22+ import static org .hamcrest .Matchers .hasProperty ;
2123import static org .hamcrest .Matchers .instanceOf ;
2224import static org .hamcrest .Matchers .startsWith ;
2325import static org .junit .Assert .assertEquals ;
2426import static org .junit .Assert .assertTrue ;
2527import static org .junit .Assert .fail ;
2628
29+ import java .io .ByteArrayOutputStream ;
2730import java .io .Closeable ;
2831import java .io .IOException ;
32+ import java .io .PrintStream ;
2933import java .nio .ByteBuffer ;
3034import java .nio .channels .SeekableByteChannel ;
35+ import java .nio .charset .StandardCharsets ;
3136import java .nio .file .FileSystems ;
3237import java .nio .file .Files ;
3338import java .nio .file .StandardOpenOption ;
3439import java .time .Instant ;
40+ import java .util .LinkedList ;
41+ import java .util .List ;
3542import java .util .NoSuchElementException ;
3643import java .util .Random ;
3744import org .apache .hadoop .conf .Configuration ;
4754import org .apache .hadoop .hbase .testclassification .IOTests ;
4855import org .apache .hadoop .hbase .testclassification .SmallTests ;
4956import org .apache .hadoop .hbase .util .Bytes ;
50- import org .hamcrest .Matchers ;
57+ import org .hamcrest .Description ;
58+ import org .hamcrest .Matcher ;
59+ import org .hamcrest .TypeSafeMatcher ;
5160import org .junit .ClassRule ;
5261import org .junit .Rule ;
5362import org .junit .Test ;
@@ -106,8 +115,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
106115 consumer .readFully ();
107116 fail ();
108117 } catch (Exception e ) {
109- assertThat (e , instanceOf ( IOException .class ));
110- assertThat ( e . getMessage (), startsWith ("Invalid onDiskSizeWithHeader=" ));
118+ assertThat (e , new IsThrowableMatching (). withInstanceOf ( IOException .class )
119+ . withMessage ( startsWith ("Invalid onDiskSizeWithHeader=" ) ));
111120 }
112121 assertEquals (0 , consumer .getItemsRead ());
113122 }
@@ -123,8 +132,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
123132 consumer .readFully ();
124133 fail ();
125134 } catch (Exception e ) {
126- assertThat (e , instanceOf ( IllegalArgumentException .class ));
127- assertThat ( e . getMessage (), startsWith ("newLimit > capacity" ));
135+ assertThat (e , new IsThrowableMatching (). withInstanceOf ( IllegalArgumentException .class )
136+ . withMessage ( startsWith ("newLimit > capacity" ) ));
128137 }
129138 assertEquals (0 , consumer .getItemsRead ());
130139 }
@@ -140,8 +149,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionFirstBlock() throws Exception {
140149 consumer .readFully ();
141150 fail ();
142151 } catch (Exception e ) {
143- assertThat (e , instanceOf ( IOException .class ));
144- assertThat ( e . getMessage (), Matchers . startsWith ("Invalid onDiskSizeWithHeader=" ));
152+ assertThat (e , new IsThrowableMatching (). withInstanceOf ( IOException .class )
153+ . withMessage ( startsWith ("Invalid onDiskSizeWithHeader=" ) ));
145154 }
146155 assertEquals (0 , consumer .getItemsRead ());
147156 }
@@ -177,8 +186,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
177186 consumer .readFully ();
178187 fail ();
179188 } catch (Exception e ) {
180- assertThat (e , instanceOf ( IOException .class ));
181- assertThat ( e . getMessage (), Matchers . startsWith ("Invalid onDiskSizeWithHeader=" ));
189+ assertThat (e , new IsThrowableMatching (). withInstanceOf ( IOException .class )
190+ . withMessage ( startsWith ("Invalid onDiskSizeWithHeader=" ) ));
182191 }
183192 assertEquals (1 , consumer .getItemsRead ());
184193 }
@@ -194,8 +203,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
194203 consumer .readFully ();
195204 fail ();
196205 } catch (Exception e ) {
197- assertTrue ( e instanceof IllegalArgumentException );
198- assertTrue ( e . getMessage (). startsWith ("newLimit > capacity" ));
206+ assertThat ( e , new IsThrowableMatching (). withInstanceOf ( IllegalArgumentException . class )
207+ . withMessage ( startsWith ("newLimit > capacity" ) ));
199208 }
200209 assertEquals (1 , consumer .getItemsRead ());
201210 }
@@ -211,8 +220,8 @@ public void testOnDiskSizeWithoutHeaderCorruptionSecondBlock() throws Exception
211220 consumer .readFully ();
212221 fail ();
213222 } catch (Exception e ) {
214- assertTrue ( e instanceof IOException );
215- assertTrue ( e . getMessage (). startsWith ("Invalid onDiskSizeWithHeader=" ));
223+ assertThat ( e , new IsThrowableMatching (). withInstanceOf ( IOException . class )
224+ . withMessage ( startsWith ("Invalid onDiskSizeWithHeader=" ) ));
216225 }
217226 assertEquals (1 , consumer .getItemsRead ());
218227 }
@@ -367,7 +376,7 @@ private interface CloseMethod {
367376 void run () throws IOException ;
368377 }
369378
370- private static < T extends Throwable > void closeQuietly (CloseMethod closeMethod ) {
379+ private static void closeQuietly (CloseMethod closeMethod ) {
371380 try {
372381 closeMethod .run ();
373382 } catch (Throwable e ) {
@@ -474,4 +483,49 @@ protected void before() throws Throwable {
474483 }
475484 }
476485 }
486+
487+ /**
488+ * A Matcher implementation that can make basic assertions over a provided {@link Throwable}.
489+ * Assertion failures include the full stacktrace in their description.
490+ */
491+ private static final class IsThrowableMatching extends TypeSafeMatcher <Throwable > {
492+
493+ private final List <Matcher <? super Throwable >> requirements = new LinkedList <>();
494+
495+ public IsThrowableMatching withInstanceOf (Class <?> type ) {
496+ requirements .add (instanceOf (type ));
497+ return this ;
498+ }
499+
500+ public IsThrowableMatching withMessage (Matcher <String > matcher ) {
501+ requirements .add (hasProperty ("message" , matcher ));
502+ return this ;
503+ }
504+
505+ @ Override
506+ protected boolean matchesSafely (Throwable throwable ) {
507+ return allOf (requirements ).matches (throwable );
508+ }
509+
510+ @ Override
511+ protected void describeMismatchSafely (Throwable item , Description mismatchDescription ) {
512+ allOf (requirements ).describeMismatch (item , mismatchDescription );
513+ // would be nice if `item` could be provided as the cause of the AssertionError instead.
514+ mismatchDescription .appendText (String .format ("%nProvided: " ));
515+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream ()) {
516+ try (PrintStream ps = new PrintStream (baos , false , StandardCharsets .UTF_8 .name ())) {
517+ item .printStackTrace (ps );
518+ ps .flush ();
519+ }
520+ mismatchDescription .appendText (baos .toString (StandardCharsets .UTF_8 .name ()));
521+ } catch (Exception e ) {
522+ throw new RuntimeException (e );
523+ }
524+ }
525+
526+ @ Override
527+ public void describeTo (Description description ) {
528+ description .appendDescriptionOf (allOf (requirements ));
529+ }
530+ }
477531}
0 commit comments