1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.instanceOf;
21import static org.junit.Assert.assertEquals;
22
23import android.support.test.filters.SmallTest;
24
25import org.junit.Before;
26import org.junit.Test;
27
28/**
29 * Unit tests for {@link LogcatLog}.
30 */
31@SmallTest
32public class LogcatLogTest {
33    private static final String TAG = "LogcatLogTest";
34    private LogcatLog mLogger;
35
36    /** Initializes test fixture. */
37    @Before
38    public void setUp() {
39        mLogger = new LogcatLog(TAG);
40    }
41
42    /**
43     * Verifies that LogcatLog's LogMessage implementation correctly
44     * handles a format with no parameters.
45     *
46     * Note: In practice, we expect clients to use eC() and friends
47     * when the message is a literal. But we still want to make sure
48     * this functionality works.
49     */
50    @Test
51    public void logMessageWorksWithParameterlessFormat() {
52        WifiLog.LogMessage logMessage = mLogger.err("hello world");
53        logMessage.flush();
54        assertEquals("hello world", logMessage.toString());
55    }
56
57    /** Verifies that LogMessage works with an empty format. */
58    @Test
59    public void logMessageWorksWithEmptyFormat() {
60        WifiLog.LogMessage logMessage = mLogger.err("");
61        logMessage.flush();
62        assertEquals("", logMessage.toString());
63    }
64
65    /** Verifies that LogMessage works with a value-only format. */
66    @Test
67    public void logMessageWorksWithValueOnly() {
68        WifiLog.LogMessage logMessage = mLogger.err("%");
69        logMessage.c(1).flush();
70        assertEquals("1", logMessage.toString());
71    }
72
73    /**
74     * Verifies that LogMessage works when the placeholder is replaced
75     * by the placeholder character.
76     */
77    @Test
78    public void logMessageIsNotConfusedByPlaceholderInValue() {
79        WifiLog.LogMessage logMessage = mLogger.err("%");
80        logMessage.c('%').flush();
81        assertEquals("%", logMessage.toString());
82    }
83
84    /** Verifies that LogMessage works when a value is at the start of the format. */
85    @Test
86    public void logMessageWorksWithValueAtBegin() {
87        WifiLog.LogMessage logMessage = mLogger.err("%stuff");
88        logMessage.c(1).flush();
89        assertEquals("1stuff", logMessage.toString());
90    }
91
92    /** Verifies that LogMessage works when a value is in the middle of the format. */
93    @Test
94    public void logMessageWorksWithValueInMiddle() {
95        WifiLog.LogMessage logMessage = mLogger.err("s%uff");
96        logMessage.c(1).flush();
97        assertEquals("s1uff", logMessage.toString());
98    }
99
100    /** Verifies that LogMessage works when a value is at the end of the format. */
101    @Test
102    public void logMessageWorksWithValueAtEnd() {
103        WifiLog.LogMessage logMessage = mLogger.err("stuff%");
104        logMessage.c(1).flush();
105        assertEquals("stuff1", logMessage.toString());
106    }
107
108    /** Verifies that LogMessage works when a format has multiple values. */
109    @Test
110    public void logMessageWorksWithMultipleValues() {
111        WifiLog.LogMessage logMessage = mLogger.err("% %");
112        logMessage.c("hello").c("world").flush();
113        assertEquals("hello world", logMessage.toString());
114    }
115
116    /** Verifies that LogMessage works when a format has multiple values and literals. */
117    @Test
118    public void logMessageWorksWithMultipleValuesAndLiterals() {
119        WifiLog.LogMessage logMessage = mLogger.err("first:% second:%");
120        logMessage.c("hello").c("world").flush();
121        assertEquals("first:hello second:world", logMessage.toString());
122    }
123
124    /** Verifies that LogMessage works when a format has multiple adjacent values. */
125    @Test
126    public void logMessageWorksWithAdjacentValues() {
127        WifiLog.LogMessage logMessage = mLogger.err("%%");
128        logMessage.c("hello").c("world").flush();
129        assertEquals("helloworld", logMessage.toString());
130    }
131
132    /** Verifies that LogMessage silently ignores extraneous values. */
133    @Test
134    public void logMessageSilentlyIgnoresExtraneousValues() {
135        WifiLog.LogMessage logMessage = mLogger.err("%");
136        logMessage.c("hello world").c("more stuff").flush();
137        assertEquals("hello world", logMessage.toString());
138    }
139
140    /**
141     * Verifies that LogMessage silently ignores extraneous values,
142     * even with an empty format string.
143     */
144    @Test
145    public void logMessageSilentlyIgnoresExtraneousValuesEvenForEmptyFormat() {
146        WifiLog.LogMessage logMessage = mLogger.err("");
147        logMessage.c("hello world").c("more stuff").flush();
148        assertEquals("", logMessage.toString());
149    }
150
151    /**
152     * Verifies that LogMessage silently ignores extraneous values,
153     * even if the format string is all literals.
154     */
155    @Test
156    public void logMessageSilentlyIgnoresExtraneousValuesEvenForFormatWithoutPlaceholders() {
157        WifiLog.LogMessage logMessage = mLogger.err("literal format");
158        logMessage.c("hello world").c("more stuff").flush();
159        assertEquals("literal format", logMessage.toString());
160    }
161
162    /** Verifies that LogMessage copies an unused placeholder to output. */
163    @Test
164    public void logMessageCopiesUnusedPlaceholderToOutput() {
165        WifiLog.LogMessage logMessage = mLogger.err("%");
166        logMessage.flush();
167        assertEquals("%", logMessage.toString());
168    }
169
170    /** Verifies that LogMessage copies multiple unused placeholders to output. */
171    @Test
172    public void logMessageCopiesMultipleUnusedPlaceholdersToOutput() {
173        WifiLog.LogMessage logMessage = mLogger.err("%%%%%");
174        logMessage.flush();
175        assertEquals("%%%%%", logMessage.toString());
176    }
177
178    /**
179     * Verifies that LogMessage copies an unused placeholder to output,
180     * even if preceded by non-placeholders.
181     */
182    @Test
183    public void logMessageCopiesUnusedPlaceholderAtEndToOutput() {
184        WifiLog.LogMessage logMessage = mLogger.err("foo%");
185        logMessage.flush();
186        assertEquals("foo%", logMessage.toString());
187    }
188
189    /**
190     * Verifies that LogMessage copies an unused placeholder to output,
191     * even if followed by non-placeholders.
192     */
193    @Test
194    public void logMessageCopiesUnusedPlaceholderAtBeginToOutput() {
195        WifiLog.LogMessage logMessage = mLogger.err("%foo");
196        logMessage.flush();
197        assertEquals("%foo", logMessage.toString());
198    }
199
200    /**
201     * Verifies that LogMessage copies an unused placeholder to output,
202     * even if it is in the middle of non-placeholders.
203     */
204    @Test
205    public void logMessageCopiesUnusedPlaceholderInMiddleToOutput() {
206        WifiLog.LogMessage logMessage = mLogger.err("f%o");
207        logMessage.flush();
208        assertEquals("f%o", logMessage.toString());
209    }
210
211    /**
212     * Verifies that LogMessage copies multiple unused placeholders to output,
213     * even if they are embedded amongst non-placeholders.
214     */
215    @Test
216    public void logMessageCopiesUnusedPlaceholdersInMiddleToOutput() {
217        WifiLog.LogMessage logMessage = mLogger.err("f%o%o%d");
218        logMessage.flush();
219        assertEquals("f%o%o%d", logMessage.toString());
220    }
221
222    /**
223     * Verifies that LogMessage preserves meta-characters in format string.
224     *
225     * Note that we deliberately test only the meta-characters that we
226     * expect to find in log messages. (Newline might also be
227     * preserved, but clients shouldn't depend on that, as messages
228     * that have newlines make logs hard to read.)
229     */
230    @Test
231    public void logMessagePreservesMetaCharactersInFormat() {
232        WifiLog.LogMessage logMessage = mLogger.err("\\hello\tworld\\");
233        logMessage.flush();
234        assertEquals("\\hello\tworld\\", logMessage.toString());
235    }
236
237    /** Verifies that LogMessage propagates meta-characters in char values. */
238    @Test
239    public void logMessagePropagatesMetaCharactersInCharValues() {
240        WifiLog.LogMessage logMessage = mLogger.err("hello%big%world");
241        logMessage.c('\t').c('\\').flush();
242        assertEquals("hello\tbig\\world", logMessage.toString());
243    }
244
245    /** Verifies that LogMessage propagates meta-characters in String values. */
246    @Test
247    public void logMessagePropagatesMetaCharactersInStringValues() {
248        WifiLog.LogMessage logMessage = mLogger.err("%%world");
249        logMessage.c("hello\t").c("big\\").flush();
250        assertEquals("hello\tbig\\world", logMessage.toString());
251    }
252
253    @Test
254    public void traceLogMessageIncludesCallerName() {
255        try {
256            LogcatLog.enableVerboseLogging(1);
257            WifiLog.LogMessage logMessage = mLogger.trace("%");
258            logMessage.c("says hello").flush();
259            assertEquals("traceLogMessageIncludesCallerName says hello",
260                    logMessage.toString());
261        } finally {
262            LogcatLog.enableVerboseLogging(0);
263        }
264    }
265
266    @Test
267    public void traceLogMessageRespectsNumFramesToIgnore() {
268        try {
269            LogcatLog.enableVerboseLogging(1);
270            WifiLog.LogMessage logMessage = traceHelper("%");
271            logMessage.c("says hello").flush();
272            assertEquals("traceLogMessageRespectsNumFramesToIgnore says hello",
273                    logMessage.toString());
274        } finally {
275            LogcatLog.enableVerboseLogging(0);
276        }
277    }
278
279    @Test
280    public void traceLogMessageDoesNotCrashOnOversizedNumFramesToIgnore() {
281        try {
282            LogcatLog.enableVerboseLogging(1);
283            WifiLog.LogMessage logMessage = mLogger.trace("%",
284                    (new Throwable()).getStackTrace().length);
285            logMessage.c("says hello").flush();
286            assertEquals("<unknown> says hello", logMessage.toString());
287        } finally {
288            LogcatLog.enableVerboseLogging(0);
289        }
290    }
291
292    @Test
293    public void traceLogMessageDoesNotCrashOnOverflowingNumFramesToIgnore() {
294        try {
295            LogcatLog.enableVerboseLogging(1);
296            WifiLog.LogMessage logMessage = mLogger.trace("%", Integer.MAX_VALUE);
297            logMessage.c("says hello").flush();
298            assertEquals("<unknown> says hello", logMessage.toString());
299        } finally {
300            LogcatLog.enableVerboseLogging(0);
301        }
302    }
303
304    @Test
305    public void traceLogMessageDoesNotCrashOnUndersizedNumFramesToIgnore() {
306        try {
307            LogcatLog.enableVerboseLogging(1);
308            WifiLog.LogMessage logMessage = mLogger.trace("%", Integer.MIN_VALUE);
309            logMessage.c("says hello").flush();
310            assertEquals("<unknown> says hello", logMessage.toString());
311        } finally {
312            LogcatLog.enableVerboseLogging(0);
313        }
314    }
315
316    @Test
317    public void traceLogMessageReturnsDummyLogMessageByDefault() {
318        assertThat(mLogger.trace("%"), instanceOf(DummyLogMessage.class));
319    }
320
321    @Test
322    public void dumpLogMessageReturnsDummyLogMessageByDefault() {
323        assertThat(mLogger.dump("%"), instanceOf(DummyLogMessage.class));
324    }
325
326    private WifiLog.LogMessage traceHelper(String format) {
327        return mLogger.trace(format, 1);
328    }
329}
330