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.mock2;
014
015import java.io.*;
016import org.apache.juneau.assertions.*;
017import org.apache.juneau.rest.client2.*;
018
019/**
020 * A capturing {@link PrintStream} that allows you to easily capture console output.
021 *
022 * <p>
023 * Stores output into an internal {@link ByteArrayOutputStream}.  Note that this means you could run into memory
024 * constraints if you heavily use this class.
025 *
026 * <p>
027 * Typically used in conjunction with the {@link RestClientBuilder#console(PrintStream)} to capture console output for
028 * testing purposes.
029 *
030 * <h5 class='figure'>Example:</h5>
031 * <p class='bcode w800'>
032 *    <jc>// A simple REST API that echos a posted bean.</jc>
033 *    <ja>@Rest</ja>
034 *    <jk>public class</jk> MyRest <jk>extends</jk> BasicRest {
035 *       <ja>@RestMethod</ja>(path=<js>"/bean"</js>)
036 *       <jk>public</jk> Bean postBean(<ja>@Body</ja> Bean b) {
037 *          <jk>return</jk> b;
038 *       }
039 *    }
040 *
041 * <jc>// Our mock console.</jc>
042 *    MockConsole console = MockConsole.<jsm>create</jsm>();
043 *
044 * <jc>// Make a call against our REST API and log the call.</jc>
045 *    MockRestClient
046 *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
047 *       .simpleJson()
048 *       .logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>)
049 *       .logToConsole()
050 *       .console(console)
051 *       .build()
052 *       .post(<js>"/bean"</js>, bean)
053 *       .run();
054 *
055 *    console.assertContents().is(
056 *       <js>""</js>,
057 *       <js>"=== HTTP Call (outgoing) ======================================================"</js>,
058 *       <js>"=== REQUEST ==="</js>,
059 *       <js>"POST http://localhost/bean"</js>,
060 *       <js>"---request headers---"</js>,
061 *       <js>" Accept: application/json+simple"</js>,
062 *       <js>"---request entity---"</js>,
063 *       <js>" Content-Type: application/json+simple"</js>,
064 *       <js>"---request content---"</js>,
065 *       <js>"{f:1}"</js>,
066 *       <js>"=== RESPONSE ==="</js>,
067 *       <js>"HTTP/1.1 200 "</js>,
068 *       <js>"---response headers---"</js>,
069 *       <js>" Content-Type: application/json"</js>,
070 *       <js>"---response content---"</js>,
071 *       <js>"{f:1}"</js>,
072 *       <js>"=== END ======================================================================="</js>,
073 *       <js>""</js>
074 *    );
075 * </p>
076 */
077public class MockConsole extends PrintStream {
078
079   private static final ByteArrayOutputStream baos = new ByteArrayOutputStream();
080
081   /**
082    * Constructor.
083    */
084   public MockConsole() {
085      super(baos);
086   }
087
088   /**
089    * Creator.
090    *
091    * @return A new {@link MockConsole} object.
092    */
093   public static MockConsole create() {
094      return new MockConsole();
095   }
096
097   /**
098    * Resets the contents of this buffer.
099    *
100    * @return This object (for method chaining).
101    */
102   public synchronized MockConsole reset() {
103      baos.reset();
104      return this;
105   }
106
107   /**
108    * Allows you to perform fluent-style assertions on the contents of this buffer.
109    *
110    * <h5 class='figure'>Example:</h5>
111    * <p class='bcode w800'>
112    *    MockConsole console = MockConsole.<jsf>create</jsf>();
113    *
114    *    MockRestClient
115    *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
116    *       .console(console)
117    *       .debug()
118    *       .simpleJson()
119    *       .build()
120    *       .get(<js>"/url"</js>)
121    *       .run();
122    *
123    *    console.assertContents().contains(<js>"HTTP GET /url"</js>);
124    * </p>
125    *
126    * @return A new fluent-style assertion object.
127    */
128   public synchronized FluentStringAssertion<MockConsole> assertContents() {
129      return new FluentStringAssertion<>(toString(), this);
130   }
131
132   /**
133    * Allows you to perform fluent-style assertions on the size of this buffer.
134    *
135    * <h5 class='figure'>Example:</h5>
136    * <p class='bcode w800'>
137    *    MockConsole console = MockConsole.<jsf>create</jsf>();
138    *
139    *    MockRestClient
140    *       .<jsm>create</jsm>(MyRest.<jk>class</jk>)
141    *       .console(console)
142    *       .debug()
143    *       .simpleJson()
144    *       .build()
145    *       .get(<js>"/url"</js>)
146    *       .run();
147    *
148    *    console.assertSize().isGreaterThan(0);
149    * </p>
150    *
151    * @return A new fluent-style assertion object.
152    */
153   public synchronized FluentIntegerAssertion<MockConsole> assertSize() {
154      return new FluentIntegerAssertion<>(baos.size(), this);
155   }
156
157   /**
158    * Returns the contents of this buffer as a string.
159    */
160   @Override
161   public String toString() {
162      return baos.toString();
163   }
164}