001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2023-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.cli; 019 020import java.io.ByteArrayOutputStream; 021import java.io.PrintStream; 022import java.nio.charset.Charset; 023import java.nio.charset.StandardCharsets; 024 025/** 026 * Utility to capture System.out and System.err in unit tests. Note that this doesn't work well 027 * together with code which keeps references to System.out/err in a static, such as JUL; see 028 * EnolaTest. 029 */ 030// TODO Try if LogManager.getLogManager().reset(); could fix ^^^ this? 031public class SystemOutErrCapture implements AutoCloseable { 032 033 // TODO Compare with similar 034 // https://github.com/Hakky54/console-captor/blob/master/src/main/java/nl/altindag/console/ConsoleCaptor.java 035 036 private static final Charset CHARSET = StandardCharsets.UTF_8; 037 038 private final PrintStream originalOut; 039 private final PrintStream originalErr; 040 041 private final ByteArrayOutputStream outBAOS = new ByteArrayOutputStream(); 042 private final ByteArrayOutputStream errBAOS = new ByteArrayOutputStream(); 043 044 private final PrintStream outBAOS_PS; 045 private final PrintStream errBAOS_PS; 046 047 public SystemOutErrCapture() { 048 originalOut = System.out; 049 originalErr = System.err; 050 051 outBAOS_PS = new PrintStream(outBAOS, true, CHARSET); 052 errBAOS_PS = new PrintStream(errBAOS, true, CHARSET); 053 054 System.setOut(outBAOS_PS); 055 System.setErr(errBAOS_PS); 056 } 057 058 public String getSystemOut() { 059 return outBAOS.toString(CHARSET); 060 } 061 062 public String getSystemErr() { 063 return errBAOS.toString(CHARSET); 064 } 065 066 public void clear() { 067 System.setOut(originalOut); 068 System.setErr(originalErr); 069 dump(); 070 outBAOS.reset(); 071 errBAOS.reset(); 072 System.setOut(outBAOS_PS); 073 System.setErr(errBAOS_PS); 074 } 075 076 @Override 077 public void close() throws Exception { 078 System.setOut(originalOut); 079 System.setErr(originalErr); 080 dump(); 081 } 082 083 private void dump() { 084 System.out.print(getSystemOut()); 085 System.err.print(getSystemErr()); 086 } 087}