View Javadoc
1   /*
2    * Copyright (c) 2012-2023, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.log;
31  
32  import java.util.concurrent.Callable;
33  import java.util.concurrent.Executors;
34  import java.util.concurrent.ScheduledExecutorService;
35  import java.util.concurrent.TimeUnit;
36  import java.util.concurrent.atomic.AtomicInteger;
37  import java.util.concurrent.atomic.AtomicReference;
38  import org.hamcrest.MatcherAssert;
39  import org.hamcrest.Matchers;
40  import org.junit.jupiter.api.Assertions;
41  import org.junit.jupiter.api.Test;
42  
43  /**
44   * Test case for {@link VerboseRunnable}.
45   * @since 0.1
46   */
47  @SuppressWarnings({ "PMD.DoNotUseThreads", "PMD.TooManyMethods" })
48  final class VerboseRunnableTest {
49  
50      @Test
51      void logsExceptionsInRunnable() {
52          Assertions.assertThrows(
53              IllegalArgumentException.class,
54              () -> new VerboseRunnable(
55                  (Runnable) () -> {
56                      throw new IllegalArgumentException("oops");
57                  }
58              ).run()
59          );
60      }
61  
62      @Test
63      void swallowsExceptionsInRunnable() {
64          new VerboseRunnable(
65              (Runnable) () -> {
66                  throw new IllegalArgumentException("boom");
67              },
68              true
69          ).run();
70      }
71  
72      @Test
73      void swallowsExceptionsInCallable() {
74          new VerboseRunnable(
75              () -> {
76                  throw new IllegalArgumentException("boom-2");
77              },
78              true
79          ).run();
80      }
81  
82      @Test
83      void translatesToStringFromUnderlyingRunnable() {
84          final String text = "some text abc";
85          final Runnable verbose = new VerboseRunnable(
86              new Runnable() {
87                  @Override
88                  public void run() {
89                      assert true;
90                  }
91  
92                  @Override
93                  public String toString() {
94                      return text;
95                  }
96              }
97          );
98          MatcherAssert.assertThat(
99              verbose,
100             Matchers.hasToString(Matchers.containsString(text))
101         );
102     }
103 
104     @Test
105     void translatesToStringFromUnderlyingCallable() {
106         final String text = "some text abc-2";
107         final Runnable verbose = new VerboseRunnable(
108             new Callable<Void>() {
109                 @Override
110                 public Void call() {
111                     return null;
112                 }
113 
114                 @Override
115                 public String toString() {
116                     return text;
117                 }
118             },
119             true
120         );
121         MatcherAssert.assertThat(
122             verbose,
123             Matchers.hasToString(Matchers.containsString(text))
124         );
125     }
126 
127     @Test
128     void preservesInterruptedStatus() throws Exception {
129         final ScheduledExecutorService svc =
130             Executors.newSingleThreadScheduledExecutor();
131         final AtomicReference<Thread> thread = new AtomicReference<>();
132         final AtomicInteger runs = new AtomicInteger();
133         svc.scheduleWithFixedDelay(
134             new VerboseRunnable(
135                 () -> {
136                     runs.addAndGet(1);
137                     thread.set(Thread.currentThread());
138                     TimeUnit.HOURS.sleep(1L);
139                     return null;
140                 },
141                 true,
142                 false
143             ),
144             1L, 1L,
145             TimeUnit.MICROSECONDS
146         );
147         while (thread.get() == null) {
148             TimeUnit.MILLISECONDS.sleep(1L);
149         }
150         thread.get().interrupt();
151         TimeUnit.SECONDS.sleep(1L);
152         svc.shutdown();
153         MatcherAssert.assertThat(runs.get(), Matchers.is(1));
154         MatcherAssert.assertThat(
155             svc.awaitTermination(1L, TimeUnit.SECONDS),
156             Matchers.is(true)
157         );
158     }
159 
160 }