• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static com.google.common.base.StandardSystemProperty.LINE_SEPARATOR;
4 import static com.google.common.truth.Truth.assertThat;
5 import static java.nio.charset.StandardCharsets.UTF_8;
6 import static org.junit.Assert.assertEquals;
7 import static org.junit.Assert.assertFalse;
8 import static org.junit.Assert.assertThrows;
9 import static org.junit.Assert.assertTrue;
10 
11 import android.util.Log;
12 import android.util.Log.TerribleFailure;
13 import android.util.Log.TerribleFailureHandler;
14 import androidx.test.ext.junit.runners.AndroidJUnit4;
15 import com.google.common.collect.Iterables;
16 import java.io.ByteArrayOutputStream;
17 import java.io.PrintStream;
18 import java.util.List;
19 import org.junit.Test;
20 import org.junit.runner.RunWith;
21 import org.robolectric.annotation.Config;
22 import org.robolectric.shadows.ShadowLog.LogItem;
23 import org.robolectric.util.ReflectionHelpers;
24 import org.robolectric.versioning.AndroidVersions.L;
25 
26 @RunWith(AndroidJUnit4.class)
27 public class ShadowLogTest {
28 
29   @Test
d_shouldLogAppropriately()30   public void d_shouldLogAppropriately() {
31     Log.d("tag", "msg");
32 
33     assertLogged(Log.DEBUG, "tag", "msg", null);
34   }
35 
36   @Test
d_shouldLogAppropriately_withThrowable()37   public void d_shouldLogAppropriately_withThrowable() {
38     Throwable throwable = new Throwable();
39 
40     Log.d("tag", "msg", throwable);
41 
42     assertLogged(Log.DEBUG, "tag", "msg", throwable);
43   }
44 
45   @Test
e_shouldLogAppropriately()46   public void e_shouldLogAppropriately() {
47     Log.e("tag", "msg");
48 
49     assertLogged(Log.ERROR, "tag", "msg", null);
50   }
51 
52   @Test
e_shouldLogAppropriately_withThrowable()53   public void e_shouldLogAppropriately_withThrowable() {
54     Throwable throwable = new Throwable();
55 
56     Log.e("tag", "msg", throwable);
57 
58     assertLogged(Log.ERROR, "tag", "msg", throwable);
59   }
60 
61   @Test
i_shouldLogAppropriately()62   public void i_shouldLogAppropriately() {
63     Log.i("tag", "msg");
64 
65     assertLogged(Log.INFO, "tag", "msg", null);
66   }
67 
68   @Test
i_shouldLogAppropriately_withThrowable()69   public void i_shouldLogAppropriately_withThrowable() {
70     Throwable throwable = new Throwable();
71 
72     Log.i("tag", "msg", throwable);
73 
74     assertLogged(Log.INFO, "tag", "msg", throwable);
75   }
76 
77   @Test
v_shouldLogAppropriately()78   public void v_shouldLogAppropriately() {
79     Log.v("tag", "msg");
80 
81     assertLogged(Log.VERBOSE, "tag", "msg", null);
82   }
83 
84   @Test
v_shouldLogAppropriately_withThrowable()85   public void v_shouldLogAppropriately_withThrowable() {
86     Throwable throwable = new Throwable();
87 
88     Log.v("tag", "msg", throwable);
89 
90     assertLogged(Log.VERBOSE, "tag", "msg", throwable);
91   }
92 
93   @Test
w_shouldLogAppropriately()94   public void w_shouldLogAppropriately() {
95     Log.w("tag", "msg");
96 
97     assertLogged(Log.WARN, "tag", "msg", null);
98   }
99 
100   @Test
w_shouldLogAppropriately_withThrowable()101   public void w_shouldLogAppropriately_withThrowable() {
102     Throwable throwable = new Throwable();
103 
104     Log.w("tag", "msg", throwable);
105 
106     assertLogged(Log.WARN, "tag", "msg", throwable);
107   }
108 
109   @Test
w_shouldLogAppropriately_withJustThrowable()110   public void w_shouldLogAppropriately_withJustThrowable() {
111     Throwable throwable = new Throwable();
112     Log.w("tag", throwable);
113     assertLogged(Log.WARN, "tag", null, throwable);
114   }
115 
116   @Test
wtf_shouldLogAppropriately()117   public void wtf_shouldLogAppropriately() {
118     Log.wtf("tag", "msg");
119 
120     assertLogged(Log.ASSERT, "tag", "msg", null);
121   }
122 
123   @Test
wtf_shouldLogAppropriately_withThrowable()124   public void wtf_shouldLogAppropriately_withThrowable() {
125     Throwable throwable = new Throwable();
126 
127     Log.wtf("tag", "msg", throwable);
128 
129     assertLogged(Log.ASSERT, "tag", "msg", throwable);
130   }
131 
132   @Test
wtf_wtfIsFatalIsSet_shouldThrowTerribleFailure()133   public void wtf_wtfIsFatalIsSet_shouldThrowTerribleFailure() {
134     ShadowLog.setWtfIsFatal(true);
135 
136     Throwable throwable = new Throwable();
137     assertThrows(TerribleFailure.class, () -> Log.wtf("tag", "msg", throwable));
138     assertLogged(Log.ASSERT, "tag", "msg", throwable);
139   }
140 
141   @Test
142   @Config(minSdk = L.SDK_INT)
wtf_shouldLogAppropriately_withNewWtfHandler()143   public void wtf_shouldLogAppropriately_withNewWtfHandler() {
144     Throwable throwable = new Throwable();
145 
146     String[] captured = new String[1];
147 
148     TerribleFailureHandler prevWtfHandler =
149         Log.setWtfHandler(
150             ReflectionHelpers.createDelegatingProxy(
151                 TerribleFailureHandler.class,
152                 new Object() {
153                   public void onTerribleFailure(String tag, TerribleFailure what, boolean system) {
154                     captured[0] = what.getMessage();
155                   }
156                 }));
157 
158     Log.wtf("tag", "msg", throwable);
159     // assert that the new handler captures the message
160     assertEquals("msg", captured[0]);
161     // reset the handler
162     Log.setWtfHandler(prevWtfHandler);
163 
164     assertLogged(Log.ASSERT, "tag", "msg", throwable);
165   }
166 
167   @Test
println_shouldLogAppropriately()168   public void println_shouldLogAppropriately() {
169     int len = Log.println(Log.ASSERT, "tag", "msg");
170     assertLogged(Log.ASSERT, "tag", "msg", null);
171     assertThat(len).isEqualTo(11);
172   }
173 
174   @Test
println_shouldLogNullTagAppropriately()175   public void println_shouldLogNullTagAppropriately() {
176     int len = Log.println(Log.ASSERT, null, "msg");
177     assertLogged(Log.ASSERT, null, "msg", null);
178     assertThat(len).isEqualTo(8);
179   }
180 
181   @Test
println_shouldLogNullMessageAppropriately()182   public void println_shouldLogNullMessageAppropriately() {
183     int len = Log.println(Log.ASSERT, "tag", null);
184     assertLogged(Log.ASSERT, "tag", null, null);
185     assertThat(len).isEqualTo(8);
186   }
187 
188   @Test
println_shouldLogNullTagAndNullMessageAppropriately()189   public void println_shouldLogNullTagAndNullMessageAppropriately() {
190     int len = Log.println(Log.ASSERT, null, null);
191     assertLogged(Log.ASSERT, null, null, null);
192     assertThat(len).isEqualTo(5);
193   }
194 
195   @Test
shouldLogToProvidedStream()196   public void shouldLogToProvidedStream() throws Exception {
197     final ByteArrayOutputStream bos = new ByteArrayOutputStream();
198     PrintStream old = ShadowLog.stream;
199     try {
200       ShadowLog.stream = new PrintStream(bos);
201       Log.d("tag", "msg");
202       assertThat(new String(bos.toByteArray(), UTF_8))
203           .isEqualTo("D/tag: msg" + System.getProperty("line.separator"));
204 
205       Log.w("tag", new RuntimeException());
206       assertTrue(new String(bos.toByteArray(), UTF_8).contains("RuntimeException"));
207     } finally {
208       ShadowLog.stream = old;
209     }
210   }
211 
specificMethodName()212   private static RuntimeException specificMethodName() {
213     return new RuntimeException();
214   }
215 
216   @Test
shouldLogAccordingToTag()217   public void shouldLogAccordingToTag() throws Exception {
218     ShadowLog.reset();
219     Log.d("tag1", "1");
220     Log.i("tag2", "2");
221     Log.e("tag3", "3");
222     Log.w("tag1", "4");
223     Log.i("tag1", "5");
224     Log.d("tag2", "6");
225     Log.d("throwable", "7", specificMethodName());
226 
227     List<LogItem> allItems = ShadowLog.getLogs();
228     assertThat(allItems.size()).isEqualTo(7);
229     int i = 1;
230     for (LogItem item : allItems) {
231       assertThat(item.msg).isEqualTo(Integer.toString(i));
232       assertThat(item.toString()).contains(item.msg);
233       i++;
234     }
235     assertThat(allItems.get(6).toString()).contains("specificMethodName");
236     assertUniformLogsForTag("tag1", 3);
237     assertUniformLogsForTag("tag2", 2);
238     assertUniformLogsForTag("tag3", 1);
239   }
240 
assertUniformLogsForTag(String tag, int count)241   private static void assertUniformLogsForTag(String tag, int count) {
242     List<LogItem> tag1Items = ShadowLog.getLogsForTag(tag);
243     assertThat(tag1Items.size()).isEqualTo(count);
244     int last = -1;
245     for (LogItem item : tag1Items) {
246       assertThat(item.tag).isEqualTo(tag);
247       int current = Integer.parseInt(item.msg);
248       assertThat(current > last).isTrue();
249       last = current;
250     }
251   }
252 
253   @Test
infoIsDefaultLoggableLevel()254   public void infoIsDefaultLoggableLevel() throws Exception {
255     PrintStream old = ShadowLog.stream;
256     ShadowLog.stream = null;
257     assertFalse(Log.isLoggable("FOO", Log.VERBOSE));
258     assertFalse(Log.isLoggable("FOO", Log.DEBUG));
259 
260     assertTrue(Log.isLoggable("FOO", Log.INFO));
261     assertTrue(Log.isLoggable("FOO", Log.WARN));
262     assertTrue(Log.isLoggable("FOO", Log.ERROR));
263     assertTrue(Log.isLoggable("FOO", Log.ASSERT));
264     ShadowLog.stream = old;
265   }
266 
assertLogged(int type, String tag, String msg, Throwable throwable)267   private static void assertLogged(int type, String tag, String msg, Throwable throwable) {
268     LogItem lastLog = Iterables.getLast(ShadowLog.getLogsForTag(tag));
269     assertEquals(type, lastLog.type);
270     assertEquals(msg, lastLog.msg);
271     assertEquals(tag, lastLog.tag);
272     assertEquals(throwable, lastLog.throwable);
273   }
274 
assertLogged( String timeString, int type, String tag, String msg, Throwable throwable)275   private static void assertLogged(
276       String timeString, int type, String tag, String msg, Throwable throwable) {
277     LogItem lastLog = Iterables.getLast(ShadowLog.getLogsForTag(tag));
278     assertEquals(timeString, lastLog.timeString);
279     assertLogged(type, tag, msg, throwable);
280   }
281 
282   @Test
identicalLogItemInstancesAreEqual()283   public void identicalLogItemInstancesAreEqual() {
284     LogItem item1 = new LogItem(Log.VERBOSE, "Foo", "Bar", null);
285     LogItem item2 = new LogItem(Log.VERBOSE, "Foo", "Bar", null);
286     assertThat(item1).isEqualTo(item2);
287     assertThat(item2).isEqualTo(item1);
288   }
289 
290   @Test
logsAfterSetLoggable()291   public void logsAfterSetLoggable() {
292     ShadowLog.setLoggable("Foo", Log.VERBOSE);
293     assertTrue(Log.isLoggable("Foo", Log.DEBUG));
294   }
295 
296   @Test
noLogAfterSetLoggable()297   public void noLogAfterSetLoggable() {
298     PrintStream old = ShadowLog.stream;
299     ShadowLog.stream = new PrintStream(new ByteArrayOutputStream());
300     ShadowLog.setLoggable("Foo", Log.DEBUG);
301     assertFalse(Log.isLoggable("Foo", Log.VERBOSE));
302     ShadowLog.stream = old;
303   }
304 
305   @Test
getLogs_shouldReturnCopy()306   public void getLogs_shouldReturnCopy() {
307     Log.d("tag1", "1");
308     assertThat(ShadowLog.getLogs()).isNotSameInstanceAs(ShadowLog.getLogs());
309     assertThat(ShadowLog.getLogs()).isEqualTo(ShadowLog.getLogs());
310   }
311 
312   @Test
getLogsForTag_empty()313   public void getLogsForTag_empty() {
314     assertThat(ShadowLog.getLogsForTag("non_existent")).isEmpty();
315   }
316 
317   @Test
clear()318   public void clear() {
319     assertThat(ShadowLog.getLogsForTag("tag1")).isEmpty();
320     Log.d("tag1", "1");
321     assertThat(ShadowLog.getLogsForTag("tag1")).isNotEmpty();
322     ShadowLog.clear();
323     assertThat(ShadowLog.getLogsForTag("tag1")).isEmpty();
324     assertThat(ShadowLog.getLogs()).isEmpty();
325   }
326 
327   @Test
shouldLogTimeWithTimeSupplier()328   public void shouldLogTimeWithTimeSupplier() {
329     ShadowLog.setTimeSupplier(() -> "20 July 1969 20:17");
330 
331     Log.d("tag", "msg");
332 
333     assertLogged("20 July 1969 20:17", Log.DEBUG, "tag", "msg", null);
334   }
335 
336   @Test
shouldLogToProvidedStreamWithTimeSupplier()337   public void shouldLogToProvidedStreamWithTimeSupplier() {
338     ShadowLog.setTimeSupplier(() -> "20 July 1969 20:17");
339 
340     ByteArrayOutputStream bos = new ByteArrayOutputStream();
341     PrintStream old = ShadowLog.stream;
342     try {
343       ShadowLog.stream = new PrintStream(bos);
344       Log.d("tag", "msg");
345       assertThat(new String(bos.toByteArray(), UTF_8))
346           .isEqualTo("20 July 1969 20:17 D/tag: msg" + LINE_SEPARATOR.value());
347 
348       Log.w("tag", new RuntimeException());
349       assertThat(new String(bos.toByteArray(), UTF_8)).contains("RuntimeException");
350     } finally {
351       ShadowLog.stream = old;
352     }
353   }
354 
355   @Test
resetShouldClearTimeSupplier()356   public void resetShouldClearTimeSupplier() {
357     ShadowLog.setTimeSupplier(() -> "15 June 1977 20:17");
358     ShadowLog.reset();
359 
360     ByteArrayOutputStream bos = new ByteArrayOutputStream();
361     PrintStream old = ShadowLog.stream;
362     try {
363       ShadowLog.stream = new PrintStream(bos);
364       Log.d("tag", "msg");
365       assertThat(new String(bos.toByteArray(), UTF_8))
366           .isEqualTo("D/tag: msg" + LINE_SEPARATOR.value());
367 
368       Log.w("tag", new RuntimeException());
369       assertThat(new String(bos.toByteArray(), UTF_8)).contains("RuntimeException");
370     } finally {
371       ShadowLog.stream = old;
372     }
373   }
374 }
375