001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.mock;
014
015import java.io.*;
016import org.apache.juneau.assertions.*;
017
018/**
019 * A capturing {@link PrintStream} that allows you to easily capture console output.
020 *
021 * <p>
022 * Stores output into an internal {@link ByteArrayOutputStream}.  Note that this means you could run into memory
023 * constraints if you heavily use this class.
024 *
025 * <p>
026 * Typically used in conjunction with the {@link org.apache.juneau.rest.client.RestClient.Builder#console(PrintStream)} to capture console output for
027 * testing purposes.
028 *
029 * <h5 class='figure'>Example:</h5>
030 * <p class='bjava'>
031 *    <jc>// A simple REST API that echos a posted bean.</jc>
032 *    <ja>@Rest</ja>
033 *    <jk>public class</jk> MyRest <jk>extends</jk> BasicRestObject {
034 *       <ja>@RestPost</ja>(<js>"/bean"</js>)
035 *       <jk>public</jk> Bean postBean(<ja>@Content</ja> Bean <jv>bean</jv>) {
036 *          <jk>return</jk> <jv>bean</jv>;
037 *       }
038 *    }
039 *
040 * <jc>// Our mock console.</jc>
041 *    MockConsole <jv>console</jv> = MockConsole.<jsm>create</jsm>();
042 *
043 * <jc>// Make a call against our REST API and log the call.</jc>
044 *    MockRestClient
045 *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
046 *       .json5()
047 *       .logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>)
048 *       .logToConsole()
049 *       .console(<jv>console</jv>)
050 *       .build()
051 *       .post(<js>"/bean"</js>, <jv>bean</jv>)
052 *       .run();
053 *
054 *    <jv>console</jv>.assertContents().is(
055 *       <js>""</js>,
056 *       <js>"=== HTTP Call (outgoing) ======================================================"</js>,
057 *       <js>"=== REQUEST ==="</js>,
058 *       <js>"POST http://localhost/bean"</js>,
059 *       <js>"---request headers---"</js>,
060 *       <js>" Accept: application/json5"</js>,
061 *       <js>"---request entity---"</js>,
062 *       <js>" Content-Type: application/json5"</js>,
063 *       <js>"---request content---"</js>,
064 *       <js>"{f:1}"</js>,
065 *       <js>"=== RESPONSE ==="</js>,
066 *       <js>"HTTP/1.1 200 "</js>,
067 *       <js>"---response headers---"</js>,
068 *       <js>" Content-Type: application/json"</js>,
069 *       <js>"---response content---"</js>,
070 *       <js>"{f:1}"</js>,
071 *       <js>"=== END ======================================================================="</js>,
072 *       <js>""</js>
073 *    );
074 * </p>
075 *
076 * <h5 class='section'>See Also:</h5><ul>
077 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-rest-mock">juneau-rest-mock</a>
078 * </ul>
079 */
080public class MockConsole extends PrintStream {
081
082   private static final ByteArrayOutputStream baos = new ByteArrayOutputStream();
083
084   /**
085    * Constructor.
086    */
087   public MockConsole() {
088      super(baos);
089   }
090
091   /**
092    * Creator.
093    *
094    * @return A new {@link MockConsole} object.
095    */
096   public static MockConsole create() {
097      return new MockConsole();
098   }
099
100   /**
101    * Resets the contents of this buffer.
102    *
103    * @return This object.
104    */
105   public synchronized MockConsole reset() {
106      baos.reset();
107      return this;
108   }
109
110   /**
111    * Allows you to perform fluent-style assertions on the contents of this buffer.
112    *
113    * <h5 class='figure'>Example:</h5>
114    * <p class='bjava'>
115    *    MockConsole <jv>console</jv> = MockConsole.<jsf>create</jsf>();
116    *
117    *    MockRestClient
118    *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
119    *       .console(<jv>console</jv>)
120    *       .debug()
121    *       .json5()
122    *       .build()
123    *       .get(<js>"/url"</js>)
124    *       .run();
125    *
126    *    <jv>console</jv>.assertContents().isContains(<js>"HTTP GET /url"</js>);
127    * </p>
128    *
129    * @return A new fluent-style assertion object.
130    */
131   public synchronized FluentStringAssertion<MockConsole> assertContents() {
132      return new FluentStringAssertion<>(toString(), this);
133   }
134
135   /**
136    * Allows you to perform fluent-style assertions on the size of this buffer.
137    *
138    * <h5 class='figure'>Example:</h5>
139    * <p class='bjava'>
140    *    MockConsole <jv>console</jv> = MockConsole.<jsf>create</jsf>();
141    *
142    *    MockRestClient
143    *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
144    *       .console(<jv>console</jv>)
145    *       .debug()
146    *       .json5()
147    *       .build()
148    *       .get(<js>"/url"</js>)
149    *       .run();
150    *
151    *    <jv>console</jv>.assertSize().isGreaterThan(0);
152    * </p>
153    *
154    * @return A new fluent-style assertion object.
155    */
156   public synchronized FluentIntegerAssertion<MockConsole> assertSize() {
157      return new FluentIntegerAssertion<>(baos.size(), this);
158   }
159
160   /**
161    * Returns the contents of this buffer as a string.
162    */
163   @Override
164   public String toString() {
165      return baos.toString();
166   }
167}