├── .editorconfig ├── .github └── workflows │ └── release-latest-version.yaml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── History.md ├── LICENSE ├── README.md ├── appveyor.yml ├── custom-checkstyle.xml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── system-stubs-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── uk │ │ └── org │ │ └── webcompere │ │ └── systemstubs │ │ ├── SystemStubs.java │ │ ├── ThrowingRunnable.java │ │ ├── environment │ │ ├── EnvironmentVariableMocker.java │ │ └── EnvironmentVariables.java │ │ ├── exception │ │ ├── LoadingException.java │ │ └── WrappedThrowable.java │ │ ├── properties │ │ ├── PropertiesUtils.java │ │ ├── SystemProperties.java │ │ └── SystemPropertiesImpl.java │ │ ├── resource │ │ ├── Executable.java │ │ ├── NameValuePairSetter.java │ │ ├── PropertySource.java │ │ ├── Resources.java │ │ ├── SingularTestResource.java │ │ └── TestResource.java │ │ ├── security │ │ ├── AbortExecutionException.java │ │ ├── NoExitSecurityManager.java │ │ ├── SecurityManagerStub.java │ │ └── SystemExit.java │ │ └── stream │ │ ├── StreamException.java │ │ ├── SystemErr.java │ │ ├── SystemErrAndOut.java │ │ ├── SystemIn.java │ │ ├── SystemOut.java │ │ ├── SystemStreamBase.java │ │ ├── input │ │ ├── AltInputStream.java │ │ ├── DecoratingAltStream.java │ │ ├── LinesAltStream.java │ │ ├── TextAltStream.java │ │ └── ThrowAtEndStream.java │ │ └── output │ │ ├── DisallowWriteStream.java │ │ ├── MultiplexOutput.java │ │ ├── NoopStream.java │ │ ├── Output.java │ │ ├── OutputFactories.java │ │ ├── OutputFactory.java │ │ └── TapStream.java │ └── test │ ├── java │ └── uk │ │ └── org │ │ └── webcompere │ │ └── systemstubs │ │ ├── AssertNothingWrittenToSystemErrTest.java │ │ ├── AssertNothingWrittenToSystemOutTest.java │ │ ├── CatchSystemExitTest.java │ │ ├── MethodUnderTest.java │ │ ├── MuteSystemErrTest.java │ │ ├── MuteSystemOutTest.java │ │ ├── PropertiesFileLoadingTest.java │ │ ├── RestoreSystemErrChecks.java │ │ ├── RestoreSystemOutChecks.java │ │ ├── RestoreSystemPropertiesTest.java │ │ ├── SecurityManagerMock.java │ │ ├── TapSystemErrAndOutTest.java │ │ ├── TapSystemErrNormalizedTest.java │ │ ├── TapSystemErrTest.java │ │ ├── TapSystemOutNormalizedTest.java │ │ ├── TapSystemOutTest.java │ │ ├── ThrowingRunnableMock.java │ │ ├── WithEnvironmentVariableTest.java │ │ ├── WithSecurityManagerTest.java │ │ ├── WithTextFromSystemInTest.java │ │ ├── environment │ │ ├── EnvironmentVariableMockerTest.java │ │ └── EnvironmentVariablesTest.java │ │ ├── properties │ │ └── SystemPropertiesTest.java │ │ ├── resource │ │ ├── PropertySourceTest.java │ │ ├── ResourcesTest.java │ │ └── SingularTestResourceTest.java │ │ ├── security │ │ └── SystemExitTest.java │ │ └── stream │ │ ├── SystemErrAndOutTest.java │ │ ├── SystemInTest.java │ │ ├── SystemStreamBaseTest.java │ │ ├── input │ │ ├── TextAltStreamTest.java │ │ └── ThrowAtEndStreamTest.java │ │ └── output │ │ ├── MultiplexOutputTest.java │ │ └── OutputFactoriesTest.java │ └── resources │ └── test.properties ├── system-stubs-interceptor ├── pom.xml └── src │ └── main │ └── java │ └── uk │ └── org │ └── webcompere │ └── systemstubs │ └── internal │ └── ProcessEnvironmentInterceptor.java ├── system-stubs-junit4 ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── uk │ │ └── org │ │ └── webcompere │ │ └── systemstubs │ │ └── rules │ │ ├── EnvironmentVariablesRule.java │ │ ├── SecurityManagerRule.java │ │ ├── SystemErrAndOutRule.java │ │ ├── SystemErrRule.java │ │ ├── SystemExitRule.java │ │ ├── SystemInRule.java │ │ ├── SystemOutRule.java │ │ ├── SystemPropertiesRule.java │ │ └── internal │ │ ├── Statements.java │ │ └── SystemStubTestRule.java │ └── test │ ├── java │ └── uk │ │ └── org │ │ └── webcompere │ │ └── systemstubs │ │ └── rules │ │ ├── ClassRuleTest.java │ │ ├── EnvironmentVariablesRuleTest.java │ │ ├── SecurityManagerRuleTest.java │ │ ├── SystemErrAndOutRuleTest.java │ │ ├── SystemExitRuleTest.java │ │ ├── SystemInRuleTest.java │ │ ├── SystemOutAndSystemErrTest.java │ │ ├── SystemOutRuleTest.java │ │ └── SystemPropertiesRuleTest.java │ └── resources │ └── test.properties ├── system-stubs-jupiter ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── uk │ │ └── org │ │ └── webcompere │ │ └── systemstubs │ │ └── jupiter │ │ ├── SystemStub.java │ │ └── SystemStubsExtension.java │ └── test │ └── java │ └── uk │ └── org │ └── webcompere │ └── systemstubs │ └── jupiter │ ├── SystemStubsExtensionStaticClassTest.java │ ├── SystemStubsExtensionTest.java │ ├── compatibility │ └── DoesNotPreventJUnitPioneerFromWorkingTest.java │ └── examples │ ├── EnvironmentVariablesAcrossThreads.java │ ├── InjectByParameter.java │ ├── MultipleTestResources.java │ ├── SpringAppWithDynamicPropertiesTest.java │ ├── SystemExitUseCase.java │ └── WithEnvironmentVariables.java └── system-stubs-testng ├── README.md ├── pom.xml └── src ├── main └── java │ └── uk │ └── org │ └── webcompere │ └── systemstubs │ └── testng │ ├── SystemStub.java │ └── SystemStubsListener.java └── test └── java └── uk └── org └── webcompere └── systemstubs └── testng ├── SystemStubsPluginWhenStubIsBlankTest.java ├── SystemStubsPluginWhenStubIsDefinedTest.java └── examples ├── CaptureSystemOutTest.java └── SystemStubsWithoutPluginTest.java /.editorconfig: -------------------------------------------------------------------------------- 1 | # Configuration file for EditorConfig: http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 4 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.{xml,yml}] 13 | indent_size = 2 14 | 15 | -------------------------------------------------------------------------------- /.github/workflows/release-latest-version.yaml: -------------------------------------------------------------------------------- 1 | name: Publish package to the Maven Central Repository 2 | on: 3 | # release: 4 | # types: [created] 5 | workflow_dispatch: 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: Set up Maven Central Repository 12 | uses: actions/setup-java@v4 13 | with: 14 | java-version: '11' 15 | distribution: 'temurin' 16 | server-id: ossrh 17 | server-username: MAVEN_USERNAME 18 | server-password: MAVEN_PASSWORD 19 | - id: install-secret-key 20 | name: Install gpg secret key 21 | run: | 22 | # Install gpg secret key 23 | cat <(echo -e "${{ secrets.GPG_PRIVATE_KEY }}") | gpg --batch --import 24 | 25 | # Verify gpg secret key 26 | gpg --list-secret-keys --keyid-format LONG 27 | - name: Publish package 28 | run: mvn -Prelease-sign-artifacts -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} --batch-mode deploy 29 | env: 30 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} 31 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .flattened-pom.xml 2 | target 3 | *.iml 4 | .idea/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webcompere/system-stubs/9af1410bc93790f560e4cd355f85457dac87e0c9/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | # History 2 | 3 | Based on the excellent work by Stefan Birkner in [System Rules](https://stefanbirkner.github.io/system-rules/index.html) and [System Lambda](https://github.com/stefanbirkner/system-lambda) this is a remix 4 | of the core techniques, to allow them to be used more flexibly. 5 | 6 | No longer limited to just being a JUnit4 rule (SystemRules) and available as a JUnit 5 plugin, this version is intended to increase usability and configurability, in a way that diverges from the original trajectory of **System Lambda**. 7 | 8 | This version comes with the [agreement](https://github.com/stefanbirkner/system-lambda/issues/9) of the original author. The original author bears no responsibility for this version. 9 | 10 | ### Differences 11 | 12 | The main aims of this version: 13 | 14 | - Enable environment variables to be set before child test suites execute 15 | - allow environment details to be set in _beforeAll_ or _beforeEach_ hooks 16 | - as can be necessary for Spring tests 17 | - Support JUnit4 and JUnit5 plugins 18 | - reduce test boilerplate 19 | - Provide more configuration and fluent setters 20 | - Modularise the code 21 | - Standardise testing around _Mockito_ and _AssertJ_ 22 | - Standardise around the Java Library as much as possible 23 | 24 | ### Execute Around 25 | 26 | In order to support migration from [System Lambda](https://github.com/stefanbirkner/system-lambda), and to enable reuse of the original unit tests, the `SystemStubs` facade supports the [execute around](https://java-design-patterns.com/patterns/execute-around/) idiom. 27 | 28 | To use the `SystemStubs` facade: 29 | 30 | ```java 31 | import static uk.org.webcompere.systemstubs.SystemStubs.*; 32 | ``` 33 | 34 | Then methods like `assertNothingWrittenToSystemOut` or `restoreSystemProperties` will work as they did in System Lambda. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Ashley Frieze (c) 2017 Stefan Birkner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | 3 | stack: jdk 11 4 | environment: 5 | matrix: 6 | - job_name: Windows build JDK 11 7 | appveyor_build_worker_image: Visual Studio 2015 8 | JAVA_HOME: C:\Program Files\Java\jdk11 9 | - job_name: Windows build JDK 17 10 | appveyor_build_worker_image: Visual Studio 2019 11 | JAVA_HOME: C:\Program Files\Java\jdk17 12 | - job_name: Linux build 13 | appveyor_build_worker_image: Ubuntu 14 | 15 | cache: 16 | - /home/appveyor/.m2 17 | - C:\Users\appveyor\.m2 18 | build_script: 19 | - ./mvnw clean package -DskipTests 20 | test_script: 21 | - ./mvnw verify 22 | after_test: 23 | - sh: CODECOV_TOKEN="be37aef1-3b14-4433-9d91-c8dd3af65285" bash <(curl -s https://codecov.io/bash) 24 | -------------------------------------------------------------------------------- /system-stubs-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | uk.org.webcompere 7 | system-stubs-parent 8 | 2.1.8 9 | ../pom.xml 10 | 11 | 12 | system-stubs-core 13 | 2.1.8 14 | jar 15 | 16 | System Stubs Core 17 | A collection of functions for testing code which uses java.lang.System. 18 | 19 | 20 | 11 21 | 11 22 | 23 | 24 | 25 | 26 | uk.org.webcompere 27 | system-stubs-interceptor 28 | provided 29 | 30 | 31 | org.apache.commons 32 | commons-lang3 33 | test 34 | 35 | 36 | org.assertj 37 | assertj-core 38 | test 39 | 40 | 41 | org.junit.jupiter 42 | junit-jupiter 43 | test 44 | 45 | 46 | org.mockito 47 | mockito-junit-jupiter 48 | test 49 | 50 | 51 | net.bytebuddy 52 | byte-buddy 53 | 54 | 55 | net.bytebuddy 56 | byte-buddy-agent 57 | 58 | 59 | com.github.spotbugs 60 | spotbugs-annotations 61 | 62 | 63 | 64 | 65 | 66 | 67 | ../system-stubs-interceptor/target/ 68 | 69 | system-stubs-interceptor.jar 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-surefire-plugin 77 | 78 | 79 | org.jacoco 80 | jacoco-maven-plugin 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-checkstyle-plugin 85 | 86 | 87 | com.github.spotbugs 88 | spotbugs-maven-plugin 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-gpg-plugin 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-source-plugin 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-javadoc-plugin 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/ThrowingRunnable.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import uk.org.webcompere.systemstubs.exception.WrappedThrowable; 4 | 5 | import java.util.concurrent.Callable; 6 | 7 | /** 8 | * Code that can be executed by one of the methods of {@link SystemStubs}. 9 | * This code may throw an {@link Exception}. Therefore we cannot use 10 | * {@link Runnable}. 11 | * @since 1.0.0 12 | */ 13 | public interface ThrowingRunnable { 14 | /** 15 | * Execute the action. 16 | * 17 | * @throws Exception the action may throw an arbitrary exception. 18 | */ 19 | void run() throws Throwable; 20 | 21 | /** 22 | * Convert this to a Callable 23 | * @return a {@link Callable} which executes this 24 | */ 25 | default Callable asCallable() { 26 | return () -> { 27 | try { 28 | run(); 29 | } catch (Error | Exception e) { 30 | throw e; 31 | } catch (Throwable t) { 32 | throw new WrappedThrowable(t); 33 | } 34 | return null; 35 | }; 36 | } 37 | 38 | /** 39 | * Convert a lambda of type runnable to Callable 40 | * @param runnable a runnable that can be converted 41 | * @return a {@link Callable} 42 | * @since 1.0.0 43 | */ 44 | static Callable asCallable(ThrowingRunnable runnable) { 45 | return runnable.asCallable(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/environment/EnvironmentVariableMocker.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.environment; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import net.bytebuddy.ByteBuddy; 5 | import net.bytebuddy.agent.ByteBuddyAgent; 6 | import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; 7 | import net.bytebuddy.implementation.MethodDelegation; 8 | import uk.org.webcompere.systemstubs.internal.ProcessEnvironmentInterceptor; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.lang.instrument.Instrumentation; 14 | import java.util.*; 15 | import java.util.jar.JarFile; 16 | 17 | import static net.bytebuddy.matcher.ElementMatchers.isStatic; 18 | import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; 19 | 20 | /** 21 | * This takes control of the environment variables using ByteBuddy. It captures the environment 22 | * when first used, and defaults to that. When the {@link EnvironmentVariables} mock wishes to provide 23 | * mocking, the alternative map of variables is put into a stack and set as the current variables used by 24 | * the interceptor. 25 | */ 26 | @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED", 27 | justification = "We need to set up the stub, but interaction is set on construction") 28 | public class EnvironmentVariableMocker { 29 | private static final Stack> REPLACEMENT_ENV = new Stack<>(); 30 | private static final Map ORIGINAL_ENV; 31 | 32 | static { 33 | ORIGINAL_ENV = new HashMap<>(System.getenv()); 34 | try { 35 | Instrumentation instrumentation = ByteBuddyAgent.install(); 36 | installInterceptorIntoBootLoader(instrumentation); 37 | 38 | var byteBuddy = new ByteBuddy(); 39 | byteBuddy.redefine(Class.forName("java.lang.ProcessEnvironment")) 40 | .method(isStatic().and(namedOneOf("getenv", "environment", "toEnvironmentBlock"))) 41 | .intercept(MethodDelegation.to(ProcessEnvironmentInterceptor.class)) 42 | .make() 43 | .load( 44 | EnvironmentVariableMocker.class.getClassLoader(), 45 | ClassReloadingStrategy.fromInstalledAgent()); 46 | 47 | ProcessEnvironmentInterceptor.setEnv(ORIGINAL_ENV); 48 | } catch (Throwable e) { 49 | 50 | throw new IllegalStateException("Cannot set up environment mocking: " + e.getMessage() + 51 | ".", e); 52 | } 53 | } 54 | 55 | private static void installInterceptorIntoBootLoader(Instrumentation instrumentation) throws IOException { 56 | File tempFile = File.createTempFile("interceptor",".jar"); 57 | tempFile.deleteOnExit(); 58 | try (FileOutputStream file = new FileOutputStream(tempFile); 59 | var resourceStream = EnvironmentVariableMocker.class.getClassLoader() 60 | .getResourceAsStream("system-stubs-interceptor.jar")) { 61 | resourceStream.transferTo(file); 62 | } 63 | 64 | instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(tempFile)); 65 | } 66 | 67 | @Deprecated(since = "2.1.5") 68 | public static void connect(Map newEnvironmentVariables) { 69 | connect(newEnvironmentVariables, Collections.emptySet()); 70 | } 71 | 72 | /** 73 | * Attach a map as the mutable replacement environment variables for now. This can be done 74 | * multiple times and each time the replacement will supersede the maps before. Then when {@link #pop()} 75 | * is called, we'll rollback to the previous. 76 | * @param newEnvironmentVariables the mutable map - note: this will be populated by the current 77 | * environment 78 | * @param variablesToRemove a list of variables to take out of the resulting environment variables 79 | */ 80 | public static void connect(Map newEnvironmentVariables, Set variablesToRemove) { 81 | // add all entries not already present in the new environment variables 82 | System.getenv().entrySet().stream() 83 | .filter(entry -> !newEnvironmentVariables.containsKey(entry.getKey())) 84 | .forEach(entry -> newEnvironmentVariables.put(entry.getKey(), entry.getValue())); 85 | variablesToRemove.forEach(newEnvironmentVariables::remove); 86 | REPLACEMENT_ENV.push(newEnvironmentVariables); 87 | ProcessEnvironmentInterceptor.setEnv(newEnvironmentVariables); 88 | } 89 | 90 | /** 91 | * Remove the latest set of mock environment variables. This will run all the way to empty, after which 92 | * the original implementation of the getenv functions will be called directly again. 93 | * @return true if mocking has now stopped 94 | */ 95 | public static synchronized boolean pop() { 96 | if (!REPLACEMENT_ENV.empty()) { 97 | REPLACEMENT_ENV.pop(); 98 | } 99 | 100 | if (!REPLACEMENT_ENV.empty()) { 101 | ProcessEnvironmentInterceptor.setEnv(REPLACEMENT_ENV.peek()); 102 | } else { 103 | ProcessEnvironmentInterceptor.setEnv(ORIGINAL_ENV); 104 | } 105 | 106 | return REPLACEMENT_ENV.empty(); 107 | } 108 | 109 | /** 110 | * A safer form - allows us to remove the specific map that we want to 111 | * @param theOneToPop the map to remove 112 | * @return true if removed 113 | */ 114 | public static synchronized boolean remove(Map theOneToPop) { 115 | var result = REPLACEMENT_ENV.remove(theOneToPop); 116 | 117 | if (!REPLACEMENT_ENV.empty()) { 118 | ProcessEnvironmentInterceptor.setEnv(REPLACEMENT_ENV.peek()); 119 | } else { 120 | ProcessEnvironmentInterceptor.setEnv(ORIGINAL_ENV); 121 | } 122 | 123 | return result; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/exception/LoadingException.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.exception; 2 | 3 | /** 4 | * When something fails to load as part of a System Stubs operation 5 | */ 6 | public class LoadingException extends RuntimeException { 7 | /** 8 | * Construct the Loading exception 9 | * @param message the message 10 | * @param cause the root cause 11 | */ 12 | public LoadingException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/exception/WrappedThrowable.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.exception; 2 | 3 | /** 4 | * Wrapper to help pass a throwable out through a {@link java.util.concurrent.Callable} 5 | */ 6 | public class WrappedThrowable extends RuntimeException { 7 | public WrappedThrowable(Throwable cause) { 8 | super(cause); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/properties/PropertiesUtils.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.properties; 2 | 3 | import java.util.Map; 4 | import java.util.Properties; 5 | 6 | import static java.util.stream.Collectors.toMap; 7 | 8 | public class PropertiesUtils { 9 | /** 10 | * Produce a clone of some properties in a new object 11 | * @param source the source to clone 12 | * @return a distinct copy 13 | */ 14 | public static Properties copyOf(Properties source) { 15 | Properties copy = new Properties(); 16 | copy.putAll(source); 17 | return copy; 18 | } 19 | 20 | /** 21 | * Convert a properties object to a map 22 | * @param properties the source properties 23 | * @return a Map 24 | */ 25 | public static Map toStringMap(Properties properties) { 26 | return properties.entrySet() 27 | .stream() 28 | .collect(toMap(entry -> String.valueOf(entry.getKey()), 29 | entry -> String.valueOf(entry.getValue()))); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/properties/SystemProperties.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.properties; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * Maintain system properties after a test from the ones before the test. Stores the 7 | * existing properties when started, and restores them when complete. Allows for a list of properties 8 | * that will be applied to the system to be set before the stubbing is triggered. 9 | */ 10 | public class SystemProperties extends SystemPropertiesImpl { 11 | 12 | public SystemProperties() { 13 | super(); 14 | } 15 | 16 | public SystemProperties(Properties properties) { 17 | super(properties); 18 | } 19 | 20 | public SystemProperties(String name, String value, String... nameValues) { 21 | super(name, value, nameValues); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/properties/SystemPropertiesImpl.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.properties; 2 | 3 | import uk.org.webcompere.systemstubs.resource.NameValuePairSetter; 4 | import uk.org.webcompere.systemstubs.resource.SingularTestResource; 5 | 6 | import java.util.HashSet; 7 | import java.util.Properties; 8 | import java.util.Set; 9 | 10 | import static java.lang.System.getProperties; 11 | import static java.lang.System.setProperties; 12 | 13 | /** 14 | * Maintain system properties after a test from the ones before the test. Stores the 15 | * existing properties when started, and restores them when complete. Allows for a list of properties 16 | * that will be applied to the system to be set before the stubbing is triggered. 17 | */ 18 | public class SystemPropertiesImpl> extends SingularTestResource 19 | implements NameValuePairSetter { 20 | private Properties originalProperties; 21 | private Properties properties; 22 | 23 | private Set propertiesToRemove = new HashSet<>(); 24 | 25 | /** 26 | * Default constructor with no properties. Use {@link #set} to set properties 27 | * either while active or before activation. 28 | * @since 1.0.0 29 | */ 30 | public SystemPropertiesImpl() { 31 | this.properties = new Properties(); 32 | } 33 | 34 | /** 35 | * Construct with a specific set of properties. 36 | * @param properties properties to use 37 | * @since 1.0.0 38 | */ 39 | public SystemPropertiesImpl(Properties properties) { 40 | this.properties = PropertiesUtils.copyOf(properties); 41 | } 42 | 43 | /** 44 | * Construct with a set of properties to apply when the object is active 45 | * @param name name of the first property 46 | * @param value value of the first property 47 | * @param nameValues pairs of names and values for further properties 48 | * @since 1.0.0 49 | */ 50 | public SystemPropertiesImpl(String name, String value, String... nameValues) { 51 | this(); 52 | if (nameValues.length % 2 != 0) { 53 | throw new IllegalArgumentException("Must have pairs of values"); 54 | } 55 | properties.setProperty(name, value); 56 | for (int i = 0; i < nameValues.length; i += 2) { 57 | properties.setProperty(nameValues[i], nameValues[i + 1]); 58 | } 59 | } 60 | 61 | /** 62 | * Set a system property. If active, this will set it with {@link System#setProperty(String, String)}. 63 | * If not active, then this will store the property to apply when this object is part of an execution. 64 | * It is also possible to use {@link System#setProperty(String, String)} while this object is active, 65 | * but when the execution finishes, this object will be unaware of the property set, so will not set 66 | * it next time. 67 | * @param name name of the property 68 | * @param value value to set 69 | * @return this object for fluent use 70 | * @since 1.0.0 71 | */ 72 | @Override 73 | @SuppressWarnings("unchecked") 74 | public T set(String name, String value) { 75 | properties.setProperty(name, value); 76 | if (isActive()) { 77 | System.setProperty(name, value); 78 | } 79 | return (T) this; 80 | } 81 | 82 | /** 83 | * Remove a property - this removes it from system properties if active, and remembers to remove it 84 | * while the object is active 85 | * @param name the name of the property to remove 86 | * @return this for fluent use 87 | * @since 2.1.5 88 | */ 89 | @Override 90 | @SuppressWarnings("unchecked") 91 | public T remove(String name) { 92 | propertiesToRemove.add(name); 93 | if (isActive()) { 94 | System.getProperties().remove(name); 95 | } 96 | return (T) this; 97 | } 98 | 99 | @Override 100 | protected void doSetup() throws Exception { 101 | originalProperties = getProperties(); 102 | Properties copyProperties = PropertiesUtils.copyOf(originalProperties); 103 | propertiesToRemove.forEach(copyProperties::remove); 104 | copyProperties.putAll(properties); 105 | setProperties(copyProperties); 106 | } 107 | 108 | @Override 109 | protected void doTeardown() throws Exception { 110 | setProperties(originalProperties); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/Executable.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import uk.org.webcompere.systemstubs.ThrowingRunnable; 4 | 5 | import java.util.concurrent.Callable; 6 | 7 | /** 8 | * The execution interface. Defines the execute-around pattern 9 | * where an object can set up and tear down some sort of resource in a try-finally block 10 | * around calling some inner operation, returning its value. 11 | * @since 1.0.0 12 | */ 13 | @FunctionalInterface 14 | public interface Executable { 15 | /** 16 | * Execute this test resource around a callable 17 | * @param callable the callable to execute 18 | * @param the type of object to return 19 | * @return the result of the operation 20 | * @throws Exception on any error thrown by the callable 21 | */ 22 | T execute(Callable callable) throws Exception; 23 | 24 | /** 25 | * Execute this test resource around a runnnable 26 | * @param runnable the runnable to execute 27 | * @throws Exception on any error thrown by the callable 28 | */ 29 | default void execute(ThrowingRunnable runnable) throws Exception { 30 | execute(runnable.asCallable()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/NameValuePairSetter.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import java.util.Map; 4 | import java.util.Properties; 5 | 6 | /** 7 | * The general interface of something that can set name value pairs on itself 8 | * @param the final type of the class which provides this 9 | */ 10 | public interface NameValuePairSetter> { 11 | /** 12 | * Set a name value pair 13 | * @param name the name 14 | * @param value the value 15 | * @return this for fluent calling 16 | */ 17 | T set(String name, String value); 18 | 19 | /** 20 | * Set many name value pairs at once 21 | * @param nameValuePairs an even number of inputs, whose {@link Object#toString()} is used for each name/value 22 | * @return this for fluent calling 23 | */ 24 | @SuppressWarnings("unchecked") 25 | default T set(Object... nameValuePairs) { 26 | if (nameValuePairs.length % 2 != 0) { 27 | throw new IllegalArgumentException("Must provide an even number of name/value pairs"); 28 | } 29 | for (int i = 0; i < nameValuePairs.length; i += 2) { 30 | set(nameValuePairs[i].toString(), nameValuePairs[i + 1].toString()); 31 | } 32 | return (T)this; 33 | } 34 | 35 | /** 36 | * Set from a collection of properties. Use with {@link PropertySource#fromFile} for example. 37 | * @param properties a map of values, or {@link Properties} object 38 | * @return this for fluent calling 39 | */ 40 | @SuppressWarnings("unchecked") 41 | default T set(Map properties) { 42 | properties.forEach((key, value) -> set(String.valueOf(key), String.valueOf(value))); 43 | return (T)this; 44 | } 45 | 46 | /** 47 | * Remove one of the name value pairs 48 | * @param name the name 49 | * @return this for fluent calling 50 | */ 51 | T remove(String name); 52 | } 53 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/PropertySource.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import uk.org.webcompere.systemstubs.exception.LoadingException; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | import java.util.Properties; 12 | 13 | /** 14 | * Methods to load properties from files or resources 15 | */ 16 | public class PropertySource { 17 | /** 18 | * Load properties from a file path 19 | * @param path the path to the file 20 | * @return a {@link Properties} object 21 | */ 22 | public static Properties fromFile(Path path) { 23 | return fromFile(path.toFile()); 24 | } 25 | 26 | /** 27 | * Load properties from a file path 28 | * @param path the path to the file 29 | * @return a {@link Properties} object 30 | */ 31 | public static Properties fromFile(String path) { 32 | return fromFile(Paths.get(path)); 33 | } 34 | 35 | /** 36 | * Load properties from a file 37 | * @param file the file 38 | * @return a {@link Properties} object 39 | */ 40 | public static Properties fromFile(File file) { 41 | try { 42 | return fromInputStream(new FileInputStream(file)); 43 | } catch (IOException e) { 44 | throw new LoadingException("Cannot read file: " + file.getAbsolutePath(), e); 45 | } 46 | } 47 | 48 | /** 49 | * Load properties from a resource 50 | * @param resourceName the resource to load 51 | * @return a {@link Properties} object 52 | */ 53 | public static Properties fromResource(String resourceName) { 54 | return fromInputStream(PropertySource.class.getClassLoader().getResourceAsStream(resourceName)); 55 | } 56 | 57 | /** 58 | * Load properties from a given input stream. Note, the subclasses of 59 | * {@link uk.org.webcompere.systemstubs.stream.input.AltInputStream} like 60 | * {@link uk.org.webcompere.systemstubs.stream.input.LinesAltStream} may be a useful way to programmatically 61 | * set properties from lines in the name=value syntax used by properties files. 62 | * @param stream the stream to load 63 | * @return a {@link Properties} objects 64 | */ 65 | public static Properties fromInputStream(InputStream stream) { 66 | try (InputStream read = stream) { 67 | Properties properties = new Properties(); 68 | properties.load(read); 69 | return properties; 70 | } catch (IOException e) { 71 | throw new LoadingException("Could not load values", e); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/Resources.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | 7 | /** 8 | * Helper functions for test resources 9 | */ 10 | public class Resources { 11 | /** 12 | * Use the execute around idiom with multiple resources 13 | * @param resources the resources to wrap around the test, in the order to set them up 14 | * @param the return type 15 | * @return an {@link Executable} with the {@link Executable#execute} methods on it 16 | */ 17 | public static Executable with(TestResource... resources) { 18 | return new Executable() { 19 | @Override 20 | public T execute(Callable callable) throws Exception { 21 | return Resources.execute(callable, resources); 22 | } 23 | }; 24 | } 25 | 26 | /** 27 | * The execute-around idiom. Prepares a resource, runs the resources and then cleans up. The resources 28 | * are set up in the order of declaration and tidied in reverse order. Any failure during set up results in 29 | * a corresponding teardown operation, just in case, but only for those resources that have been set up so far. 30 | * @param callable the item to run 31 | * @param resources the resources to set up 32 | * @throws Exception on error 33 | */ 34 | public static T execute(Callable callable, TestResource... resources) throws Exception { 35 | LinkedList resourcesSetUp = new LinkedList<>(); 36 | 37 | try { 38 | for (TestResource resource : resources) { 39 | resourcesSetUp.addFirst(resource); 40 | resource.setup(); 41 | } 42 | 43 | return callable.call(); 44 | } finally { 45 | executeCleanup(resourcesSetUp); 46 | } 47 | } 48 | 49 | /** 50 | * Clean up all of the resources provided, tolerating exceptions in any of them and throwing 51 | * at the end if necessary 52 | * @param resourcesSetUp the list of resources in the order to clean them up 53 | * @throws Exception on the first teardown error 54 | */ 55 | public static void executeCleanup(List resourcesSetUp) throws Exception { 56 | Exception firstExceptionThrownOnTidyUp = null; 57 | for (TestResource resource : resourcesSetUp) { 58 | try { 59 | resource.teardown(); 60 | } catch (Exception e) { 61 | firstExceptionThrownOnTidyUp = firstExceptionThrownOnTidyUp == null ? e : firstExceptionThrownOnTidyUp; 62 | } 63 | } 64 | if (firstExceptionThrownOnTidyUp != null) { 65 | throw firstExceptionThrownOnTidyUp; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/SingularTestResource.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | /** 4 | * Adds reference counting to the {@link TestResource} interface in case something tries to perform 5 | * multiple setup or teardown calls on the same resource. Promises only a single instance of the 6 | * set up at a time. 7 | * @since 1.0.0 8 | */ 9 | public abstract class SingularTestResource implements TestResource { 10 | private int refCount = 0; 11 | 12 | @Override 13 | public void setup() throws Exception { 14 | refCount++; 15 | 16 | if (refCount == 1) { 17 | doSetup(); 18 | } 19 | } 20 | 21 | @Override 22 | public void teardown() throws Exception { 23 | refCount--; 24 | 25 | if (refCount == 0) { 26 | doTeardown(); 27 | } 28 | 29 | if (refCount < 0) { 30 | refCount = 0; 31 | } 32 | } 33 | 34 | /** 35 | * Subclass overrides this to provide actual setup 36 | * @throws Exception on setup error 37 | */ 38 | protected abstract void doSetup() throws Exception; 39 | 40 | /** 41 | * Subclass overrides this to provide actual cleanup 42 | * @throws Exception on clean up error 43 | */ 44 | protected abstract void doTeardown() throws Exception; 45 | 46 | protected boolean isActive() { 47 | return refCount > 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/TestResource.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * A test resource is something that can be set up at the start of a test and 7 | * torn down at the end. 8 | */ 9 | public interface TestResource extends Executable { 10 | /** 11 | * Prepare the resource for testing 12 | * @throws Exception on error starting 13 | */ 14 | void setup() throws Exception; 15 | 16 | /** 17 | * Clean up the resource 18 | * @throws Exception on error cleaning up 19 | */ 20 | void teardown() throws Exception; 21 | 22 | /** 23 | * Execute this test resource around a callable 24 | * @param callable the callable to execute 25 | * @param the type of object to return 26 | * @return the result of the operation 27 | * @throws Exception on any error thrown by the callable 28 | * @since 1.0.0 29 | */ 30 | default T execute(Callable callable) throws Exception { 31 | return Resources.execute(callable, this); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/security/AbortExecutionException.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.security; 2 | 3 | /** 4 | * Can be thrown by a Security Manager to stop execution of the test. The {@link SecurityManagerStub} 5 | * will recognise that the test hasn't failed, but the code under test needs to stop. 6 | */ 7 | public class AbortExecutionException extends SecurityException { 8 | private static final long serialVersionUID = 159678654L; 9 | } 10 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/security/SecurityManagerStub.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.security; 2 | 3 | import uk.org.webcompere.systemstubs.resource.SingularTestResource; 4 | 5 | import java.util.concurrent.Callable; 6 | 7 | /** 8 | * Switch the security manager for an alternative 9 | * @since 1.0.0 10 | */ 11 | public class SecurityManagerStub extends SingularTestResource { 12 | private SecurityManager originalSecurityManager; 13 | private T securityManager; 14 | 15 | /** 16 | * Default constructor for subclasses that will provide a create method on the fly 17 | */ 18 | public SecurityManagerStub() { 19 | this(null); 20 | } 21 | 22 | /** 23 | * Construct with the security manager to substitute. If null, then one will be created using 24 | * the factory method at setup time. 25 | * @param securityManager a security manager to use while active 26 | */ 27 | public SecurityManagerStub(T securityManager) { 28 | this.securityManager = securityManager; 29 | } 30 | 31 | /** 32 | * Get the security manager that this class uses when active 33 | * @return the security manager 34 | */ 35 | public T getSecurityManager() { 36 | return securityManager; 37 | } 38 | 39 | /** 40 | * Called if we need to wipe the current security manager 41 | */ 42 | protected void clearSecurityManager() { 43 | this.securityManager = null; 44 | } 45 | 46 | /** 47 | * Set the current security manager 48 | * @param securityManager the manager to set 49 | */ 50 | public void setSecurityManager(T securityManager) { 51 | this.securityManager = securityManager; 52 | if (isActive()) { 53 | System.setSecurityManager(securityManager); 54 | } 55 | } 56 | 57 | @Override 58 | protected void doSetup() throws Exception { 59 | originalSecurityManager = System.getSecurityManager(); 60 | 61 | if (securityManager == null) { 62 | securityManager = createSecurityManager(); 63 | } 64 | 65 | setSecurityManager(securityManager); 66 | } 67 | 68 | @Override 69 | protected void doTeardown() throws Exception { 70 | System.setSecurityManager(originalSecurityManager); 71 | } 72 | 73 | /** 74 | * Override to create a specific security manager 75 | * @return a new security manager - can be null 76 | */ 77 | protected T createSecurityManager() { 78 | return null; 79 | } 80 | 81 | /** 82 | * Overridden to notice the abort exception that marks exit tests and others where we 83 | * want to tap into a stop in processing to find the exit code etc. 84 | * @param callable the callable to execute 85 | * @param return type 86 | * @return the result of the callable or null if there was an early abort 87 | * @throws Exception on exceptions that are not {@link AbortExecutionException} 88 | */ 89 | @Override 90 | public R execute(Callable callable) throws Exception { 91 | try { 92 | return super.execute(callable); 93 | } catch (AbortExecutionException ignoreAbortExecution) { 94 | // stop the test early and return 95 | return null; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/security/SystemExit.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.security; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | 5 | /** 6 | * A {@link uk.org.webcompere.systemstubs.resource.TestResource} which provides the exit code called when it was active. 7 | * Gives access to the {@link NoExitSecurityManager} object inside via {@link SecurityManagerStub#getSecurityManager()}. 8 | * When the {@link NoExitSecurityManager} is in use, any calls to {@link System#exit(int)} are converted 9 | * to an {@link AbortExecutionException} which the surrounding test can catch. 10 | * @since 1.0.0 11 | */ 12 | public class SystemExit extends SecurityManagerStub { 13 | /** 14 | * What was the exit code provided if System.exit was called. 15 | * @return exit code or null if no exit called 16 | */ 17 | @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE") 18 | public Integer getExitCode() { 19 | return getSecurityManager() == null ? null : getSecurityManager().getExitCode(); 20 | } 21 | 22 | @Override 23 | protected NoExitSecurityManager createSecurityManager() { 24 | return new NoExitSecurityManager(System.getSecurityManager()); 25 | } 26 | 27 | @Override 28 | protected void doSetup() throws Exception { 29 | // clear any previous security managers 30 | clearSecurityManager(); 31 | super.doSetup(); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/StreamException.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | /** 4 | * Thrown when there is an error substituting a system stream 5 | */ 6 | public class StreamException extends RuntimeException { 7 | public StreamException(String message, Throwable cause) { 8 | super(message, cause); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/SystemErr.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import uk.org.webcompere.systemstubs.stream.output.Output; 4 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 5 | 6 | import java.io.OutputStream; 7 | 8 | /** 9 | * Replace System.err with an alternative 10 | * @since 1.0.0 11 | */ 12 | public class SystemErr extends SystemStreamBase { 13 | 14 | /** 15 | * Construct with the {@link OutputStream} to use in place of System.err 16 | * @param output new output target 17 | */ 18 | public SystemErr(Output output) { 19 | super(output, System::setErr, () -> System.err); 20 | } 21 | 22 | /** 23 | * Construct with a {@link OutputFactory} for creating output objects from the existing output 24 | * @param outputFactory the factory to use 25 | */ 26 | public SystemErr(OutputFactory outputFactory) { 27 | super(outputFactory, System::setErr, () -> System.err); 28 | } 29 | 30 | /** 31 | * Default constructor, taps the output 32 | */ 33 | public SystemErr() { 34 | super(System::setErr, () -> System.err); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/SystemErrAndOut.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import uk.org.webcompere.systemstubs.resource.Resources; 4 | import uk.org.webcompere.systemstubs.resource.TestResource; 5 | import uk.org.webcompere.systemstubs.stream.output.Output; 6 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 7 | import uk.org.webcompere.systemstubs.stream.output.TapStream; 8 | 9 | import java.io.OutputStream; 10 | 11 | import static java.util.Arrays.asList; 12 | 13 | /** 14 | * Composite of both {@link SystemErr} and {@link SystemOut} for when directing 15 | * both of them to the same stream 16 | * @since 1.0.0 17 | */ 18 | public class SystemErrAndOut implements Output, TestResource { 19 | private SystemErr systemErr; 20 | private SystemOut systemOut; 21 | 22 | /** 23 | * Default constructor uses {@link TapStream}, shared for both System.out and System.err 24 | */ 25 | public SystemErrAndOut() { 26 | this(new TapStream()); 27 | } 28 | 29 | /** 30 | * Construct with an output shared from the an output created against the System.out original 31 | * @param outputFactory the output factory to create the output 32 | */ 33 | public SystemErrAndOut(OutputFactory outputFactory) { 34 | systemOut = new SystemOut(outputFactory); 35 | systemErr = new SystemErr(outputStream -> systemOut.getOutput()); 36 | } 37 | 38 | /** 39 | * Construct with a target to direct both System out and error to 40 | * @param output the output target 41 | */ 42 | public SystemErrAndOut(Output output) { 43 | this(output.factoryOfSelf()); 44 | } 45 | 46 | @Override 47 | public void setup() throws Exception { 48 | systemOut.setup(); 49 | systemErr.setup(); 50 | } 51 | 52 | @Override 53 | public void teardown() throws Exception { 54 | Resources.executeCleanup(asList(systemOut, systemErr)); 55 | } 56 | 57 | @Override 58 | public String getText() { 59 | // both share the output, so use Err's 60 | return systemErr.getText(); 61 | } 62 | 63 | @Override 64 | public void clear() { 65 | // only clear one of them as they share the same output 66 | systemErr.clear(); 67 | } 68 | 69 | @Override 70 | public OutputStream getOutputStream() { 71 | return systemErr.getOutputStream(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/SystemIn.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import uk.org.webcompere.systemstubs.ThrowingRunnable; 4 | import uk.org.webcompere.systemstubs.resource.SingularTestResource; 5 | import uk.org.webcompere.systemstubs.stream.input.*; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | import static java.lang.System.setIn; 11 | 12 | /** 13 | * A stub that defines the text provided by {@code System.in}. The methods 14 | * {@link #andExceptionThrownOnInputEnd(IOException)} and 15 | * {@link #andExceptionThrownOnInputEnd(RuntimeException)} can be used to 16 | * simulate a {@code System.in} that throws an exception. 17 | * The specified behaviour of {@code System.in} is applied to an 18 | * arbitrary piece of code that is provided to {@link #execute(ThrowingRunnable)}. 19 | * @since 1.0.0 20 | */ 21 | public class SystemIn extends SingularTestResource { 22 | private InputStream originalIn; 23 | private AltInputStream altInputStream; 24 | 25 | /** 26 | * Default constructor for use by reflection 27 | */ 28 | public SystemIn() { 29 | this(new String[0]); 30 | } 31 | 32 | /** 33 | * Construct with the lines of text to provide as input 34 | * @param lines lines provided as input using {@link LinesAltStream} 35 | */ 36 | public SystemIn(String... lines) { 37 | this(new LinesAltStream(lines)); 38 | } 39 | 40 | /** 41 | * Construct with a specific input stream - e.g. a FileInputStream 42 | * @param inputStream the input stream to route to System in 43 | */ 44 | public SystemIn(InputStream inputStream) { 45 | this(new DecoratingAltStream(inputStream)); 46 | } 47 | 48 | /** 49 | * Construct with an {@link AltInputStream} - e.g. a {@link TextAltStream} 50 | * or custom provider of input. 51 | * @param altInputStream the stream ot use 52 | */ 53 | public SystemIn(AltInputStream altInputStream) { 54 | this.altInputStream = altInputStream; 55 | } 56 | 57 | /** 58 | * Fluent setter to set the input stream 59 | * @param inputStream stream to use 60 | * @return this for fluent use 61 | */ 62 | public SystemIn setInputStream(InputStream inputStream) { 63 | return setInputStream(new DecoratingAltStream(inputStream)); 64 | } 65 | 66 | /** 67 | * Fluent setter to set the input stream 68 | * @param altInputStream stream to use 69 | * @return this for fluent use 70 | */ 71 | public SystemIn setInputStream(AltInputStream altInputStream) { 72 | if (isActive()) { 73 | setIn(altInputStream); 74 | } 75 | this.altInputStream = altInputStream; 76 | return this; 77 | } 78 | 79 | /** 80 | * Sets an exception that is thrown after the text is read. 81 | * @param exception the {@code IOException} to be thrown. 82 | * @return the {@code SystemInStub} itself. 83 | * @throws IllegalStateException if a {@code RuntimeException} was 84 | * already set by {@link #andExceptionThrownOnInputEnd(RuntimeException)} 85 | */ 86 | public SystemIn andExceptionThrownOnInputEnd(IOException exception) { 87 | if (altInputStream.contains(ThrowAtEndStream.class)) { 88 | throw new IllegalStateException("You cannot call" + 89 | " andExceptionThrownOnInputEnd(IOException) because" + 90 | " andExceptionThrownOnInputEnd has" + 91 | " already been called."); 92 | } 93 | 94 | setInputStream(new ThrowAtEndStream(altInputStream, exception)); 95 | 96 | return this; 97 | } 98 | 99 | /** 100 | * Sets an exception that is thrown after the text is read. 101 | * @param exception the {@code RuntimeException} to be thrown. 102 | * @return the {@code SystemInStub} itself. 103 | * @throws IllegalStateException if an {@code IOException} was already 104 | * set by {@link #andExceptionThrownOnInputEnd(IOException)} 105 | */ 106 | public SystemIn andExceptionThrownOnInputEnd(RuntimeException exception) { 107 | if (altInputStream.contains(ThrowAtEndStream.class)) { 108 | throw new IllegalStateException("You cannot call" + 109 | " andExceptionThrownOnInputEnd(RuntimeException) because" + 110 | " andExceptionThrownOnInputEnd has" + 111 | " already been called."); 112 | } 113 | 114 | setInputStream(new ThrowAtEndStream(altInputStream, exception)); 115 | 116 | return this; 117 | } 118 | 119 | @Override 120 | protected void doSetup() throws Exception { 121 | originalIn = System.in; 122 | setIn(altInputStream); 123 | } 124 | 125 | @Override 126 | protected void doTeardown() throws Exception { 127 | setIn(originalIn); 128 | altInputStream.close(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/SystemOut.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import uk.org.webcompere.systemstubs.stream.output.Output; 4 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 5 | 6 | import java.io.OutputStream; 7 | 8 | /** 9 | * Replace System.out with an alternative 10 | * @since 1.0.0 11 | */ 12 | public class SystemOut extends SystemStreamBase { 13 | /** 14 | * Construct with the {@link OutputStream} to use in place of System.out 15 | * @param output new output target 16 | */ 17 | public SystemOut(Output output) { 18 | super(output, System::setOut, () -> System.out); 19 | } 20 | 21 | /** 22 | * Construct with a {@link OutputFactory} for creating output objects from the existing output 23 | * @param outputFactory the factory to use 24 | */ 25 | public SystemOut(OutputFactory outputFactory) { 26 | super(outputFactory, System::setOut, () -> System.out); 27 | } 28 | 29 | /** 30 | * Default constructor, taps the output 31 | */ 32 | public SystemOut() { 33 | super(System::setOut, () -> System.out); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/SystemStreamBase.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import uk.org.webcompere.systemstubs.resource.SingularTestResource; 4 | import uk.org.webcompere.systemstubs.stream.output.Output; 5 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 6 | import uk.org.webcompere.systemstubs.stream.output.TapStream; 7 | 8 | import java.io.OutputStream; 9 | import java.io.PrintStream; 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.function.Consumer; 12 | import java.util.function.Supplier; 13 | 14 | import static java.nio.charset.Charset.defaultCharset; 15 | 16 | /** 17 | * A general purpose replacement for a system stream. Uses an {@link Output} object 18 | * in place of the intended stream while active. Presents methods to access the output. 19 | * When active converts the output into a {@link PrintStream} and applies it to the 20 | * environment. 21 | * @since 1.0.0 22 | */ 23 | public class SystemStreamBase extends SingularTestResource implements Output { 24 | private static final boolean AUTO_FLUSH = true; 25 | private static final String DEFAULT_ENCODING = defaultCharset().name(); 26 | 27 | protected PrintStream originalStream; 28 | protected Output currentTarget; 29 | protected OutputFactory targetFactory; 30 | protected Consumer printStreamSetter; 31 | protected Supplier printStreamGetter; 32 | 33 | protected SystemStreamBase(Consumer printStreamSetter, 34 | Supplier printStreamGetter) { 35 | this(new TapStream(), printStreamSetter, printStreamGetter); 36 | } 37 | 38 | protected SystemStreamBase(Output target, 39 | Consumer printStreamSetter, 40 | Supplier printStreamGetter) { 41 | this(target.factoryOfSelf(), printStreamSetter, printStreamGetter); 42 | } 43 | 44 | protected SystemStreamBase(OutputFactory targetFactory, 45 | Consumer printStreamSetter, 46 | Supplier printStreamGetter) { 47 | this.targetFactory = targetFactory; 48 | this.printStreamSetter = printStreamSetter; 49 | this.printStreamGetter = printStreamGetter; 50 | } 51 | 52 | /** 53 | * Convert an output stream to a {@link PrintStream} 54 | * @param outputStream the output stream to use 55 | * @return a {@link PrintStream} that can be written to 56 | * @throws UnsupportedEncodingException on errors constructing the stream (unlikely) 57 | */ 58 | public static PrintStream wrap(OutputStream outputStream) throws UnsupportedEncodingException { 59 | return new PrintStream(outputStream, 60 | AUTO_FLUSH, 61 | DEFAULT_ENCODING); 62 | } 63 | 64 | @Override 65 | protected void doSetup() throws Exception { 66 | // in case this is being reused, it is cleared on setup 67 | clear(); 68 | 69 | originalStream = printStreamGetter.get(); 70 | try { 71 | currentTarget = targetFactory.apply(originalStream); 72 | printStreamSetter.accept(wrap(currentTarget.getOutputStream())); 73 | } catch (UnsupportedEncodingException e) { 74 | throw new StreamException("Cannot wrap stream: " + e.getMessage(), e); 75 | } 76 | } 77 | 78 | @Override 79 | protected void doTeardown() throws Exception { 80 | printStreamSetter.accept(originalStream); 81 | 82 | // for outputs like files, that need to be closed 83 | currentTarget.closeOutput(); 84 | } 85 | 86 | @Override 87 | public String getText() { 88 | return currentTarget.getText(); 89 | } 90 | 91 | @Override 92 | public void clear() { 93 | if (currentTarget != null) { 94 | currentTarget.clear(); 95 | } 96 | } 97 | 98 | @Override 99 | public OutputStream getOutputStream() { 100 | if (currentTarget == null) { 101 | return null; 102 | } 103 | return currentTarget.getOutputStream(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/input/AltInputStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import java.io.InputStream; 4 | 5 | /** 6 | * Base class for alternative input streams 7 | */ 8 | public abstract class AltInputStream extends InputStream { 9 | /** 10 | * Is this input stream of the given type, or a decorator of a stream of the 11 | * given type? 12 | * @param stream type of stream 13 | * @return true if there is already one of these in the chain 14 | */ 15 | public boolean contains(Class stream) { 16 | return stream.isAssignableFrom(this.getClass()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/input/DecoratingAltStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | /** 7 | * Decorates one stream by delegating to another 8 | */ 9 | public class DecoratingAltStream extends AltInputStream { 10 | private InputStream decoratee; 11 | 12 | /** 13 | * Construct the stream with the decoratee 14 | * @param decoratee the input stream that will be read from 15 | */ 16 | public DecoratingAltStream(InputStream decoratee) { 17 | this.decoratee = decoratee; 18 | } 19 | 20 | @Override 21 | public int read() throws IOException { 22 | return decoratee.read(); 23 | } 24 | 25 | @Override 26 | public int read(byte[] b, int off, int len) throws IOException { 27 | return decoratee.read(b, off, len); 28 | } 29 | 30 | @Override 31 | public void close() throws IOException { 32 | decoratee.close(); 33 | } 34 | 35 | @Override 36 | public boolean contains(Class stream) { 37 | return super.contains(stream) || 38 | stream.isAssignableFrom(decoratee.getClass()) || 39 | (decoratee instanceof AltInputStream && ((AltInputStream)decoratee).contains(stream)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/input/LinesAltStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import java.io.IOException; 4 | import java.nio.charset.Charset; 5 | import java.util.Arrays; 6 | import java.util.Iterator; 7 | import java.util.stream.IntStream; 8 | import java.util.stream.Stream; 9 | 10 | import static java.lang.System.lineSeparator; 11 | 12 | /** 13 | * Provides lines of text from a source stream as an input stream 14 | */ 15 | public class LinesAltStream extends AltInputStream { 16 | private Iterator byteIterator; 17 | 18 | /** 19 | * Given a stream of lines, supply them as an input stream 20 | * @param lines lines as a stream 21 | */ 22 | public LinesAltStream(String... lines) { 23 | this(Arrays.stream(lines), true); 24 | } 25 | 26 | /** 27 | * Given a stream of lines, supply them as an input stream 28 | * @param lines lines as a stream 29 | */ 30 | public LinesAltStream(Stream lines) { 31 | this(lines, true); 32 | } 33 | 34 | /** 35 | * Given a stream of lines, supply them as an input stream with optional line breaks added 36 | * @param lines the lines of the stream 37 | * @param addLineBreak whether to add a line break 38 | */ 39 | public LinesAltStream(Stream lines, boolean addLineBreak) { 40 | Stream source = addLineBreak ? lines.flatMap(line -> Stream.of(line, lineSeparator())) : lines; 41 | 42 | byteIterator = source.flatMap(LinesAltStream::toByteArrayStream) 43 | .iterator(); 44 | } 45 | 46 | @Override 47 | public int read() throws IOException { 48 | return byteIterator.hasNext() ? byteIterator.next() : -1; 49 | } 50 | 51 | private static Stream toByteArrayStream(String s) { 52 | byte[] bytes = s.getBytes(Charset.defaultCharset()); 53 | return IntStream.range(0, bytes.length) 54 | .mapToObj(i -> bytes[i]); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/input/TextAltStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.nio.charset.Charset; 5 | 6 | /** 7 | * A string stream uses a ByteArray to provide a single string as an input 8 | */ 9 | public class TextAltStream extends DecoratingAltStream { 10 | /** 11 | * Construct with the string to use as an input 12 | * @param string the input string 13 | */ 14 | public TextAltStream(String string) { 15 | super(new ByteArrayInputStream(string.getBytes(Charset.defaultCharset()))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/input/ThrowAtEndStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | 5 | import java.io.IOException; 6 | import java.nio.charset.Charset; 7 | import java.util.Objects; 8 | 9 | import static java.lang.System.lineSeparator; 10 | 11 | /** 12 | * Monitor a stream and throw an exception if a read operation occurs after the last 13 | * character of the stream. This slices the buffer into segments with whole lines in, to avoid 14 | * read-ahead scanners from hitting the error too soon. Decorator/chain of responsibility pattern. 15 | */ 16 | public class ThrowAtEndStream extends DecoratingAltStream { 17 | private IOException ioException; 18 | private RuntimeException runtimeException; 19 | 20 | /** 21 | * Construct to decorate another stream 22 | * @param decoratee real source of the bytes 23 | * @param ioException the {@link IOException} to throw when running out of data 24 | */ 25 | @SuppressFBWarnings("EI_EXPOSE_REP2") 26 | public ThrowAtEndStream(AltInputStream decoratee, IOException ioException) { 27 | super(decoratee); 28 | this.ioException = Objects.requireNonNull(ioException); 29 | } 30 | 31 | /** 32 | * Construct to decorate another stream 33 | * @param decoratee real source of the bytes 34 | * @param runtimeException the {@link RuntimeException} to throw when running out of data 35 | */ 36 | @SuppressFBWarnings("EI_EXPOSE_REP2") 37 | public ThrowAtEndStream(AltInputStream decoratee, RuntimeException runtimeException) { 38 | super(decoratee); 39 | this.runtimeException = Objects.requireNonNull(runtimeException); 40 | } 41 | 42 | @Override 43 | public int read() throws IOException { 44 | int next = super.read(); 45 | if (next == -1) { 46 | throwException(); 47 | } 48 | return next; 49 | } 50 | 51 | @Override 52 | public int read(byte[] buffer, int offset, int len) throws IOException { 53 | if (buffer == null) { 54 | throw new NullPointerException(); 55 | } 56 | if (offset < 0 || len < 0 || len > buffer.length - offset) { 57 | throw new IndexOutOfBoundsException(); 58 | } 59 | if (len == 0) { 60 | return 0; 61 | } 62 | 63 | // return only a line at a time to the calling code 64 | // this prevents an exception being thrown as a caller reads ahead beyond 65 | // the last line 66 | return readNextLine(buffer, offset, len); 67 | } 68 | 69 | private int readNextLine(byte[] buffer, int offset, int len) throws IOException { 70 | byte[] lineSeparator = lineSeparator().getBytes(Charset.defaultCharset()); 71 | int writeLocation = offset; 72 | while ((writeLocation - offset) < len) { 73 | int next = read(); 74 | if (next == -1) { 75 | return writeLocation == offset ? -1 : writeLocation - offset; 76 | } 77 | buffer[writeLocation] = (byte)(next & 0xff); 78 | writeLocation++; 79 | 80 | if (reachedLineEnd(buffer, offset, writeLocation, lineSeparator)) { 81 | break; 82 | } 83 | } 84 | return writeLocation - offset; 85 | } 86 | 87 | private boolean reachedLineEnd(byte[] buffer, int bufferStart, int bufferEnd, byte[] lineSeparator) { 88 | if (bufferEnd - bufferStart < lineSeparator.length) { 89 | return false; 90 | } 91 | 92 | for (int i = 0; i < lineSeparator.length; i++) { 93 | if (buffer[(bufferEnd - lineSeparator.length) + i] != lineSeparator[i]) { 94 | return false; 95 | } 96 | } 97 | 98 | return true; 99 | } 100 | 101 | private void throwException() throws IOException { 102 | if (ioException != null) { 103 | throw ioException; 104 | } 105 | throw runtimeException; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/DisallowWriteStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.OutputStream; 4 | 5 | /** 6 | * An {@link Output} that throws an {@link AssertionError} if anything is written. 7 | * @since 1.0.0 8 | */ 9 | public class DisallowWriteStream extends OutputStream implements Output { 10 | @Override 11 | public void write(int b) { 12 | throw new AssertionError("Tried to write '" + (char) b + 13 | "' although this is not allowed."); 14 | } 15 | 16 | @Override 17 | public DisallowWriteStream getOutputStream() { 18 | return this; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/MultiplexOutput.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.util.Arrays; 6 | import java.util.stream.Stream; 7 | 8 | /** 9 | * A composite output which directs to multiple targets. It reads text from only the first. It is, itself 10 | * an {@link OutputStream} 11 | */ 12 | public class MultiplexOutput extends OutputStream implements Output { 13 | private Output[] outputs; 14 | 15 | /** 16 | * Construct with a variable number of outputs to multiplex to 17 | * @param first the first output 18 | * @param others additional outputs 19 | */ 20 | public MultiplexOutput(Output first, Output... others) { 21 | outputs = Stream.concat(Stream.of(first), Arrays.stream(others)) 22 | .toArray(Output[]::new); 23 | } 24 | 25 | @Override 26 | public void write(int b) throws IOException { 27 | for (Output output : outputs) { 28 | output.getOutputStream().write(b); 29 | } 30 | } 31 | 32 | @Override 33 | public String getText() { 34 | return outputs[0].getText(); 35 | } 36 | 37 | @Override 38 | public void clear() { 39 | for (Output output : outputs) { 40 | output.clear(); 41 | } 42 | } 43 | 44 | @Override 45 | public void close() throws IOException { 46 | try { 47 | closeOutput(); 48 | } catch (IOException e) { 49 | throw e; 50 | } catch (Exception e) { 51 | throw new IOException(e); 52 | } 53 | } 54 | 55 | @Override 56 | public void closeOutput() throws Exception { 57 | for (Output output : outputs) { 58 | output.closeOutput(); 59 | } 60 | } 61 | 62 | @Override 63 | public MultiplexOutput getOutputStream() { 64 | return this; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/NoopStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.OutputStream; 4 | 5 | /** 6 | * An {@link Output} that discards anything written to it. It can be used to mute 7 | * System.err for example. 8 | */ 9 | public class NoopStream extends OutputStream implements Output { 10 | @Override 11 | public void write(int b) { 12 | } 13 | 14 | @Override 15 | public NoopStream getOutputStream() { 16 | return this; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/Output.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.OutputStream; 4 | import java.util.Arrays; 5 | import java.util.regex.Pattern; 6 | import java.util.stream.Stream; 7 | 8 | import static java.util.stream.Collectors.joining; 9 | 10 | /** 11 | * A target for output. This can be plugged into a {@link uk.org.webcompere.systemstubs.stream.SystemStreamBase} 12 | * derived class to be converted to a {@link java.io.PrintStream} for use with System.out 13 | * etc. 14 | * @since 1.0.0 15 | */ 16 | public interface Output { 17 | /** 18 | * Convert an existing {@link OutputStream} into an {@link Output}. Providing no 19 | * ability to clear or get the text of that output stream. 20 | * @param stream the target stream 21 | * @param the type of stream 22 | * @return an {@link Output} object 23 | */ 24 | static Output fromStream(S stream) { 25 | return () -> stream; 26 | } 27 | 28 | /** 29 | * Convert an existing {@link OutputStream} into an {@link Output}. Providing no 30 | * ability to clear or get the text of that output stream. 31 | * @param stream the target stream 32 | * @param the type of stream 33 | * @return an {@link Output} object 34 | */ 35 | static Output fromCloseableStream(S stream) { 36 | return new Output() { 37 | 38 | @Override 39 | public void closeOutput() throws Exception { 40 | stream.close(); 41 | } 42 | 43 | @Override 44 | public S getOutputStream() { 45 | return stream; 46 | } 47 | }; 48 | } 49 | 50 | /** 51 | * Get the plaintext 52 | * @return the output as a single string - not null 53 | */ 54 | default String getText() { 55 | return ""; 56 | } 57 | 58 | /** 59 | * Clear the output fresh for another test 60 | */ 61 | default void clear() { 62 | // does nothing 63 | } 64 | 65 | /** 66 | * When the target stream is meant to be closed, then close it 67 | * @throws Exception on any error closing 68 | */ 69 | default void closeOutput() throws Exception { 70 | // does nothing here 71 | } 72 | 73 | /** 74 | * Access the output stream that's behind this 75 | * @return get the output stream - can be null if the object hasn't been activated 76 | */ 77 | T getOutputStream(); 78 | 79 | /** 80 | * Access the current output object 81 | * @return this if an {@link Output} object, or the child {@link Output} otherwise 82 | */ 83 | default Output getOutput() { 84 | return this; 85 | } 86 | 87 | /** 88 | * Get the plain text broken into lines by the system's line separator 89 | * @return a stream of lines 90 | */ 91 | default Stream getLines() { 92 | return Arrays.stream(getText().split(Pattern.quote(System.lineSeparator()))); 93 | } 94 | 95 | /** 96 | * Get the plain text broken into lines and recombined with \n 97 | * @return the output as a single string 98 | */ 99 | default String getLinesNormalized() { 100 | return getLinesNormalized("\n"); 101 | } 102 | 103 | /** 104 | * Get the plain text broken into lines and recombined with a custom delimited 105 | * @param linebreak the linebreak delimiter 106 | * @return the output as a single string 107 | */ 108 | default String getLinesNormalized(String linebreak) { 109 | String combined = getLines().collect(joining(linebreak)); 110 | if (combined.isEmpty()) { 111 | return ""; 112 | } 113 | // the split process removes a trailing linebreak/implied end linebreak 114 | return combined + linebreak; 115 | } 116 | 117 | /** 118 | * Convert this {@link Output} into a factory which does nothing except return this 119 | * @return a factory 120 | */ 121 | default OutputFactory factoryOfSelf() { 122 | return original -> this; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/OutputFactories.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.util.Arrays; 6 | import java.util.stream.Stream; 7 | 8 | import static uk.org.webcompere.systemstubs.stream.output.Output.fromStream; 9 | 10 | /** 11 | * Common output scenarios, creating an output factory or output. 12 | */ 13 | public class OutputFactories { 14 | 15 | /** 16 | * Construct an output made of multiple others with no dependency on the previous output stream 17 | * @param first the first output to multiplex 18 | * @param others the others 19 | * @return an {@link Output} which multiplexes 20 | */ 21 | public static Output ofMultiple(Output first, Output... others) { 22 | return new MultiplexOutput(first, others); 23 | } 24 | 25 | /** 26 | * Construct an output made of multiple others with no dependency on the previous output stream 27 | * @param first the first output to multiplex 28 | * @param others the others 29 | * @return an {@link Output} which multiplexes 30 | */ 31 | public static OutputFactory ofMultiple(OutputFactory first, 32 | OutputFactory... others) { 33 | return original -> { 34 | Output[] constructed = new Output[others.length]; 35 | for (int i = 0; i < others.length; i++) { 36 | constructed[i] = others[i].apply(original); 37 | } 38 | return new MultiplexOutput(first.apply(original), constructed); 39 | }; 40 | } 41 | 42 | /** 43 | * Construct a multiplexed output made of the provided outputs, adding the original stream on the end. 44 | * @param first the first output to multiplex 45 | * @param others the others 46 | * @return an {@link OutputFactory} which produces a multiplexed output, which includes the previous setting for 47 | * the System.out or System.err allowing a tap alongside the original 48 | */ 49 | public static OutputFactory ofMultiplePlusOriginal(OutputFactory first, 50 | OutputFactory... others) { 51 | return ofMultiple(first, Stream.concat(Arrays.stream(others), Stream.of(Output::fromStream)) 52 | .toArray(OutputFactory[]::new)); 53 | } 54 | 55 | /** 56 | * Construct a multiplexed output made of the provided outputs, adding the original stream on the end. 57 | * @param first the first output to multiplex 58 | * @param others the others 59 | * @return an {@link OutputFactory} which produces a multiplexed output, which includes the previous setting for 60 | * the System.out or System.err allowing a tap alongside the original 61 | */ 62 | public static OutputFactory ofMultiplePlusOriginal(Output first, 63 | Output... others) { 64 | return original -> 65 | new MultiplexOutput(first, Stream.concat(Arrays.stream(others), Stream.of(fromStream(original))) 66 | .toArray(Output[]::new)); 67 | } 68 | 69 | 70 | /** 71 | * Tap an output while still using the original output 72 | * @return an {@link OutputFactory} which performs a tap 73 | */ 74 | public static OutputFactory tapAndOutput() { 75 | return ofMultiplePlusOriginal(new TapStream()); 76 | } 77 | 78 | /** 79 | * Write to file when the output is active, closing it when it's deactivated 80 | * @param file the target file for writing to 81 | */ 82 | public static OutputFactory writeToFile(File file) { 83 | return original -> Output.fromCloseableStream(new FileOutputStream(file)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/OutputFactory.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.OutputStream; 4 | 5 | /** 6 | * Functional interface for creating {@link Output} objects for use as the output 7 | * based on the current system {@link java.io.PrintStream} 8 | * @param the type of stream the {@link Output} will handle 9 | */ 10 | @FunctionalInterface 11 | public interface OutputFactory { 12 | /** 13 | * Current the current input stream, produce an {@link Output} 14 | * @param original the original stream 15 | * @return an output to use for writing 16 | * @throws Exception on error creating the object 17 | */ 18 | Output apply(OutputStream original) throws Exception; 19 | } 20 | -------------------------------------------------------------------------------- /system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/stream/output/TapStream.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.nio.charset.Charset; 5 | 6 | /** 7 | * TapStream is a {@link ByteArrayOutputStream} that satisfies the {@link Output} 8 | * interface too. 9 | */ 10 | public class TapStream extends ByteArrayOutputStream implements Output { 11 | @Override 12 | public String getText() { 13 | return new String(getOutputStream().toByteArray(), Charset.defaultCharset()); 14 | } 15 | 16 | @Override 17 | public TapStream getOutputStream() { 18 | return this; 19 | } 20 | 21 | @Override 22 | public void clear() { 23 | reset(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/MethodUnderTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | interface MethodUnderTest { 4 | void accept( 5 | ThrowingRunnable throwingRunnable 6 | ) throws Exception; 7 | } 8 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/MuteSystemErrTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.PrintStream; 5 | 6 | import org.junit.jupiter.api.DisplayNameGeneration; 7 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 8 | import org.junit.jupiter.api.Nested; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static java.lang.System.*; 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | @DisplayNameGeneration(ReplaceUnderscores.class) 15 | class MuteSystemErrTest { 16 | 17 | @Test 18 | void no_text_is_written_to_System_err_by_statement( 19 | ) throws Exception { 20 | ByteArrayOutputStream captureOutputStream = new ByteArrayOutputStream(); 21 | setErr(new PrintStream(captureOutputStream)); 22 | SystemStubs.muteSystemErr( 23 | () -> err.println("some text") 24 | ); 25 | assertThat(captureOutputStream) 26 | .hasToString(""); 27 | } 28 | 29 | @Nested 30 | class System_err_is_same_as_before 31 | extends RestoreSystemErrChecks 32 | { 33 | System_err_is_same_as_before() { 34 | super(SystemStubs::muteSystemErr); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/MuteSystemOutTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.PrintStream; 5 | 6 | import org.junit.jupiter.api.DisplayNameGeneration; 7 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 8 | import org.junit.jupiter.api.Nested; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static java.lang.System.out; 12 | import static java.lang.System.setOut; 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | @DisplayNameGeneration(ReplaceUnderscores.class) 16 | class MuteSystemOutTest { 17 | 18 | @Test 19 | void no_text_is_written_to_System_out_by_statement( 20 | ) throws Exception { 21 | ByteArrayOutputStream captureOutputStream = new ByteArrayOutputStream(); 22 | setOut(new PrintStream(captureOutputStream)); 23 | SystemStubs.muteSystemOut( 24 | () -> out.println("some text") 25 | ); 26 | assertThat(captureOutputStream) 27 | .hasToString(""); 28 | } 29 | 30 | @Nested 31 | class System_out_is_same_as_before 32 | extends RestoreSystemOutChecks 33 | { 34 | System_out_is_same_as_before() { 35 | super(SystemStubs::muteSystemOut); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/PropertiesFileLoadingTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.Nested; 4 | import org.junit.jupiter.api.Test; 5 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 6 | import uk.org.webcompere.systemstubs.properties.SystemProperties; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | import static uk.org.webcompere.systemstubs.resource.PropertySource.fromResource; 10 | 11 | public class PropertiesFileLoadingTest { 12 | @Nested 13 | class ForEnvironmentVariables { 14 | @Test 15 | void can_load_properties_from_resources() throws Exception { 16 | new EnvironmentVariables() 17 | .set(fromResource("test.properties")) 18 | .execute(() -> { 19 | assertThat(System.getenv()).containsEntry("value1", "foo").containsEntry("value2", "bar"); 20 | assertThat(System.getenv("value1")).isEqualTo("foo"); 21 | assertThat(System.getenv("value2")).isEqualTo("bar"); 22 | }); 23 | } 24 | } 25 | 26 | @Nested 27 | class ForSystemProperties { 28 | @Test 29 | void can_load_properties_from_resources() throws Exception { 30 | new SystemProperties() 31 | .set(fromResource("test.properties")) 32 | .execute(() -> { 33 | assertThat(System.getProperty("value1")).isEqualTo("foo"); 34 | assertThat(System.getProperty("value2")).isEqualTo("bar"); 35 | }); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/RestoreSystemErrChecks.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.io.PrintStream; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 9 | 10 | abstract class RestoreSystemErrChecks { 11 | 12 | private final MethodUnderTest methodUnderTest; 13 | 14 | RestoreSystemErrChecks( 15 | MethodUnderTest methodUnderTest 16 | ) { 17 | this.methodUnderTest = methodUnderTest; 18 | } 19 | 20 | @Test 21 | void after_statement_is_executed( 22 | ) throws Exception { 23 | PrintStream originalErr = System.err; 24 | methodUnderTest.accept( 25 | () -> { 26 | } 27 | ); 28 | assertThat(System.err).isSameAs(originalErr); 29 | } 30 | 31 | @Test 32 | void after_statement_throws_exception() { 33 | PrintStream originalErr = System.err; 34 | assertThatThrownBy(() -> methodUnderTest.accept( 35 | () -> { 36 | throw new Exception("some exception"); 37 | } 38 | )).hasMessage("some exception"); 39 | assertThat(System.err).isSameAs(originalErr); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/RestoreSystemOutChecks.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.io.PrintStream; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 9 | 10 | abstract class RestoreSystemOutChecks { 11 | 12 | private final MethodUnderTest methodUnderTest; 13 | 14 | RestoreSystemOutChecks( 15 | MethodUnderTest methodUnderTest 16 | ) { 17 | this.methodUnderTest = methodUnderTest; 18 | } 19 | 20 | @Test 21 | void after_statement_is_executed( 22 | ) throws Exception { 23 | PrintStream originalOut = System.out; 24 | methodUnderTest.accept( 25 | () -> { 26 | } 27 | ); 28 | assertThat(System.out).isSameAs(originalOut); 29 | } 30 | 31 | @Test 32 | void after_statement_throws_exception() { 33 | PrintStream originalOut = System.out; 34 | assertThatThrownBy(() -> methodUnderTest.accept( 35 | () -> { 36 | throw new Exception("some exception"); 37 | } 38 | )).hasMessage("some exception"); 39 | assertThat(System.out).isSameAs(originalOut); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/RestoreSystemPropertiesTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import java.util.Properties; 4 | import java.util.concurrent.atomic.AtomicReference; 5 | 6 | import org.junit.jupiter.api.DisplayNameGeneration; 7 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 8 | import org.junit.jupiter.api.Nested; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 12 | import static uk.org.webcompere.systemstubs.SystemStubs.restoreSystemProperties; 13 | import static java.lang.System.clearProperty; 14 | import static java.lang.System.getProperty; 15 | import static java.lang.System.setProperty; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | @DisplayNameGeneration(ReplaceUnderscores.class) 19 | class RestoreSystemPropertiesTest { 20 | @Test 21 | void statement_is_executed( 22 | ) throws Exception { 23 | ThrowingRunnableMock statementMock = new ThrowingRunnableMock(); 24 | 25 | restoreSystemProperties( 26 | statementMock 27 | ); 28 | 29 | assertThat(statementMock.hasBeenEvaluated).isTrue(); 30 | } 31 | 32 | @Nested 33 | class properties_have_the_same_values_as_before { 34 | @Test 35 | void after_statement_is_executed( 36 | ) throws Exception { 37 | setProperty("some property", "some value"); 38 | setProperty("another property", "some value"); 39 | 40 | restoreSystemProperties( 41 | () -> { 42 | clearProperty("some property"); 43 | setProperty("another property", "another value"); 44 | } 45 | ); 46 | 47 | assertThat(getProperty("some property")) 48 | .isEqualTo("some value"); 49 | assertThat(getProperty("another property")) 50 | .isEqualTo("some value"); 51 | } 52 | 53 | @Test 54 | void after_statement_throws_exception( 55 | ) { 56 | setProperty("some property", "some value"); 57 | setProperty("another property", "some value"); 58 | 59 | assertThatThrownBy(() -> 60 | restoreSystemProperties( 61 | () -> { 62 | clearProperty("some property"); 63 | setProperty("another property", "another value"); 64 | throw new RuntimeException(); 65 | } 66 | )).isInstanceOf(RuntimeException.class); 67 | 68 | assertThat(getProperty("some property")) 69 | .isEqualTo("some value"); 70 | assertThat(getProperty("another property")) 71 | .isEqualTo("some value"); 72 | } 73 | } 74 | 75 | @Nested 76 | class property_that_does_not_exist_before_the_statement_is_executed { 77 | @Test 78 | void does_not_exist_afterwards( 79 | ) throws Exception { 80 | clearProperty("some property"); 81 | 82 | restoreSystemProperties( 83 | () -> setProperty("some property", "some value") 84 | ); 85 | 86 | assertThat(getProperty("some property")) 87 | .isNull(); 88 | } 89 | 90 | @Test 91 | void does_not_exist_after_statement_throws_exception( 92 | ) { 93 | clearProperty("some property"); 94 | 95 | assertThatThrownBy(() -> 96 | restoreSystemProperties( 97 | () -> { 98 | setProperty("some property", "some value"); 99 | throw new RuntimeException(); 100 | } 101 | ) 102 | ).isInstanceOf(RuntimeException.class); 103 | 104 | assertThat(getProperty("some property")) 105 | .isNull(); 106 | } 107 | } 108 | 109 | @Test 110 | void at_start_of_the_statement_execution_properties_are_equal_to_the_original_properties( 111 | ) throws Exception { 112 | AtomicReference propertiesAtStartOfExecution 113 | = new AtomicReference<>(); 114 | //ensure at least one property is set 115 | setProperty("some property", "some value"); 116 | Properties originalProperties = System.getProperties(); 117 | 118 | restoreSystemProperties( 119 | () -> propertiesAtStartOfExecution.set(System.getProperties()) 120 | ); 121 | 122 | assertThat(propertiesAtStartOfExecution.get()) 123 | .isEqualTo(originalProperties); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/TapSystemErrAndOutTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | import uk.org.webcompere.systemstubs.stream.SystemErrAndOut; 8 | import uk.org.webcompere.systemstubs.stream.output.TapStream; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 12 | import static uk.org.webcompere.systemstubs.SystemStubs.*; 13 | 14 | @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) 15 | public class TapSystemErrAndOutTest { 16 | 17 | @Test 18 | void application_writes_text_to_System_err_and_out() throws Exception { 19 | String text = tapSystemErrAndOut(() -> { 20 | System.err.print("text from err"); 21 | System.out.print("text from out"); 22 | }); 23 | assertThat(text).isEqualTo("text from errtext from out"); 24 | } 25 | 26 | @Test 27 | void construct_system_err_and_out_tap() throws Exception { 28 | SystemErrAndOut stream = withSystemErrAndOut(new TapStream()); 29 | stream.execute(() -> { 30 | System.err.println("text from err"); 31 | System.out.println("text from out"); 32 | }); 33 | assertThat(stream.getLines()) 34 | .containsExactly("text from err","text from out"); 35 | } 36 | 37 | @Test 38 | void construct_system_err_and_out_default_tap() throws Exception { 39 | SystemErrAndOut stream = withTapSystemErrAndOut(); 40 | stream.execute(() -> { 41 | System.err.println("text from err"); 42 | System.out.println("text from out"); 43 | }); 44 | assertThat(stream.getLines()) 45 | .containsExactly("text from err","text from out"); 46 | } 47 | 48 | @Nested 49 | class nothing_written_to_system_err_or_out { 50 | @Test 51 | void when_writes_to_out_is_error() { 52 | assertThatThrownBy(() -> { 53 | assertNothingWrittenToSystemErrOrOut(() -> { 54 | System.out.print("oops"); 55 | }); 56 | }).isInstanceOf(AssertionError.class); 57 | 58 | } 59 | 60 | @Test 61 | void when_writes_to_err_is_error() { 62 | assertThatThrownBy(() -> { 63 | assertNothingWrittenToSystemErrOrOut(() -> { 64 | System.err.print("oops"); 65 | }); 66 | }).isInstanceOf(AssertionError.class); 67 | } 68 | 69 | @Test 70 | void when_does_nothing_is_ok() throws Exception { 71 | assertNothingWrittenToSystemErrOrOut(() -> { 72 | 73 | }); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/TapSystemErrNormalizedTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static java.lang.System.err; 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | @DisplayNameGeneration(ReplaceUnderscores.class) 12 | class TapSystemErrNormalizedTest { 13 | 14 | @Test 15 | void taps_text_that_is_written_to_System_err_by_statement_has_only_slash_n_for_new_line( 16 | ) throws Exception { 17 | String textWrittenToSystemErr = SystemStubs.tapSystemErrNormalized( 18 | () -> err.println("some text") 19 | ); 20 | 21 | assertThat(textWrittenToSystemErr) 22 | .isEqualTo("some text\n"); 23 | } 24 | 25 | @Test 26 | void tapped_text_is_empty_when_statement_does_not_write_to_System_err( 27 | ) throws Exception { 28 | String textWrittenToSystemErr = SystemStubs.tapSystemErrNormalized( 29 | () -> {} 30 | ); 31 | 32 | assertThat(textWrittenToSystemErr) 33 | .isEqualTo(""); 34 | } 35 | 36 | @Nested 37 | class System_err_is_same_as_before 38 | extends RestoreSystemErrChecks 39 | { 40 | System_err_is_same_as_before() { 41 | super(SystemStubs::tapSystemErrNormalized); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/TapSystemErrTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static uk.org.webcompere.systemstubs.SystemStubs.tapSystemErr; 9 | import static java.lang.System.err; 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @DisplayNameGeneration(ReplaceUnderscores.class) 13 | class TapSystemErrTest { 14 | 15 | @Test 16 | void taps_text_that_is_written_to_System_err_by_statement( 17 | ) throws Exception { 18 | String textWrittenToSystemErr = tapSystemErr( 19 | () -> err.print("some text") 20 | ); 21 | 22 | assertThat(textWrittenToSystemErr) 23 | .isEqualTo("some text"); 24 | } 25 | 26 | @Test 27 | void tapped_text_is_empty_when_statement_does_not_write_to_System_err( 28 | ) throws Exception { 29 | String textWrittenToSystemErr = tapSystemErr( 30 | () -> {} 31 | ); 32 | 33 | assertThat(textWrittenToSystemErr) 34 | .isEqualTo(""); 35 | } 36 | 37 | @Nested 38 | class System_err_is_same_as_before 39 | extends RestoreSystemErrChecks 40 | { 41 | System_err_is_same_as_before() { 42 | super(SystemStubs::tapSystemErr); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/TapSystemOutNormalizedTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static uk.org.webcompere.systemstubs.SystemStubs.tapSystemOutNormalized; 9 | import static java.lang.System.out; 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @DisplayNameGeneration(ReplaceUnderscores.class) 13 | class TapSystemOutNormalizedTest { 14 | 15 | @Test 16 | void taps_text_that_is_written_to_System_out_by_statement_has_only_slash_n_for_new_line( 17 | ) throws Exception { 18 | String textWrittenToSystemOut = tapSystemOutNormalized( 19 | () -> out.println("some text") 20 | ); 21 | 22 | assertThat(textWrittenToSystemOut) 23 | .isEqualTo("some text\n"); 24 | } 25 | 26 | @Test 27 | void tapped_text_is_empty_when_statement_does_not_write_to_System_out( 28 | ) throws Exception { 29 | String textWrittenToSystemOut = tapSystemOutNormalized( 30 | () -> {} 31 | ); 32 | 33 | assertThat(textWrittenToSystemOut) 34 | .isEqualTo(""); 35 | } 36 | 37 | @Nested 38 | class System_out_is_same_as_before 39 | extends RestoreSystemOutChecks 40 | { 41 | System_out_is_same_as_before() { 42 | super(SystemStubs::tapSystemOutNormalized); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/TapSystemOutTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static uk.org.webcompere.systemstubs.SystemStubs.tapSystemOut; 9 | import static java.lang.System.*; 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @DisplayNameGeneration(ReplaceUnderscores.class) 13 | class TapSystemOutTest { 14 | 15 | @Test 16 | void taps_text_that_is_written_to_System_out_by_statement( 17 | ) throws Exception { 18 | String textWrittenToSystemOut = tapSystemOut( 19 | () -> out.print("some text") 20 | ); 21 | 22 | assertThat(textWrittenToSystemOut) 23 | .isEqualTo("some text"); 24 | } 25 | 26 | @Test 27 | void tapped_text_is_empty_when_statement_does_not_write_to_System_out( 28 | ) throws Exception { 29 | String textWrittenToSystemOut = tapSystemOut( 30 | () -> {} 31 | ); 32 | 33 | assertThat(textWrittenToSystemOut) 34 | .isEqualTo(""); 35 | } 36 | 37 | @Nested 38 | class System_out_is_same_as_before 39 | extends RestoreSystemOutChecks 40 | { 41 | System_out_is_same_as_before() { 42 | super(SystemStubs::tapSystemOut); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/ThrowingRunnableMock.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | class ThrowingRunnableMock implements ThrowingRunnable { 4 | boolean hasBeenEvaluated = false; 5 | 6 | @Override 7 | public void run() throws Exception { 8 | hasBeenEvaluated = true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/WithSecurityManagerTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs; 2 | 3 | import org.junit.jupiter.api.DisplayNameGeneration; 4 | import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static java.lang.System.getSecurityManager; 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 11 | 12 | @DisplayNameGeneration(ReplaceUnderscores.class) 13 | class WithSecurityManagerTest { 14 | private static final SecurityManager MANAGER = new SecurityManagerMock(); 15 | 16 | @Test 17 | void specified_security_manager_is_present_while_statement_is_executed( 18 | ) throws Exception { 19 | SystemStubs.withSecurityManager( 20 | MANAGER, 21 | () -> assertThat(getSecurityManager()).isSameAs(MANAGER) 22 | ); 23 | } 24 | 25 | @Test 26 | void statement_is_executed() throws Exception { 27 | ThrowingRunnableMock statementMock = new ThrowingRunnableMock(); 28 | 29 | SystemStubs.withSecurityManager( 30 | MANAGER, 31 | statementMock 32 | ); 33 | 34 | assertThat(statementMock.hasBeenEvaluated).isTrue(); 35 | } 36 | 37 | @Nested 38 | class the_security_manager_is_the_same_as_before { 39 | @Test 40 | void after_statement_is_executed( 41 | ) throws Exception { 42 | SecurityManager originalManager = getSecurityManager(); 43 | 44 | SystemStubs.withSecurityManager( 45 | MANAGER, 46 | () -> { 47 | } 48 | ); 49 | 50 | assertThat(getSecurityManager()).isSameAs(originalManager); 51 | } 52 | 53 | @Test 54 | void after_statement_throws_exception() { 55 | SecurityManager originalSecurityManager = getSecurityManager(); 56 | 57 | assertThatThrownBy(() -> 58 | SystemStubs.withSecurityManager( 59 | MANAGER, 60 | () -> { 61 | throw new RuntimeException(); 62 | } 63 | )).isInstanceOf(RuntimeException.class); 64 | 65 | assertThat(getSecurityManager()).isSameAs(originalSecurityManager); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/resource/PropertySourceTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import uk.org.webcompere.systemstubs.stream.input.LinesAltStream; 5 | 6 | import java.io.File; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.Properties; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static uk.org.webcompere.systemstubs.resource.PropertySource.fromFile; 13 | import static uk.org.webcompere.systemstubs.resource.PropertySource.fromResource; 14 | 15 | class PropertySourceTest { 16 | // this is a disgusting way to initialize a map - sorry! Java's `Map.of` and Guava's `ImmutableMap.of` 17 | // are much better! 18 | private static final Map EXPECTED_TEST_PROPERTIES = new HashMap() {{ 19 | put("value1", "foo"); 20 | put("value2", "bar"); 21 | }}; 22 | 23 | 24 | @Test 25 | void fromFileByFilename() { 26 | Properties props = fromFile("src/test/resources/test.properties"); 27 | assertThat(props).containsAllEntriesOf(EXPECTED_TEST_PROPERTIES); 28 | } 29 | 30 | @Test 31 | void fromFileByFile() { 32 | Properties props = fromFile(new File("src/test/resources/test.properties")); 33 | assertThat(props).containsAllEntriesOf(EXPECTED_TEST_PROPERTIES); 34 | } 35 | 36 | @Test 37 | void fromFileByPath() { 38 | Properties props = fromFile(new File("src/test/resources/test.properties").toPath()); 39 | assertThat(props).containsAllEntriesOf(EXPECTED_TEST_PROPERTIES); 40 | } 41 | 42 | @Test 43 | void fromResources() { 44 | Properties props = fromResource("test.properties"); 45 | assertThat(props).containsAllEntriesOf(EXPECTED_TEST_PROPERTIES); 46 | } 47 | 48 | @Test 49 | void fromLines() { 50 | Properties props = PropertySource.fromInputStream(new LinesAltStream("value1=foo", "value2=bar")); 51 | assertThat(props).containsAllEntriesOf(EXPECTED_TEST_PROPERTIES); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/resource/ResourcesTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import org.mockito.Mock; 6 | import org.mockito.junit.jupiter.MockitoExtension; 7 | 8 | import java.util.concurrent.Callable; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 12 | import static org.mockito.BDDMockito.*; 13 | import static org.mockito.Mockito.never; 14 | import static uk.org.webcompere.systemstubs.resource.Resources.execute; 15 | import static uk.org.webcompere.systemstubs.resource.Resources.with; 16 | 17 | @ExtendWith(MockitoExtension.class) 18 | class ResourcesTest { 19 | @Mock 20 | private TestResource firstResource; 21 | 22 | @Mock 23 | private TestResource secondResource; 24 | 25 | @Mock 26 | private TestResource thirdResource; 27 | 28 | @Mock 29 | private Callable callable; 30 | 31 | @Test 32 | void canRunRunnableWithNoResources() throws Exception { 33 | execute(callable); 34 | 35 | then(callable).should().call(); 36 | } 37 | 38 | @Test 39 | void canRunRunnableWithOneResource() throws Exception { 40 | execute(callable, firstResource); 41 | 42 | then(callable).should().call(); 43 | then(firstResource).should().setup(); 44 | then(firstResource).should().teardown(); 45 | } 46 | 47 | @Test 48 | void runnablesReturnIsReturned() throws Exception { 49 | given(callable.call()).willReturn("bar"); 50 | 51 | String result = execute(callable, firstResource); 52 | assertThat(result).isEqualTo("bar"); 53 | } 54 | 55 | @Test 56 | void canRunRunnableWithTwoResources() throws Exception { 57 | execute(callable, firstResource, secondResource); 58 | 59 | then(callable).should().call(); 60 | then(firstResource).should().setup(); 61 | then(firstResource).should().teardown(); 62 | 63 | then(secondResource).should().setup(); 64 | then(secondResource).should().teardown(); 65 | } 66 | 67 | @Test 68 | void canRunRunnableWithThreeResources() throws Exception { 69 | execute(callable, firstResource, secondResource, thirdResource); 70 | 71 | then(callable).should().call(); 72 | then(firstResource).should().setup(); 73 | then(firstResource).should().teardown(); 74 | 75 | then(secondResource).should().setup(); 76 | then(secondResource).should().teardown(); 77 | 78 | then(thirdResource).should().setup(); 79 | then(thirdResource).should().teardown(); 80 | } 81 | 82 | @Test 83 | void canRunRunnableWithThreeResourcesUsingWith() throws Exception { 84 | with(firstResource, secondResource, thirdResource) 85 | .execute(callable); 86 | 87 | then(callable).should().call(); 88 | then(firstResource).should().setup(); 89 | then(firstResource).should().teardown(); 90 | 91 | then(secondResource).should().setup(); 92 | then(secondResource).should().teardown(); 93 | 94 | then(thirdResource).should().setup(); 95 | then(thirdResource).should().teardown(); 96 | } 97 | 98 | @Test 99 | void whenSecondResourceFailsToStartThirdIsNeverTouchedButSecondIsCleaned() throws Exception { 100 | willThrow(new RuntimeException("boom")).given(secondResource).setup(); 101 | 102 | assertThatThrownBy(() -> execute(callable, firstResource, secondResource, thirdResource)) 103 | .hasMessage("boom"); 104 | 105 | then(callable).should(never()).call(); 106 | then(firstResource).should().setup(); 107 | then(firstResource).should().teardown(); 108 | 109 | then(secondResource).should().setup(); 110 | then(secondResource).should().teardown(); 111 | 112 | then(thirdResource).should(never()).setup(); 113 | then(thirdResource).should(never()).teardown(); 114 | } 115 | 116 | @Test 117 | void whenSecondResourceFailsToCleanThenThirdIsStillCleaned() throws Exception { 118 | willThrow(new RuntimeException("boom")).given(secondResource).teardown(); 119 | 120 | assertThatThrownBy(() -> execute(callable, firstResource, secondResource, thirdResource)) 121 | .hasMessage("boom"); 122 | 123 | then(callable).should().call(); 124 | then(firstResource).should().setup(); 125 | then(firstResource).should().teardown(); 126 | 127 | then(secondResource).should().setup(); 128 | then(secondResource).should().teardown(); 129 | 130 | then(thirdResource).should().setup(); 131 | then(thirdResource).should().teardown(); 132 | } 133 | 134 | @Test 135 | void whenRunnableFailsTheErrorIsFromTheRunnable() throws Exception { 136 | willThrow(new RuntimeException("boom")).given(callable).call(); 137 | 138 | assertThatThrownBy(() -> execute(callable, firstResource, secondResource, thirdResource)) 139 | .hasMessage("boom"); 140 | 141 | then(callable).should().call(); 142 | then(firstResource).should().setup(); 143 | then(firstResource).should().teardown(); 144 | 145 | then(secondResource).should().setup(); 146 | then(secondResource).should().teardown(); 147 | 148 | then(thirdResource).should().setup(); 149 | then(thirdResource).should().teardown(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/resource/SingularTestResourceTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.resource; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import org.mockito.Answers; 6 | import org.mockito.Mock; 7 | import org.mockito.junit.jupiter.MockitoExtension; 8 | 9 | import static org.mockito.BDDMockito.then; 10 | import static org.mockito.Mockito.never; 11 | import static org.mockito.Mockito.times; 12 | 13 | 14 | @ExtendWith(MockitoExtension.class) 15 | class SingularTestResourceTest { 16 | @Mock(answer = Answers.CALLS_REAL_METHODS) 17 | private SingularTestResource singularTestResource; 18 | 19 | @Test 20 | void oneCallToSetupDoesSetup() throws Exception { 21 | singularTestResource.setup(); 22 | 23 | then(singularTestResource).should().doSetup(); 24 | } 25 | 26 | @Test 27 | void twoCallsToSetupDoesOnlyOneSetup() throws Exception { 28 | singularTestResource.setup(); 29 | singularTestResource.setup(); 30 | 31 | then(singularTestResource).should().doSetup(); 32 | } 33 | 34 | @Test 35 | void oneCallToTeardownDoesNothing() throws Exception { 36 | singularTestResource.teardown(); 37 | 38 | then(singularTestResource).should(never()).doTeardown(); 39 | } 40 | 41 | @Test 42 | void aTeardownHappensAfterASetup() throws Exception { 43 | singularTestResource.setup(); 44 | singularTestResource.teardown(); 45 | 46 | then(singularTestResource).should().doSetup(); 47 | then(singularTestResource).should().doTeardown(); 48 | } 49 | 50 | @Test 51 | void setupAndTearDownIsRepeatable() throws Exception { 52 | singularTestResource.setup(); 53 | singularTestResource.teardown(); 54 | 55 | then(singularTestResource).should().doSetup(); 56 | then(singularTestResource).should().doTeardown(); 57 | 58 | singularTestResource.setup(); 59 | singularTestResource.teardown(); 60 | 61 | then(singularTestResource).should(times(2)).doSetup(); 62 | then(singularTestResource).should(times(2)).doTeardown(); 63 | } 64 | 65 | @Test 66 | void aPreEmptiveTeardownShouldNotPreventASetupTeardown() throws Exception { 67 | singularTestResource.teardown(); 68 | 69 | singularTestResource.setup(); 70 | singularTestResource.teardown(); 71 | 72 | then(singularTestResource).should().doSetup(); 73 | then(singularTestResource).should().doTeardown(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/security/SystemExitTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.security; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | class SystemExitTest { 11 | 12 | private SystemExit systemExit = new SystemExit(); 13 | 14 | @Test 15 | void whenNoExitThenNoExitCode() { 16 | assertThat(systemExit.getExitCode()).isNull(); 17 | } 18 | 19 | @Test 20 | void whenOneExitThenExitCodeProvided() throws Exception { 21 | systemExit.execute(() -> { 22 | System.exit(123); 23 | }); 24 | 25 | // can also be seen outside of "execute" 26 | assertThat(systemExit.getExitCode()).isEqualTo(123); 27 | } 28 | 29 | @Test 30 | void whenTwoExitsThenSecondDoesntApplyAndCodeTerminates() throws Exception { 31 | List list = new ArrayList<>(); 32 | systemExit.execute(() -> { 33 | System.exit(123); 34 | System.exit(234); 35 | list.add("a"); 36 | }); 37 | 38 | assertThat(systemExit.getExitCode()).isEqualTo(123); 39 | assertThat(list.isEmpty()); 40 | } 41 | 42 | @Test 43 | void whenTwoActivationsThenEachIsUnique() throws Exception { 44 | systemExit.execute(() -> { 45 | System.exit(123); 46 | assertThat(systemExit.getExitCode()).isEqualTo(123); 47 | }); 48 | 49 | assertThat(systemExit.getExitCode()).isEqualTo(123); 50 | 51 | systemExit.execute(() -> { 52 | System.exit(234); 53 | assertThat(systemExit.getExitCode()).isEqualTo(234); 54 | }); 55 | 56 | assertThat(systemExit.getExitCode()).isEqualTo(234); 57 | } 58 | 59 | @Test 60 | void localSystemExitObjectExampleForIgnore() throws Exception { 61 | new SystemExit() 62 | .execute(() -> { 63 | System.exit(0); 64 | }); 65 | } 66 | 67 | @Test 68 | void localSystemExitObjectExampleForCapture() throws Exception { 69 | SystemExit exit = new SystemExit(); 70 | exit.execute(() -> { 71 | System.exit(0); 72 | }); 73 | 74 | assertThat(exit.getExitCode()).isEqualTo(0); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/SystemErrAndOutTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | class SystemErrAndOutTest { 8 | 9 | @Test 10 | void canTapSystemErrorWithErrAndOut() throws Exception { 11 | SystemErrAndOut errAndOut = new SystemErrAndOut(); 12 | errAndOut.execute(() -> { 13 | System.err.print("hello"); 14 | }); 15 | assertThat(errAndOut.getText()).isEqualTo("hello"); 16 | } 17 | 18 | @Test 19 | void canTapSystemOutWithErrAndOut() throws Exception { 20 | SystemErrAndOut errAndOut = new SystemErrAndOut(); 21 | errAndOut.execute(() -> { 22 | System.out.print("hello out"); 23 | }); 24 | assertThat(errAndOut.getText()).isEqualTo("hello out"); 25 | } 26 | 27 | @Test 28 | void canClearTheOutputWhileStillInUseAndReuse() throws Exception { 29 | SystemErrAndOut errAndOut = new SystemErrAndOut(); 30 | errAndOut.execute(() -> { 31 | System.out.print("hello out"); 32 | assertThat(errAndOut.getText()).isEqualTo("hello out"); 33 | 34 | errAndOut.clear(); 35 | 36 | System.out.print("hello again"); 37 | assertThat(errAndOut.getText()).isEqualTo("hello again"); 38 | }); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/SystemInTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import uk.org.webcompere.systemstubs.stream.input.LinesAltStream; 5 | import uk.org.webcompere.systemstubs.stream.input.TextAltStream; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.util.List; 10 | import java.util.Scanner; 11 | import java.util.UUID; 12 | import java.util.stream.Stream; 13 | 14 | import static java.util.stream.Collectors.toList; 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 17 | import static org.mockito.BDDMockito.then; 18 | import static org.mockito.Mockito.spy; 19 | 20 | class SystemInTest { 21 | private List linesRead; 22 | 23 | @Test 24 | void canConstructWithDefaultConstructorWithNoData() throws Exception { 25 | new SystemIn() 26 | .execute(() -> assertThat(System.in.read()).isEqualTo(-1)); 27 | } 28 | 29 | @Test 30 | void canReadASingleLineOfTextFromSystemInA() throws Exception { 31 | new SystemIn("Hello world") 32 | .execute(() -> linesRead = readLinesFromSystemIn(1)); 33 | 34 | assertThat(linesRead).containsExactly("Hello world"); 35 | } 36 | 37 | @Test 38 | void canReadLinesOfTextFromSystemIn() throws Exception { 39 | new SystemIn("Hello world", "goodbye world") 40 | .execute(() -> linesRead = readLinesFromSystemIn(1)); 41 | 42 | assertThat(linesRead).containsExactly("Hello world"); 43 | } 44 | 45 | @Test 46 | void canReadTwoLinesOfTextFromSystemIn() throws Exception { 47 | new SystemIn("Hello world", "goodbye world") 48 | .execute(() -> linesRead = readLinesFromSystemIn(2)); 49 | 50 | assertThat(linesRead).containsExactly("Hello world", "goodbye world"); 51 | } 52 | 53 | @Test 54 | void willHaveNoExceptionWhenRunsOutOfTextAtLineBreak() throws Exception { 55 | new SystemIn("Hello world", "goodbye world") 56 | .andExceptionThrownOnInputEnd(new IOException("Ran out of text")) 57 | .execute(() -> readLinesFromSystemIn(2)); 58 | } 59 | 60 | @Test 61 | void willHaveExceptionWhenRunsOutOfTextAfterLineBreak() throws Exception { 62 | new SystemIn("Hello world", "goodbye world") 63 | .andExceptionThrownOnInputEnd(new IOException("Ran out of text")) 64 | .execute(() -> { 65 | assertThatThrownBy(() -> readLinesFromSystemIn(3)) 66 | .hasMessage("No line found"); 67 | }); 68 | } 69 | 70 | @Test 71 | void willAvoidExceptionByNotRunningOutOfText() throws Exception { 72 | new SystemIn("Hello world", "goodbye world") 73 | .andExceptionThrownOnInputEnd(new IOException("Ran out of text")) 74 | .execute(() -> { 75 | // reading short of the full text results in no exception 76 | readLinesFromSystemIn(2); 77 | }); 78 | } 79 | 80 | @Test 81 | void canReadInfiniteStreamOfTextFromSystemIn() throws Exception { 82 | new SystemIn(new LinesAltStream(Stream.generate(() -> UUID.randomUUID().toString()))) 83 | .execute(() -> { 84 | // can read up to an arbitrary limit 85 | assertThat(readLinesFromSystemIn(120)).hasSize(120); 86 | }); 87 | } 88 | 89 | @Test 90 | void canSetInputStreamWhileSystemInIsActive() throws Exception { 91 | SystemIn in = new SystemIn(); 92 | in.execute(() -> { 93 | in.setInputStream(new TextAltStream("foo")); 94 | Scanner scanner = new Scanner(System.in); 95 | assertThat(scanner.nextLine()).isEqualTo("foo"); 96 | }); 97 | } 98 | 99 | @Test 100 | void closesStreamOnTeardown() throws Exception { 101 | InputStream stream = spy(new TextAltStream("foo")); 102 | new SystemIn(stream) 103 | .execute(() -> { 104 | Scanner scanner = new Scanner(System.in); 105 | assertThat(scanner.nextLine()).isEqualTo("foo"); 106 | }); 107 | 108 | then(stream).should().close(); 109 | } 110 | 111 | /** 112 | * Read a certain number of lines from System.in 113 | * @param count the count to read 114 | * @return the list of lines read 115 | */ 116 | private static List readLinesFromSystemIn(int count) { 117 | Scanner scanner = new Scanner(System.in); 118 | return Stream.generate(scanner::nextLine) 119 | .limit(count) 120 | .collect(toList()); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/SystemStreamBaseTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import uk.org.webcompere.systemstubs.stream.output.NoopStream; 5 | 6 | import static org.assertj.core.api.Assertions.assertThat; 7 | 8 | class SystemStreamBaseTest { 9 | private SystemOut systemOut = new SystemOut(); 10 | private SystemOut noopOut = new SystemOut(new NoopStream()); 11 | 12 | @Test 13 | void canReadText() throws Exception { 14 | systemOut.execute(() -> System.out.println("Hello")); 15 | 16 | assertThat(systemOut.getText()).startsWith("Hello"); 17 | } 18 | 19 | @Test 20 | void canReadLines() throws Exception { 21 | systemOut.execute(() -> { 22 | System.out.println("foo"); 23 | System.out.println("bar"); 24 | }); 25 | 26 | assertThat(systemOut.getLines()).containsExactly("foo", "bar"); 27 | } 28 | 29 | @Test 30 | void canReuseSystemOutputAsItClearsInBetween() throws Exception { 31 | systemOut.execute(() -> System.out.println("Hello")); 32 | 33 | systemOut.execute(() -> System.out.println("World")); 34 | 35 | assertThat(systemOut.getLinesNormalized()) 36 | .isEqualTo("World\n"); 37 | } 38 | 39 | @Test 40 | void canClearSystemOut() throws Exception { 41 | systemOut.execute(() -> System.out.println("Hello")); 42 | 43 | systemOut.clear(); 44 | 45 | assertThat(systemOut.getText()) 46 | .isEmpty(); 47 | } 48 | 49 | @Test 50 | void noOpStreamHasNoText() throws Exception { 51 | noopOut.execute(() -> System.out.println("Anyone home?")); 52 | 53 | assertThat(noopOut.getText()).isEmpty(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/input/TextAltStreamTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Scanner; 6 | 7 | import static java.lang.System.lineSeparator; 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | class TextAltStreamTest { 11 | @Test 12 | void textCanBeReadFromStream() { 13 | TextAltStream stream = new TextAltStream("Hello" + lineSeparator() + "World" + lineSeparator()); 14 | Scanner scanner = new Scanner(stream); 15 | assertThat(scanner.nextLine()).isEqualTo("Hello"); 16 | assertThat(scanner.nextLine()).isEqualTo("World"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/input/ThrowAtEndStreamTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.input; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.io.IOException; 6 | import java.util.Scanner; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 10 | 11 | class ThrowAtEndStreamTest { 12 | private AltInputStream wrapped = new LinesAltStream("first", "second"); 13 | private AltInputStream emptyWrapped = new LinesAltStream(); 14 | 15 | @Test 16 | void wrappedStreamYieldsLines() { 17 | ThrowAtEndStream throwAtEndStream = new ThrowAtEndStream(wrapped, new IOException("boom")); 18 | Scanner scanner = new Scanner(throwAtEndStream); 19 | assertThat(scanner.nextLine()).isEqualTo("first"); 20 | assertThat(scanner.nextLine()).isEqualTo("second"); 21 | 22 | // scanner has its own exception but the stream throws the canned exception 23 | assertThatThrownBy(scanner::nextLine).hasMessage("No line found"); 24 | assertThatThrownBy(throwAtEndStream::read).hasMessage("boom"); 25 | } 26 | 27 | @Test 28 | void emptyStreamYieldsNoLines() { 29 | ThrowAtEndStream throwAtEndStream = new ThrowAtEndStream(emptyWrapped, new IOException("boom")); 30 | Scanner scanner = new Scanner(throwAtEndStream); 31 | 32 | assertThatThrownBy(scanner::nextLine).hasMessage("No line found"); 33 | } 34 | 35 | @Test 36 | void streamCannotReadWithNullBuffer() { 37 | ThrowAtEndStream stream = new ThrowAtEndStream(wrapped, new IOException()); 38 | assertThatThrownBy(() -> stream.read(null, 0, 128)) 39 | .isInstanceOf(NullPointerException.class); 40 | } 41 | 42 | @Test 43 | void streamCannotReadWithBufferTooShort() { 44 | ThrowAtEndStream stream = new ThrowAtEndStream(wrapped, new IOException()); 45 | assertThatThrownBy(() -> stream.read(new byte[12], 0, 128)) 46 | .isInstanceOf(IndexOutOfBoundsException.class); 47 | } 48 | 49 | @Test 50 | void returnsNothingWhenLengthIsZero() throws Exception { 51 | ThrowAtEndStream stream = new ThrowAtEndStream(wrapped, new IOException()); 52 | assertThat(stream.read(new byte[12], 0, 0)).isZero(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/output/MultiplexOutputTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.io.PrintStream; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static uk.org.webcompere.systemstubs.stream.SystemStreamBase.wrap; 9 | 10 | class MultiplexOutputTest { 11 | @Test 12 | void multiplexOneStream_thenCanWrite() throws Exception { 13 | TapStream tapStream = new TapStream(); 14 | MultiplexOutput multiplexOutput = new MultiplexOutput(tapStream); 15 | 16 | PrintStream printer = wrap(multiplexOutput); 17 | printer.println("Foo"); 18 | 19 | assertThat(multiplexOutput.getLines()).containsExactly("Foo"); 20 | assertThat(tapStream.getLines()).containsExactly("Foo"); 21 | } 22 | 23 | @Test 24 | void multiplexTwoStream_thenCanWriteToBoth() throws Exception { 25 | TapStream tapStream1 = new TapStream(); 26 | TapStream tapStream2 = new TapStream(); 27 | MultiplexOutput multiplexOutput = new MultiplexOutput(tapStream1, tapStream2); 28 | 29 | PrintStream printer = wrap(multiplexOutput); 30 | printer.println("Foo"); 31 | 32 | assertThat(multiplexOutput.getLines()).containsExactly("Foo"); 33 | assertThat(tapStream1.getLines()).containsExactly("Foo"); 34 | assertThat(tapStream2.getLines()).containsExactly("Foo"); 35 | } 36 | 37 | @Test 38 | void multiplexTwoStream_thenCanClearBoth() throws Exception { 39 | TapStream tapStream1 = new TapStream(); 40 | TapStream tapStream2 = new TapStream(); 41 | MultiplexOutput multiplexOutput = new MultiplexOutput(tapStream1, tapStream2); 42 | 43 | PrintStream printer = wrap(multiplexOutput); 44 | printer.println("Foo"); 45 | 46 | multiplexOutput.clear(); 47 | 48 | assertThat(tapStream1.getText()).isEmpty(); 49 | assertThat(tapStream2.getText()).isEmpty(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/java/uk/org/webcompere/systemstubs/stream/output/OutputFactoriesTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.stream.output; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.io.TempDir; 5 | import uk.org.webcompere.systemstubs.stream.SystemOut; 6 | 7 | import java.io.File; 8 | import java.io.PrintStream; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static uk.org.webcompere.systemstubs.stream.SystemStreamBase.wrap; 12 | import static uk.org.webcompere.systemstubs.stream.output.OutputFactories.*; 13 | 14 | /** 15 | * Also examples for how to both tap and allow System output 16 | */ 17 | class OutputFactoriesTest { 18 | @Test 19 | void whenTapAndConsoleThenTapWorks() throws Exception { 20 | SystemOut systemOut = new SystemOut(tapAndOutput()); 21 | systemOut.execute(() -> System.out.println("I write to the console and the tap")); 22 | assertThat(systemOut.getLines()).containsExactly("I write to the console and the tap"); 23 | } 24 | 25 | @Test 26 | void whenTapAndConsoleThenConsoleWorks() throws Exception { 27 | SystemOut pretendToBeConsole = new SystemOut(); 28 | pretendToBeConsole.execute(() -> { 29 | // here we're pretending that the outer SystemOut is the ACTUAL system out 30 | // it's SystemOut all the way down! 31 | SystemOut systemOut = new SystemOut(tapAndOutput()); 32 | systemOut.execute(() -> System.out.println("I write to the console and the tap")); 33 | assertThat(systemOut.getLines()).containsExactly("I write to the console and the tap"); 34 | }); 35 | 36 | assertThat(pretendToBeConsole.getLines()).containsExactly("I write to the console and the tap"); 37 | } 38 | 39 | @Test 40 | void canDirectSystemOutToFile(@TempDir File tempDir) throws Exception { 41 | File target = new File(tempDir, "file"); 42 | new SystemOut(writeToFile(target)) 43 | .execute(() -> { 44 | System.out.println("This is going into a file"); 45 | }); 46 | 47 | assertThat(target).hasContent("This is going into a file" + System.lineSeparator()); 48 | } 49 | 50 | @Test 51 | void canDirectSystemOutToFileAndConsole(@TempDir File tempDir) throws Exception { 52 | File target = new File(tempDir, "file"); 53 | new SystemOut(ofMultiplePlusOriginal(writeToFile(target))) 54 | .execute(() -> { 55 | System.out.println("This is going into a file"); 56 | }); 57 | 58 | assertThat(target).hasContent("This is going into a file" + System.lineSeparator()); 59 | } 60 | 61 | @Test 62 | void canDirectSystemOutToFileAndConsoleAndTap(@TempDir File tempDir) throws Exception { 63 | File target = new File(tempDir, "file"); 64 | SystemOut systemOut = new SystemOut(ofMultiplePlusOriginal(new TapStream().factoryOfSelf(), writeToFile(target))); 65 | systemOut.execute(() -> { 66 | System.out.println("This is going into a file"); 67 | }); 68 | 69 | assertThat(target).hasContent("This is going into a file" + System.lineSeparator()); 70 | assertThat(systemOut.getLines()).containsExactly("This is going into a file"); 71 | } 72 | 73 | @Test 74 | void canComposeMultiplex() throws Exception { 75 | TapStream tapStream1 = new TapStream(); 76 | TapStream tapStream2 = new TapStream(); 77 | Output multiplexOutput = ofMultiple(tapStream1, tapStream2); 78 | 79 | PrintStream printer = wrap(multiplexOutput.getOutputStream()); 80 | printer.println("Foo"); 81 | 82 | assertThat(multiplexOutput.getLines()).containsExactly("Foo"); 83 | assertThat(tapStream1.getLines()).containsExactly("Foo"); 84 | assertThat(tapStream2.getLines()).containsExactly("Foo"); 85 | } 86 | 87 | @Test 88 | void canComposeMultiplexOfFilesClosedByOutputClose(@TempDir File tempDir) throws Exception { 89 | File file1 = new File(tempDir, "file1"); 90 | File file2 = new File(tempDir, "file2"); 91 | Output multiplexOutput = ofMultiple(writeToFile(file1), writeToFile(file2)) 92 | .apply(null); 93 | 94 | PrintStream printer = wrap(multiplexOutput.getOutputStream()); 95 | printer.println("Foo"); 96 | 97 | // close it as though it's a stream 98 | multiplexOutput.getOutputStream().closeOutput(); 99 | 100 | assertThat(file1).hasContent("Foo" + System.lineSeparator()); 101 | assertThat(file2).hasContent("Foo" + System.lineSeparator()); 102 | } 103 | 104 | @Test 105 | void canComposeMultiplexOfFilesClosedByOutputStreamClose(@TempDir File tempDir) throws Exception { 106 | File file1 = new File(tempDir, "file1"); 107 | File file2 = new File(tempDir, "file2"); 108 | Output multiplexOutput = ofMultiple(writeToFile(file1), writeToFile(file2)) 109 | .apply(null); 110 | 111 | PrintStream printer = wrap(multiplexOutput.getOutputStream()); 112 | printer.println("Foo"); 113 | 114 | // close it as though it's a stream 115 | multiplexOutput.getOutputStream().close(); 116 | 117 | assertThat(file1).hasContent("Foo" + System.lineSeparator()); 118 | assertThat(file2).hasContent("Foo" + System.lineSeparator()); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /system-stubs-core/src/test/resources/test.properties: -------------------------------------------------------------------------------- 1 | value1=foo 2 | # comment 3 | value2=bar 4 | -------------------------------------------------------------------------------- /system-stubs-interceptor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | uk.org.webcompere 7 | system-stubs-parent 8 | 2.1.8 9 | ../pom.xml 10 | 11 | 12 | system-stubs-interceptor 13 | 2.1.8 14 | jar 15 | 16 | System Stubs Interceptor 17 | The jar used for byte buddy stubbing 18 | 19 | 20 | 11 21 | 11 22 | 23 | 24 | 25 | 26 | com.github.spotbugs 27 | spotbugs-annotations 28 | 29 | 30 | 31 | 32 | system-stubs-interceptor 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-surefire-plugin 37 | 38 | 39 | org.jacoco 40 | jacoco-maven-plugin 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-checkstyle-plugin 45 | 46 | 47 | com.github.spotbugs 48 | spotbugs-maven-plugin 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-gpg-plugin 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-source-plugin 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-javadoc-plugin 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /system-stubs-junit4/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | uk.org.webcompere 7 | system-stubs-parent 8 | 2.1.8 9 | ../pom.xml 10 | 11 | 12 | system-stubs-junit4 13 | 2.1.8 14 | jar 15 | 16 | System Stubs JUnit4 17 | JUnit4 rules using System Stubs implementation 18 | 19 | 20 | 11 21 | 11 22 | 23 | 24 | 25 | 26 | uk.org.webcompere 27 | system-stubs-core 28 | 29 | 30 | org.assertj 31 | assertj-core 32 | test 33 | 34 | 35 | junit 36 | junit 37 | 38 | 39 | org.mockito 40 | mockito-core 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-surefire-plugin 50 | 51 | 52 | buildme 53 | buildmetoo 54 | 55 | 56 | 57 | 58 | org.jacoco 59 | jacoco-maven-plugin 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-checkstyle-plugin 64 | 65 | 66 | com.github.spotbugs 67 | spotbugs-maven-plugin 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-gpg-plugin 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-source-plugin 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-javadoc-plugin 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/EnvironmentVariablesRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 4 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 5 | 6 | import java.util.Map; 7 | import java.util.Properties; 8 | 9 | /** 10 | * JUnit 4 rule which sets up the environment variables around whatever JUnit 4 is running 11 | * @since 1.0.0 12 | */ 13 | public class EnvironmentVariablesRule extends EnvironmentVariables implements SystemStubTestRule { 14 | 15 | /** 16 | * Default constructor provides restoration of the environment and the ability to set values 17 | */ 18 | public EnvironmentVariablesRule() { 19 | } 20 | 21 | /** 22 | * Construct with some variables to apply when active 23 | * @param properties map of variables to apply when active 24 | */ 25 | public EnvironmentVariablesRule(Properties properties) { 26 | super(properties); 27 | } 28 | 29 | /** 30 | * Construct with variables that will be set when the rule is active 31 | * @param name name of the first variable 32 | * @param value value of the first variable 33 | * @param others pairs of name/values as Strings 34 | */ 35 | public EnvironmentVariablesRule(String name, String value, String... others) { 36 | super(name, value, others); 37 | } 38 | 39 | /** 40 | * Construct with some variables to apply when active 41 | * @param variables map of variables to apply when active 42 | */ 43 | public EnvironmentVariablesRule(Map variables) { 44 | super(variables); 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | public EnvironmentVariablesRule and(String name, String value) { 52 | return new EnvironmentVariablesRule(super.and(name, value).getVariables()); 53 | } 54 | 55 | /** 56 | * {@inheritDoc} 57 | */ 58 | @Override 59 | public EnvironmentVariablesRule set(String name, String value) { 60 | return (EnvironmentVariablesRule)super.set(name, value); 61 | } 62 | 63 | /** 64 | * {@inheritDoc} 65 | */ 66 | @Override 67 | public EnvironmentVariablesRule set(Map properties) { 68 | return (EnvironmentVariablesRule)super.set(properties); 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | public EnvironmentVariablesRule remove(String name) { 75 | return (EnvironmentVariablesRule)super.remove(name); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SecurityManagerRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.security.SecurityManagerStub; 5 | 6 | /** 7 | * Set an alternative security manager within tests 8 | * @since 1.0.0 9 | */ 10 | public class SecurityManagerRule extends SecurityManagerStub implements SystemStubTestRule { 11 | /** 12 | * Default constructor - use this when the security manager will be set in-flight 13 | */ 14 | public SecurityManagerRule() { 15 | } 16 | 17 | /** 18 | * Construct with a specific security manager to use 19 | * @param securityManager the security manager to use 20 | */ 21 | public SecurityManagerRule(SecurityManager securityManager) { 22 | super(securityManager); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemErrAndOutRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.stream.SystemErrAndOut; 5 | import uk.org.webcompere.systemstubs.stream.output.Output; 6 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 7 | 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * JUnit4 rule for tapping both {@link System#err} and {@link System#out} at the same 12 | * time with the same {@link Output} 13 | * @since 1.0.0 14 | */ 15 | public class SystemErrAndOutRule extends SystemErrAndOut implements SystemStubTestRule { 16 | /** 17 | * Default constructor - uses a {@link uk.org.webcompere.systemstubs.stream.output.TapStream} 18 | */ 19 | public SystemErrAndOutRule() { 20 | } 21 | 22 | /** 23 | * Construct with a shared {@link Output} 24 | * @param output the output both system err and out will write to 25 | */ 26 | public SystemErrAndOutRule(Output output) { 27 | super(output); 28 | } 29 | 30 | /** 31 | * Construct with an output shared from the an output created against the System.out original 32 | * @param outputFactory the output factory to create the output 33 | */ 34 | public SystemErrAndOutRule(OutputFactory outputFactory) { 35 | super(outputFactory); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemErrRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.stream.SystemErr; 5 | import uk.org.webcompere.systemstubs.stream.output.Output; 6 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 7 | 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * JUnit4 test rule that captures {@link System#err} during tests. 12 | * @see uk.org.webcompere.systemstubs.stream.SystemErr 13 | * @since 1.0.0 14 | */ 15 | public class SystemErrRule extends SystemErr implements SystemStubTestRule { 16 | /** 17 | * Construct with an alternative {@link Output} to use 18 | * @param output the output to write system error to 19 | */ 20 | public SystemErrRule(Output output) { 21 | super(output); 22 | } 23 | 24 | /** 25 | * Construct with a {@link OutputFactory} for creating output objects from the existing output 26 | * 27 | * @param outputFactory the factory to use 28 | */ 29 | public SystemErrRule(OutputFactory outputFactory) { 30 | super(outputFactory); 31 | } 32 | 33 | /** 34 | * Default constructor, uses a {@link uk.org.webcompere.systemstubs.stream.output.TapStream} to 35 | * tap system error while the rule is active 36 | */ 37 | public SystemErrRule() { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemExitRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.security.SystemExit; 5 | 6 | /** 7 | * Add to a test to catch System exit events 8 | * @since 1.0.0 9 | */ 10 | public class SystemExitRule extends SystemExit implements SystemStubTestRule { 11 | } 12 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemInRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.stream.SystemIn; 5 | import uk.org.webcompere.systemstubs.stream.input.AltInputStream; 6 | 7 | import java.io.InputStream; 8 | 9 | /** 10 | * The {@link SystemIn} system stub as a JUnit 4 test rule 11 | * @since 1.0.0 12 | */ 13 | public class SystemInRule extends SystemIn implements SystemStubTestRule { 14 | /** 15 | * Construct with multiple lines on System.in 16 | * @param lines lines to provide - will be separated by system line separator 17 | */ 18 | public SystemInRule(String... lines) { 19 | super(lines); 20 | } 21 | 22 | /** 23 | * Construct with an input stream to read from - this will be closed on tidy up 24 | * @param inputStream the stream to read from 25 | */ 26 | public SystemInRule(InputStream inputStream) { 27 | super(inputStream); 28 | } 29 | 30 | /** 31 | * Construct with any of the {@link AltInputStream} objects - e.g. 32 | * {@link uk.org.webcompere.systemstubs.stream.input.LinesAltStream} 33 | * @param altInputStream the stream to use while the rule is active 34 | */ 35 | public SystemInRule(AltInputStream altInputStream) { 36 | super(altInputStream); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemOutRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 4 | import uk.org.webcompere.systemstubs.stream.SystemOut; 5 | import uk.org.webcompere.systemstubs.stream.output.Output; 6 | import uk.org.webcompere.systemstubs.stream.output.OutputFactory; 7 | 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * JUnit4 test rule that captures {@link System#out} during tests. 12 | * @see uk.org.webcompere.systemstubs.stream.SystemOut 13 | * @since 1.0.0 14 | */ 15 | public class SystemOutRule extends SystemOut implements SystemStubTestRule { 16 | /** 17 | * Construct with an alternative {@link Output} to use 18 | * 19 | * @param output the output to write system error to 20 | */ 21 | public SystemOutRule(Output output) { 22 | super(output); 23 | } 24 | 25 | /** 26 | * Construct with a {@link OutputFactory} for creating output objects from the existing output 27 | * 28 | * @param outputFactory the factory to use 29 | */ 30 | public SystemOutRule(OutputFactory outputFactory) { 31 | super(outputFactory); 32 | } 33 | 34 | /** 35 | * Default constructor, uses a {@link uk.org.webcompere.systemstubs.stream.output.TapStream} to 36 | * tap system out while the rule is active 37 | */ 38 | public SystemOutRule() { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/SystemPropertiesRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import uk.org.webcompere.systemstubs.properties.SystemPropertiesImpl; 4 | import uk.org.webcompere.systemstubs.rules.internal.SystemStubTestRule; 5 | 6 | import java.util.Properties; 7 | 8 | /** 9 | * Returns the system properties to their original state around each test block. Provides 10 | * the ability for properties to be prepared before the test starts, via {@link #set}. 11 | * @since 1.0.0 12 | */ 13 | public class SystemPropertiesRule extends SystemPropertiesImpl implements SystemStubTestRule { 14 | 15 | /** 16 | * Default constructor provides restoration of properties 17 | */ 18 | public SystemPropertiesRule() { 19 | } 20 | 21 | /** 22 | * Construct with some properties to apply when active 23 | * @param properties system properties to apply when active 24 | */ 25 | public SystemPropertiesRule(Properties properties) { 26 | super(properties); 27 | } 28 | 29 | public SystemPropertiesRule(String name, String value, String... nameValues) { 30 | super(name, value, nameValues); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/internal/Statements.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules.internal; 2 | 3 | import org.junit.runners.model.Statement; 4 | import uk.org.webcompere.systemstubs.ThrowingRunnable; 5 | import uk.org.webcompere.systemstubs.exception.WrappedThrowable; 6 | import uk.org.webcompere.systemstubs.resource.Resources; 7 | import uk.org.webcompere.systemstubs.resource.TestResource; 8 | 9 | /** 10 | * JUnit4 {@link Statement} helper 11 | */ 12 | public class Statements { 13 | /** 14 | * Convert executing the test resource into a statement 15 | */ 16 | public static Statement toStatement(Statement base, TestResource resource) { 17 | return new Statement() { 18 | public void evaluate() throws Throwable { 19 | try { 20 | Resources.execute(ThrowingRunnable.asCallable(base::evaluate), resource); 21 | } catch (WrappedThrowable t) { 22 | throw t.getCause(); 23 | } 24 | } 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/main/java/uk/org/webcompere/systemstubs/rules/internal/SystemStubTestRule.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules.internal; 2 | 3 | import org.junit.rules.TestRule; 4 | import org.junit.runner.Description; 5 | import org.junit.runners.model.Statement; 6 | import uk.org.webcompere.systemstubs.resource.TestResource; 7 | 8 | import static uk.org.webcompere.systemstubs.rules.internal.Statements.toStatement; 9 | 10 | /** 11 | * Common implementation to convert the {@link TestRule} interface into utilisation 12 | * of the {@link TestResource} interface. 13 | * @since 1.0.0 14 | */ 15 | public interface SystemStubTestRule extends TestRule, TestResource { 16 | @Override 17 | default Statement apply(Statement statement, Description description) { 18 | return toStatement(statement, this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/ClassRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.ClassRule; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.Suite; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | /** 11 | * Example to demonstrate how the @ClassRule integration works 12 | */ 13 | @RunWith(Suite.class) 14 | // use this test suite to control the execution order of the child class tests, to prove no bleed 15 | // in the environment between them 16 | @Suite.SuiteClasses({ClassRuleTest.Test1.class, ClassRuleTest.Test2.class, ClassRuleTest.Test3.class}) 17 | public class ClassRuleTest { 18 | 19 | public static class Test1 { 20 | @ClassRule 21 | public static EnvironmentVariablesRule env1 = new EnvironmentVariablesRule("someVar", "value1"); 22 | 23 | @Test 24 | public void test1() { 25 | assertThat(System.getenv("someVar")).isEqualTo("value1"); 26 | } 27 | } 28 | 29 | public static class Test2 { 30 | 31 | @Test 32 | public void test2() { 33 | assertThat(System.getenv("someVar")).isNull(); 34 | } 35 | } 36 | 37 | public static class Test3 { 38 | @ClassRule 39 | public static EnvironmentVariablesRule env1 = new EnvironmentVariablesRule("someVar", "value3"); 40 | 41 | @Test 42 | public void test3() { 43 | assertThat(System.getenv("someVar")).isEqualTo("value3"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/EnvironmentVariablesRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | 8 | import static org.assertj.core.api.Assertions.as; 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static uk.org.webcompere.systemstubs.resource.PropertySource.fromResource; 11 | 12 | @RunWith(Enclosed.class) 13 | public class EnvironmentVariablesRuleTest { 14 | public static class UsingSingleArgumentConstructor { 15 | @Rule 16 | public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule() 17 | .and("SOME", "value") 18 | .set("OTHER", "thing"); 19 | 20 | @Test 21 | public void hasEnvironmentVariablesFromInitializer() { 22 | assertThat(System.getenv("SOME")).isEqualTo("value"); 23 | assertThat(System.getenv("OTHER")).isEqualTo("thing"); 24 | } 25 | 26 | @Test 27 | public void canMakeChangeToEnvironment() { 28 | assertThat(System.getenv("FOO")).isNull(); 29 | environmentVariablesRule.set("FOO", "bar"); 30 | assertThat(System.getenv("FOO")).isEqualTo("bar"); 31 | } 32 | 33 | @Test 34 | public void canMakeAlternativeChangeToEnvironment() { 35 | assertThat(System.getenv("FOO")).isNull(); 36 | environmentVariablesRule.set("FOO", "baz"); 37 | assertThat(System.getenv("FOO")).isEqualTo("baz"); 38 | } 39 | } 40 | 41 | public static class UsingMultipleArgumentConstructor { 42 | @Rule 43 | public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule( 44 | "SOME", "value2", 45 | "OTHER", "thing2"); 46 | 47 | @Test 48 | public void withMultipleEnvironmentVariablesSetByConstructor() { 49 | assertThat(System.getenv("SOME")).isEqualTo("value2"); 50 | assertThat(System.getenv("OTHER")).isEqualTo("thing2"); 51 | } 52 | } 53 | 54 | public static class UsingTestResources { 55 | @Rule 56 | public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule() 57 | .set(fromResource("test.properties")); 58 | 59 | @Test 60 | public void withMultipleEnvironmentVariablesSetByConstructor() { 61 | assertThat(System.getenv("value1")).isEqualTo("foo"); 62 | } 63 | } 64 | 65 | public static class UsingTestResourcesViaConstructor { 66 | @Rule 67 | public EnvironmentVariablesRule environmentVariablesRule = 68 | new EnvironmentVariablesRule(fromResource("test.properties")); 69 | 70 | @Test 71 | public void withMultipleEnvironmentVariablesSetByConstructor() { 72 | assertThat(System.getenv("value1")).isEqualTo("foo"); 73 | } 74 | } 75 | 76 | public static class UsingRemoveViaConstructor { 77 | @Rule 78 | public EnvironmentVariablesRule environmentVariablesRule = 79 | new EnvironmentVariablesRule(fromResource("test.properties")); 80 | 81 | @Test 82 | public void withMultipleEnvironmentVariablesSetByConstructor() { 83 | assertThat(System.getenv("value1")).isEqualTo("foo"); 84 | } 85 | } 86 | 87 | public static class BuildVariableIsSet { 88 | @Test 89 | public void variablesAreVisibleNormally() { 90 | assertThat(System.getenv("SET_IN_BUILD")).isEqualTo("buildme"); 91 | assertThat(System.getenv("SET_IN_BUILD2")).isEqualTo("buildmetoo"); 92 | } 93 | } 94 | 95 | public static class BuildVariableIsRemoveable{ 96 | @Rule 97 | public EnvironmentVariablesRule environmentVariablesRule = 98 | new EnvironmentVariablesRule() 99 | .remove("SET_IN_BUILD") 100 | .remove("SET_IN_BUILD2"); 101 | 102 | 103 | @Test 104 | public void variablesAreVisibleNormally() { 105 | assertThat(System.getenv("SET_IN_BUILD")).isNull(); 106 | assertThat(System.getenv("SET_IN_BUILD2")).isNull(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SecurityManagerRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | import org.mockito.Answers; 8 | import org.mockito.Mock; 9 | import org.mockito.Spy; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | 12 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 13 | import static org.mockito.ArgumentMatchers.any; 14 | import static org.mockito.ArgumentMatchers.anyInt; 15 | import static org.mockito.BDDMockito.then; 16 | import static org.mockito.BDDMockito.willThrow; 17 | import static org.mockito.Mockito.mock; 18 | import static org.mockito.Mockito.never; 19 | 20 | @RunWith(Enclosed.class) 21 | public class SecurityManagerRuleTest { 22 | public static class SetSecurityManagerAtConstruction { 23 | @Rule 24 | public SecurityManagerRule securityManagerRule = new SecurityManagerRule(mock(SecurityManager.class)); 25 | 26 | @Test 27 | public void securityManagerAlreadyMocked() { 28 | // the security manager must be a mockito mock for this to work 29 | then(System.getSecurityManager()) 30 | .should(never()) 31 | .checkLink(any()); 32 | } 33 | } 34 | 35 | @RunWith(MockitoJUnitRunner.class) 36 | public static class SetSecurityManagerOnTheFly { 37 | @Rule 38 | public SecurityManagerRule securityManagerRule = new SecurityManagerRule(); 39 | 40 | @Mock(answer = Answers.RETURNS_DEEP_STUBS) 41 | public SecurityManager mockManager; 42 | 43 | @Test 44 | public void canMockTheSecurityManager() { 45 | // uses System.exit as an example of mocking the security manager 46 | // though the SystemExitRule does that better 47 | 48 | // the point is that a custom security manager can be provided somehow 49 | 50 | willThrow(new RuntimeException("don't go")) 51 | .given(mockManager) 52 | .checkExit(anyInt()); 53 | 54 | securityManagerRule.setSecurityManager(mockManager); 55 | 56 | assertThatThrownBy(() -> System.exit(123)) 57 | .hasMessage("don't go"); 58 | 59 | then(mockManager).should().checkExit(123); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemErrAndOutRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | import uk.org.webcompere.systemstubs.stream.output.TapStream; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static uk.org.webcompere.systemstubs.stream.output.OutputFactories.tapAndOutput; 11 | 12 | @RunWith(Enclosed.class) 13 | public class SystemErrAndOutRuleTest { 14 | 15 | public static class ExplicitOutput { 16 | @Rule 17 | public SystemErrAndOutRule errAndOutRule = new SystemErrAndOutRule(new TapStream()); 18 | 19 | @Test 20 | public void whenNothingIsWrittenNoTextIsFound() { 21 | assertThat(errAndOutRule.getText()).isEmpty(); 22 | } 23 | 24 | @Test 25 | public void whenWriteToOutThenItCanBeFound() { 26 | System.out.println("Some text"); 27 | assertThat(errAndOutRule.getLines()).contains("Some text"); 28 | } 29 | 30 | @Test 31 | public void whenWriteToErrThenItCanBeFound() { 32 | System.err.println("Some text"); 33 | assertThat(errAndOutRule.getLines()).contains("Some text"); 34 | } 35 | } 36 | 37 | public static class DefaultOutput { 38 | @Rule 39 | public SystemErrAndOutRule errAndOutRule = new SystemErrAndOutRule(); 40 | 41 | @Test 42 | public void whenNothingIsWrittenNoTextIsFound() { 43 | assertThat(errAndOutRule.getText()).isEmpty(); 44 | } 45 | 46 | @Test 47 | public void whenWriteToOutThenItCanBeFound() { 48 | System.out.println("Some text"); 49 | assertThat(errAndOutRule.getLines()).contains("Some text"); 50 | } 51 | 52 | @Test 53 | public void whenWriteToErrThenItCanBeFound() { 54 | System.err.println("Some text"); 55 | assertThat(errAndOutRule.getLines()).contains("Some text"); 56 | } 57 | } 58 | 59 | public static class TapWhileAlsoWritingToConsole { 60 | @Rule 61 | public SystemErrAndOutRule errAndOutRule = new SystemErrAndOutRule(tapAndOutput()); 62 | 63 | @Test 64 | public void whenWriteToOutThenItCanBeFound() { 65 | System.out.println("Some text"); 66 | assertThat(errAndOutRule.getLines()).contains("Some text"); 67 | } 68 | 69 | @Test 70 | public void whenWriteToErrThenItCanBeFound() { 71 | System.err.println("Some text"); 72 | assertThat(errAndOutRule.getLines()).contains("Some text"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemExitRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import uk.org.webcompere.systemstubs.security.AbortExecutionException; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 9 | 10 | public class SystemExitRuleTest { 11 | @Rule 12 | public SystemExitRule systemExitRule = new SystemExitRule(); 13 | 14 | @Test 15 | public void theCodeExitsButTheProgramDoesnt() { 16 | assertThatThrownBy(() -> { 17 | // some test code performs an exit 18 | System.exit(92); 19 | }).isInstanceOf(AbortExecutionException.class); 20 | 21 | assertThat(systemExitRule.getExitCode()).isEqualTo(92); 22 | } 23 | 24 | @Test 25 | public void noSystemExit() { 26 | assertThat(systemExitRule.getExitCode()).isNull(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemInRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | import uk.org.webcompere.systemstubs.stream.input.LinesAltStream; 8 | 9 | import java.io.ByteArrayInputStream; 10 | import java.io.IOException; 11 | import java.nio.charset.Charset; 12 | import java.util.List; 13 | import java.util.Scanner; 14 | import java.util.stream.Stream; 15 | 16 | import static java.lang.System.lineSeparator; 17 | import static java.util.stream.Collectors.toList; 18 | import static org.assertj.core.api.Assertions.assertThat; 19 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 20 | 21 | @RunWith(Enclosed.class) 22 | public class SystemInRuleTest { 23 | public static class SingleTextBlock { 24 | @Rule 25 | public SystemInRule systemInRule = new SystemInRule("text" ); 26 | 27 | @Test 28 | public void canReadText() { 29 | assertThat(readLinesFromSystemIn(1)).containsExactly("text"); 30 | } 31 | 32 | @Test 33 | public void canSetException() { 34 | systemInRule.andExceptionThrownOnInputEnd(new IOException("boom")); 35 | readLinesFromSystemIn(1); 36 | assertThatThrownBy(() -> System.in.read()).hasMessage("boom"); 37 | } 38 | } 39 | 40 | public static class MultiLineBlock { 41 | @Rule 42 | public SystemInRule systemInRule = new SystemInRule("line1", "line2"); 43 | 44 | @Test 45 | public void canReadText() { 46 | assertThat(readLinesFromSystemIn(2)).containsExactly("line1", "line2"); 47 | } 48 | } 49 | 50 | public static class LineStream { 51 | @Rule 52 | public SystemInRule systemInRule = new SystemInRule(new LinesAltStream("line1", "line2")); 53 | 54 | @Test 55 | public void canReadText() { 56 | assertThat(readLinesFromSystemIn(2)).containsExactly("line1", "line2"); 57 | } 58 | } 59 | 60 | public static class AnyStream { 61 | @Rule 62 | public SystemInRule systemInRule = new SystemInRule( 63 | new ByteArrayInputStream("line1\n".getBytes(Charset.defaultCharset()))); 64 | 65 | @Test 66 | public void canReadText() { 67 | assertThat(readLinesFromSystemIn(1)).containsExactly("line1"); 68 | } 69 | } 70 | 71 | /** 72 | * Read a certain number of lines from System.in 73 | * @param count the count to read 74 | * @return the list of lines read 75 | */ 76 | private static List readLinesFromSystemIn(int count) { 77 | Scanner scanner = new Scanner(System.in); 78 | return Stream.generate(scanner::nextLine) 79 | .limit(count) 80 | .collect(toList()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemOutAndSystemErrTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | import uk.org.webcompere.systemstubs.stream.output.DisallowWriteStream; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 11 | 12 | @RunWith(Enclosed.class) 13 | public class SystemOutAndSystemErrTest { 14 | 15 | public static class DisallowingWrite { 16 | @Rule 17 | public SystemErrRule noErrors = new SystemErrRule(new DisallowWriteStream()); 18 | 19 | @Rule 20 | public SystemOutRule noOutput = new SystemOutRule(new DisallowWriteStream()); 21 | 22 | @Test 23 | public void codeThatDoesNotOutputIsOk() { 24 | // this code doesn't hit system.out 25 | } 26 | 27 | @Test 28 | public void whenHitSystemOutThenIsError() { 29 | assertThatThrownBy(() -> System.out.println("boom")) 30 | .isInstanceOf(AssertionError.class); 31 | } 32 | 33 | @Test 34 | public void whenHitSystemErrThenIsError() { 35 | assertThatThrownBy(() -> System.err.println("boom")) 36 | .isInstanceOf(AssertionError.class); 37 | } 38 | } 39 | 40 | public static class TappingWrite { 41 | @Rule 42 | public SystemErrRule tapErr = new SystemErrRule(); 43 | 44 | @Rule 45 | public SystemOutRule tapOut = new SystemOutRule(); 46 | 47 | @Test 48 | public void whenHitSystemOutThenCanRead() { 49 | System.out.println("boom"); 50 | assertThat(tapOut.getLines()).containsExactly("boom"); 51 | } 52 | 53 | @Test 54 | public void whenHitSystemErrThenCanRead() { 55 | System.err.println("boom"); 56 | assertThat(tapErr.getLines()).containsExactly("boom"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemOutRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.experimental.runners.Enclosed; 6 | import org.junit.runner.RunWith; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | import static uk.org.webcompere.systemstubs.stream.output.OutputFactories.tapAndOutput; 10 | 11 | @RunWith(Enclosed.class) 12 | public class SystemOutRuleTest { 13 | 14 | public static class WithTappedSystemOut { 15 | @Rule 16 | public SystemOutRule systemOutRule = new SystemOutRule(); 17 | 18 | @Test 19 | public void whenWriteToSystemOutItCanBeSeen() { 20 | // imagine the code under test did this 21 | System.out.println("I am the system"); 22 | 23 | // then the test code can read it 24 | assertThat(systemOutRule.getLines()).containsExactly("I am the system"); 25 | } 26 | } 27 | 28 | public static class WithTappedAndStillWritingToConsole { 29 | @Rule 30 | public SystemOutRule systemOutRule = new SystemOutRule(tapAndOutput()); 31 | 32 | @Test 33 | public void whenWriteToSystemOutItCanBeSeen() { 34 | // imagine the code under test did this 35 | System.out.println("I am the system"); 36 | 37 | // then the test code can read it 38 | assertThat(systemOutRule.getLines()).containsExactly("I am the system"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/java/uk/org/webcompere/systemstubs/rules/SystemPropertiesRuleTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.rules; 2 | 3 | import org.junit.Before; 4 | import org.junit.FixMethodOrder; 5 | import org.junit.Rule; 6 | import org.junit.Test; 7 | import org.junit.experimental.runners.Enclosed; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.MethodSorters; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static uk.org.webcompere.systemstubs.resource.PropertySource.fromResource; 13 | 14 | @RunWith(Enclosed.class) 15 | public class SystemPropertiesRuleTest { 16 | // order of tests is important to demonstrate no bleed between properties 17 | @FixMethodOrder(MethodSorters.NAME_ASCENDING) 18 | public static class SystemPropertiesRuleNoBleedTest { 19 | 20 | @Rule 21 | public SystemPropertiesRule systemPropertiesRule = new SystemPropertiesRule("constructed", "yes"); 22 | 23 | @Before 24 | public void before() { 25 | systemPropertiesRule.set("before", "true"); 26 | } 27 | 28 | @Test 29 | public void a_canSetAPropertyAndReadIt() { 30 | System.setProperty("some", "property"); 31 | assertThat(System.getProperty("some")).isEqualTo("property"); 32 | } 33 | 34 | @Test 35 | public void b_propertyFromPreviousTestNotSet() { 36 | assertThat(System.getProperty("some")).isNull(); 37 | } 38 | 39 | @Test 40 | public void c_canSetPropertyViaRuleObject() { 41 | systemPropertiesRule.set("some", "otherProperty"); 42 | assertThat(System.getProperty("some")).isEqualTo("otherProperty"); 43 | } 44 | 45 | @Test 46 | public void d_eachTestGetsFreshInstanceSoSetDoesNotApply() { 47 | assertThat(System.getProperty("some")).isNull(); 48 | } 49 | 50 | @Test 51 | public void e_propertySetInBeforeMethodIsAvailable() { 52 | assertThat(System.getProperty("before")).isEqualTo("true"); 53 | } 54 | 55 | @Test 56 | public void f_propertySetInConstructorIsAvailable() { 57 | assertThat(System.getProperty("constructed")).isEqualTo("yes"); 58 | } 59 | } 60 | 61 | public static class WithPropertiesFromResources { 62 | @Rule 63 | public SystemPropertiesRule systemPropertiesRule = new SystemPropertiesRule() 64 | .set(fromResource("test.properties")); 65 | 66 | @Test 67 | public void g_withPropertiesFromFile() { 68 | assertThat(System.getProperty("value2")).isEqualTo("bar"); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /system-stubs-junit4/src/test/resources/test.properties: -------------------------------------------------------------------------------- 1 | value1=foo 2 | # comment 3 | value2=bar 4 | -------------------------------------------------------------------------------- /system-stubs-jupiter/README.md: -------------------------------------------------------------------------------- 1 | # System Stubs JUnit Jupiter 2 | 3 | Supports two methods of providing System Stub `TestResource` objects to 4 | JUnit 5 unit test. 5 | 6 | ```xml 7 | 8 | uk.org.webcompere 9 | system-stubs-jupiter 10 | 2.1.8 11 | 12 | ``` 13 | 14 | ## Extension 15 | 16 | Add the extension to a test class: 17 | 18 | ```java 19 | @ExtendWith(SystemStubsExtension.class) 20 | ``` 21 | 22 | This will resolve parameters and fields. 23 | 24 | ## Using the Extension 25 | ### By Parameter 26 | 27 | Provides a stub to the unit test which has already captured the necessary 28 | restore settings and is active. Will tidy up after the test: 29 | 30 | ```java 31 | @Test 32 | void method1(SystemProperties properties) { 33 | properties.set("prop1", "prop1"); 34 | assertThat(System.getProperty("prop1")).isEqualTo("prop1"); 35 | } 36 | ``` 37 | 38 | Supports all the System Stub objects that can be constructed without 39 | parameters, including `SystemProperties` and `EnvironmentVariables`. 40 | 41 | ### By Field 42 | 43 | Any field marked with `@SystemStub` will be instantiated and activated before 44 | each test if not already instantiated. If already instantiated it 45 | will be activated. At the end of each test it will be torn down. 46 | 47 | This allows for the environment to be built in `@BeforeEach` methods, for example. 48 | 49 | It also allows for the whole class to repeatedly clean the environment. E.g. 50 | 51 | ```java 52 | @SystemStub 53 | private SystemProperties systemProperties; 54 | 55 | @Test 56 | void someTest() { 57 | // this test cannot damage the system properties 58 | // because changes made via System.setProperty 59 | // or systemProperties.set will be undone after the test 60 | } 61 | ``` 62 | 63 | The `@SystemStub` annotation is required for the automatic use of the 64 | system stub objects so that it is also possible to manually set up and tear down 65 | the objects in other parts of the lifecycle as required. 66 | 67 | ### Fields with Single Test Instance 68 | 69 | In cases where `@TestInstance(TestInstance.Lifecycle.PER_CLASS)` is used, 70 | the system stub objects in the test instance fields are shared across multiple tests. 71 | 72 | This means that the following is possible: 73 | 74 | ```java 75 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 76 | class SomeTest { 77 | 78 | @SystemStub 79 | private EnvironmentVariables environment; 80 | 81 | @Test 82 | void test1_canSetUpEnvironment() { 83 | environment.set("shared", "instance"); 84 | } 85 | 86 | @Test 87 | void test2_canReceiveEnviroment() { 88 | assertThat(System.getenv("shared")).isEqualTo("instance"); 89 | } 90 | } 91 | ``` 92 | 93 | ### Static Fields 94 | 95 | When a System Stub object is used with a static field, it is 96 | automatically created and activated around the whole test class: 97 | 98 | ```java 99 | @SystemStub 100 | private static EnvironmentVariables testWideVariables = new EnvironmentVariables( 101 | "some", "value", 102 | "other", "setting"); 103 | 104 | @BeforeAll 105 | static void beforeAll() { 106 | // maybe work out some additional environment variables 107 | // to set here and use testWideVariables.set(...) 108 | } 109 | 110 | @Test 111 | void thisTestRunsWithTheEnvironment() { 112 | // and if this test uses testWideVariables.set(..) 113 | // the environment variable will be shared with subsequent 114 | // tests 115 | } 116 | ``` 117 | ## Use Cases 118 | 119 | A strong use case for dynamic environment variables and system properties is 120 | when performing Spring testing using dynamic resources such as Testcontainers 121 | or WireMock, which can run on random ports. 122 | 123 | Similarly, a particular system under test may automatically apply proxy 124 | settings from the environment variables as part of its static initialization. 125 | 126 | This plugin, or the manual use of the `setup` and `teardown` methods 127 | on the System Stub resource objects can allow the environment 128 | to be set at the right moment before other tests depend on it. 129 | 130 | See [the SpringBoot example test](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SpringAppWithDynamicPropertiesTest.java) for an example. 131 | 132 | ## Examples 133 | 134 | - [EnvironmentVariables declared before test](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/WithEnvironmentVariables.java) 135 | - [EnvironmentVariables, System Properties and TappingSystemOut](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/MultipleTestResources.java) - demonstrating 136 | multiple resources being set up with their defaults 137 | - [Injecting Resources by Parameter](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/InjectByParameter.java) 138 | - [SpringBoot dynamic property setting](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SpringAppWithDynamicPropertiesTest.java) - including use of `SystemOut` to capture log output 139 | - [System.Exit managed by the extension](src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SystemExitUseCase.java) 140 | 141 | ## Extensibility 142 | 143 | This plugin may also be used with home-made test resources so long 144 | as they subclass `TestResource`. 145 | 146 | Example: 147 | 148 | ```java 149 | public class CustomResource implements TestResource { 150 | // ... override setup/teardown to manage resource 151 | } 152 | 153 | 154 | // test 155 | @ExtendWith(SystemStubsExtension.class) 156 | class SomeTest { 157 | @SystemStub 158 | private CustomResource customResource; // assuming there's a default constructor 159 | 160 | @Test 161 | void someTest() { 162 | // access the resource 163 | } 164 | } 165 | ``` 166 | 167 | **Note: The extension requires the test resource to provide a default constructor to enable it to create 168 | instances for parameter injection and automatic field creation.** 169 | -------------------------------------------------------------------------------- /system-stubs-jupiter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | uk.org.webcompere 7 | system-stubs-parent 8 | 2.1.8 9 | ../pom.xml 10 | 11 | 12 | system-stubs-jupiter 13 | 2.1.8 14 | jar 15 | 16 | System Stubs Jupiter 17 | JUnit Jupiter Extension for System Stubs 18 | 19 | 20 | 11 21 | 11 22 | 23 | 24 | 25 | 26 | uk.org.webcompere 27 | system-stubs-core 28 | 29 | 30 | org.assertj 31 | assertj-core 32 | test 33 | 34 | 35 | org.junit.jupiter 36 | junit-jupiter 37 | provided 38 | 39 | 40 | 41 | 42 | com.github.tomakehurst 43 | wiremock 44 | 2.27.2 45 | test 46 | 47 | 48 | 49 | org.junit-pioneer 50 | junit-pioneer 51 | 2.1.0 52 | test 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-web 58 | 2.7.15 59 | test 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | 2.7.15 66 | test 67 | 68 | 69 | 70 | io.rest-assured 71 | rest-assured 72 | 5.3.1 73 | test 74 | 75 | 76 | 77 | org.eclipse.jetty 78 | jetty-server 79 | 9.4.52.v20230823 80 | test 81 | 82 | 83 | 84 | org.eclipse.jetty 85 | jetty-servlet 86 | 9.4.52.v20230823 87 | test 88 | 89 | 90 | 91 | org.eclipse.jetty 92 | jetty-servlets 93 | 9.4.52.v20230823 94 | test 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-surefire-plugin 103 | 104 | 105 | org.jacoco 106 | jacoco-maven-plugin 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-checkstyle-plugin 111 | 112 | 113 | com.github.spotbugs 114 | spotbugs-maven-plugin 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-gpg-plugin 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-source-plugin 125 | 126 | 127 | org.apache.maven.plugins 128 | maven-javadoc-plugin 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/main/java/uk/org/webcompere/systemstubs/jupiter/SystemStub.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marks a field in a test class as a system stub - this makes it get set up 10 | * automatically around individual tests or, if static, around the whole test fixture 11 | * @since 1.0.0 12 | */ 13 | @Target({ ElementType.FIELD }) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface SystemStub { 16 | } 17 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/SystemStubsExtensionStaticClassTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter; 2 | 3 | import org.junit.jupiter.api.*; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | @Nested 10 | @ExtendWith(SystemStubsExtension.class) 11 | public class SystemStubsExtensionStaticClassTest { 12 | 13 | @SystemStub 14 | private static EnvironmentVariables environmentVariables; 15 | 16 | @BeforeAll 17 | static void beforeAll() { 18 | environmentVariables.set("someglobal", "value"); 19 | } 20 | 21 | @Test 22 | void canAccessFromStaticContext() { 23 | assertThat(System.getenv("someglobal")).isEqualTo("value"); 24 | } 25 | 26 | @Nested 27 | class NestedClass { 28 | @Test 29 | void hasEnvironmentOfParent() { 30 | assertThat(System.getenv("someglobal")).isEqualTo("value"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/compatibility/DoesNotPreventJUnitPioneerFromWorkingTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.compatibility; 2 | 3 | import org.junit.jupiter.api.Nested; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.condition.EnabledForJreRange; 6 | import org.junit.jupiter.api.condition.JRE; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.junitpioneer.jupiter.SetEnvironmentVariable; 9 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 10 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 11 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | @EnabledForJreRange(max = JRE.JAVA_16) 16 | class DoesNotPreventJUnitPioneerFromWorkingTest { 17 | 18 | @Nested 19 | @ExtendWith(SystemStubsExtension.class) 20 | static class StubsWorks { 21 | @SystemStub 22 | private EnvironmentVariables variables; 23 | 24 | @Test 25 | void canStubVariable() { 26 | variables.set("MACHINE", "hot"); 27 | 28 | assertThat(System.getenv("MACHINE")).isEqualTo("hot"); 29 | } 30 | } 31 | 32 | @Nested 33 | @SetEnvironmentVariable(key="MACHINE", value="COLD") 34 | static class PioneerWorks { 35 | @Test 36 | void canPioneerVariable() { 37 | assertThat(System.getenv("MACHINE")).isEqualTo("cold"); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/EnvironmentVariablesAcrossThreads.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 6 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 7 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.concurrent.CountDownLatch; 12 | 13 | import static java.lang.System.getenv; 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | 16 | @ExtendWith(SystemStubsExtension.class) 17 | class EnvironmentVariablesAcrossThreads { 18 | 19 | @SystemStub 20 | private EnvironmentVariables environmentVariables = new EnvironmentVariables("foo", "bar"); 21 | 22 | @Test 23 | void theVariablesAreSetInTheTestMainThread() { 24 | assertThat(getenv("foo")).isEqualTo("bar"); 25 | } 26 | 27 | @Test 28 | void theVariablesAreVisibleToWorkerThreads() throws Exception { 29 | Map result = new HashMap<>(); 30 | 31 | CountDownLatch latch = new CountDownLatch(1); 32 | 33 | new Thread(() -> { 34 | result.put("foo", getenv("foo")); 35 | latch.countDown(); 36 | }).start(); 37 | 38 | latch.await(); 39 | 40 | assertThat(result).containsEntry("foo", "bar"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/InjectByParameter.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 6 | import uk.org.webcompere.systemstubs.security.AbortExecutionException; 7 | import uk.org.webcompere.systemstubs.security.SystemExit; 8 | import uk.org.webcompere.systemstubs.stream.SystemErrAndOut; 9 | import uk.org.webcompere.systemstubs.stream.SystemIn; 10 | import uk.org.webcompere.systemstubs.stream.input.LinesAltStream; 11 | 12 | import java.util.Scanner; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 16 | 17 | @ExtendWith(SystemStubsExtension.class) 18 | public class InjectByParameter { 19 | @Test 20 | void useALocalSystemExit(SystemExit exit) { 21 | assertThatThrownBy(() -> System.exit(123)) 22 | .isInstanceOf(AbortExecutionException.class); 23 | 24 | assertThat(exit.getExitCode()).isEqualTo(123); 25 | } 26 | 27 | @Test 28 | void tapErrorAndOutAndProvideSystemIn(SystemErrAndOut errAndOut, SystemIn systemIn) { 29 | // given the system in contains lines 30 | systemIn.setInputStream(new LinesAltStream("one", "two", "three")); 31 | 32 | // when the algorithm runs 33 | try { 34 | Scanner scanner = new Scanner(System.in); 35 | while (true) { 36 | System.out.println(scanner.nextLine()); 37 | } 38 | } catch (Exception e) { 39 | System.err.println(e.getMessage()); 40 | } 41 | 42 | // then the output is both the out and errs 43 | assertThat(errAndOut.getLines()).containsExactly("one", "two", "three", "No line found"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/MultipleTestResources.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import org.junit.jupiter.api.MethodOrderer; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.TestMethodOrder; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 8 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 9 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 10 | import uk.org.webcompere.systemstubs.properties.SystemProperties; 11 | import uk.org.webcompere.systemstubs.stream.SystemOut; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | @ExtendWith(SystemStubsExtension.class) 16 | @TestMethodOrder(MethodOrderer.MethodName.class) 17 | public class MultipleTestResources { 18 | // protected the environment, allowing us a set method 19 | @SystemStub 20 | private EnvironmentVariables environmentVariables; 21 | 22 | // defaults to protecting system properties against change 23 | @SystemStub 24 | private SystemProperties systemProperties; 25 | 26 | // defaults to tapping system out 27 | @SystemStub 28 | private SystemOut systemOut; 29 | 30 | @Test 31 | void method1_canDoThingsThatAreIsolatedFromOtherMethods() { 32 | environmentVariables.set("a", "b"); 33 | systemProperties.set("prop1", "proppy"); 34 | 35 | System.out.println("hello world"); 36 | 37 | assertThat(System.getenv("a")).isEqualTo("b"); 38 | assertThat(System.getProperty("prop1")).isEqualTo("proppy"); 39 | 40 | assertThat(systemOut.getText()).startsWith("hello world"); 41 | } 42 | 43 | @Test 44 | void method2_isUnaffectedByAllTheEventsOfMethod1() { 45 | assertThat(System.getenv("a")).isNull(); 46 | assertThat(System.getProperty("prop1")).isNull(); 47 | 48 | assertThat(systemOut.getText()).isEmpty(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SpringAppWithDynamicPropertiesTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import com.github.tomakehurst.wiremock.WireMockServer; 4 | import com.github.tomakehurst.wiremock.core.Options; 5 | import org.junit.jupiter.api.AfterAll; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.Nested; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.boot.test.web.server.LocalServerPort; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | import org.springframework.web.client.RestTemplate; 19 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 20 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 21 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 22 | import uk.org.webcompere.systemstubs.stream.SystemOut; 23 | 24 | import static com.github.tomakehurst.wiremock.client.WireMock.*; 25 | import static io.restassured.RestAssured.given; 26 | import static org.assertj.core.api.Assertions.assertThat; 27 | import static org.hamcrest.CoreMatchers.is; 28 | import static uk.org.webcompere.systemstubs.stream.output.OutputFactories.tapAndOutput; 29 | 30 | @ExtendWith(SystemStubsExtension.class) 31 | public class SpringAppWithDynamicPropertiesTest { 32 | private static final WireMockServer wireMock = new WireMockServer(Options.DYNAMIC_PORT); 33 | 34 | // sets the environment before Spring even starts 35 | @SystemStub 36 | private static EnvironmentVariables environmentVariables; 37 | 38 | @SystemStub 39 | private static SystemOut systemOut = new SystemOut(tapAndOutput()); 40 | 41 | @BeforeAll 42 | static void beforeAll() { 43 | wireMock.start(); 44 | 45 | wireMock.stubFor(get(urlEqualTo("/foo")) 46 | .willReturn(aResponse().withBody("from wiremock").withStatus(200))); 47 | 48 | // this is setting an environment variable to override a Spring 49 | // property `server.url`. We could similarly use the `SystemProperties` 50 | // object to set `server.url` - but this approach is slightly more challenging, 51 | // so it a more interesting example. 52 | // Only this technique can set environment variables before ANY spring resources 53 | // start up. This could, therefore, be used to override system settings like 54 | // https_proxy, picked up by SDKs in use in the spring application 55 | environmentVariables.set("SERVER_URL", wireMock.baseUrl()); 56 | } 57 | 58 | @AfterAll 59 | static void afterAll() { 60 | wireMock.stop(); 61 | } 62 | 63 | // pretend spring app that expects server.url property 64 | // but can have it overridden by an environment variable 65 | @RestController 66 | public static class RestApi { 67 | private String baseUrl; 68 | private RestTemplate restTemplate = new RestTemplate(); 69 | 70 | public RestApi(@Value("${server.url}") String baseUrl) { 71 | this.baseUrl = baseUrl; 72 | } 73 | 74 | @GetMapping("/") 75 | public ResponseEntity getSlash() { 76 | return restTemplate.getForEntity(baseUrl + "/foo", String.class); 77 | } 78 | } 79 | 80 | @SpringBootApplication 81 | public static class App { 82 | public static void main(String[] args) { 83 | SpringApplication.run(App.class, args); 84 | } 85 | } 86 | 87 | @Nested 88 | @SpringBootTest(classes = {RestApi.class, App.class}, 89 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 90 | class InnerSpringTest { 91 | @LocalServerPort 92 | private int serverPort; 93 | 94 | @Test 95 | void canReachServiceThatTalksToWiremock() { 96 | given() 97 | .baseUri("http://localhost:" + serverPort) 98 | .when() 99 | .get("/") 100 | .then() 101 | .statusCode(200) 102 | .body(is("from wiremock")); 103 | 104 | } 105 | 106 | @Test 107 | void canSeeLoggingOutputInSystemOutObject() { 108 | assertThat(systemOut.getText()) 109 | .contains(":: Spring Boot :: (v2.7.15)"); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SystemExitUseCase.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 6 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 7 | import uk.org.webcompere.systemstubs.security.AbortExecutionException; 8 | import uk.org.webcompere.systemstubs.security.SystemExit; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 12 | 13 | @ExtendWith(SystemStubsExtension.class) 14 | class SystemExitUseCase { 15 | // the presence of this in the test means System.exit becomes an exception 16 | @SystemStub 17 | private SystemExit systemExit; 18 | 19 | @Test 20 | void doSomethingThatAccidentallyCallsSystemExit() { 21 | // this test would have stopped the JVM, now it ends in `AbortExecutionException` 22 | // System.exit(1); 23 | } 24 | 25 | @Test 26 | void canCatchSystemExit() { 27 | assertThatThrownBy(() -> System.exit(1)) 28 | .isInstanceOf(AbortExecutionException.class); 29 | 30 | assertThat(systemExit.getExitCode()).isEqualTo(1); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/WithEnvironmentVariables.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.jupiter.examples; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 6 | import uk.org.webcompere.systemstubs.jupiter.SystemStub; 7 | import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | @ExtendWith(SystemStubsExtension.class) 12 | class WithEnvironmentVariables { 13 | 14 | @SystemStub 15 | private EnvironmentVariables variables = new EnvironmentVariables("input", "foo"); 16 | 17 | @Test 18 | void hasAccessToEnvironmentVariables() { 19 | assertThat(System.getenv("input")).isEqualTo("foo"); 20 | } 21 | 22 | @Test 23 | void changeEnvironmentVariablesDuringTest() { 24 | variables.set("input", "bar"); 25 | 26 | assertThat(System.getenv("input")) 27 | .isEqualTo("bar"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /system-stubs-testng/README.md: -------------------------------------------------------------------------------- 1 | # System Stubs TestNG 2 | 3 | Provides some automatic instantiation of System Stubs objects during the test lifecycle. 4 | 5 | ```xml 6 | 7 | uk.org.webcompere 8 | system-stubs-testng 9 | 2.1.8 10 | 11 | ``` 12 | 13 | ## Options 14 | 15 | ### Stub Without the Plugin 16 | System Stubs Core can be used with TestNG as it is framework agnostic. 17 | 18 | We can call the `setup` method on any of the stubs in a before method, and `teardown` in the after method. 19 | 20 | ```java 21 | private EnvironmentVariables environmentVariables = new EnvironmentVariables(); 22 | 23 | @BeforeTest 24 | public void beforeTest() throws Exception { 25 | environmentVariables.set("setinbefore", "yes"); 26 | 27 | environmentVariables.setup(); 28 | } 29 | 30 | @AfterTest 31 | public void afterTest() throws Exception { 32 | environmentVariables.teardown(); 33 | } 34 | ``` 35 | 36 | With this code, we'd expect tests to be able to modify the runtime environment by manipulating the 37 | `environmentVariables` object, and we'd expect the tests to see the environment variables set in the `beforeTest` 38 | function; in this example, `setinbefore` was set to `yes`. 39 | 40 | Similarly, we can use `setup` and `teardown` methods of a `TestResources` such as `EnvironmentVariables` inside a test case, or use the `SystemStubs` wrapper methods such as 41 | `withEnvironmentVariables`. See the [main documentation](../README.md) for more on the execute around pattern. 42 | 43 | ### Using the Plugin 44 | 45 | The plugin: 46 | 47 | - Automatically instantiates system stubs objects before they're first used by a TestNG annotated method 48 | - Activates the objects during tests 49 | - Turns the objects off after tests 50 | 51 | Usage: 52 | 53 | ```java 54 | @Listeners(SystemStubsListener.class) 55 | public class CaptureSystemOutTest { 56 | 57 | // We can ininitialise this object with `new` here, or 58 | // leave it uninitialized for the plugin to do it for us 59 | @SystemStub 60 | private SystemOut out; 61 | 62 | @BeforeTest 63 | public void beforeTest() { 64 | out.clear(); 65 | } 66 | 67 | @Test 68 | public void canReadThingsSentToSystemOut() { 69 | // simulate the system under test writing to std out 70 | System.out.println("Can I assert this?"); 71 | 72 | assertThat(out.getText()).isEqualTo("Can I assert this?\n"); 73 | } 74 | } 75 | ``` 76 | 77 | > Note: in this instance we've used the `SystemOut` stub. We've had to remember to call its `clear` method as it 78 | > will be shared between tests. 79 | > Note: we may prefer to initialize our stub objects to give them configuration or initial values without using 80 | > a `@BeforeTest` function. 81 | 82 | We can use any of the core system stubs classes such as: 83 | 84 | - `EnvironmentVariables` - for overriding the environment variables 85 | - `SystemProperties` - for temporarily overwriting system properties and then restoring them afterwards 86 | - `SystemOut` - for tapping the `System.out` 87 | - ... and so on 88 | 89 | All we need to do is: 90 | 91 | - Add the `@Listeners(SystemStubsListener.class)` annotation to our TestNG test class (using an array with {} if we have other listeners) 92 | - Add a field for each System Stub we want to use 93 | - Annotate that field with the `@SystemStubs` annotation 94 | 95 | ### Benefits of the Plugin 96 | 97 | With the plugin, there's less boilerplate to write. Any exception handling is also covered by the plugin - or at 98 | least, we don't have to explicitly add `throws` to any of our methods that set up or teardown a stub. 99 | 100 | However, the plugin is simple and opinionated. For fine-grained control of the stubs, the direct method 101 | may sometimes be preferable. 102 | 103 | ## Feedback 104 | 105 | This TestNG module is incubating. Please raise issues with examples if it proves to have issues in practice. 106 | -------------------------------------------------------------------------------- /system-stubs-testng/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | uk.org.webcompere 7 | system-stubs-parent 8 | 2.1.8 9 | ../pom.xml 10 | 11 | 12 | 13 | system-stubs-testng 14 | 2.1.8 15 | jar 16 | 17 | 18 | 11 19 | 11 20 | 21 | 22 | 23 | 24 | uk.org.webcompere 25 | system-stubs-core 26 | 27 | 28 | 29 | com.github.spotbugs 30 | spotbugs-annotations 31 | 32 | 33 | 34 | org.testng 35 | testng 36 | provided 37 | 38 | 39 | 40 | org.assertj 41 | assertj-core 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-surefire-plugin 51 | 52 | 53 | org.jacoco 54 | jacoco-maven-plugin 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-checkstyle-plugin 59 | 60 | 61 | com.github.spotbugs 62 | spotbugs-maven-plugin 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-gpg-plugin 69 | 70 | 71 | org.apache.maven.plugins 72 | maven-source-plugin 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-javadoc-plugin 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /system-stubs-testng/src/main/java/uk/org/webcompere/systemstubs/testng/SystemStub.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marks a field in a test class as a system stub - this causes the {@link SystemStubsListener} to activate 10 | * it during tests. It also causes the field to become instantiated if left uninitialized 11 | * @since 1.0.0 12 | */ 13 | @Target({ ElementType.FIELD }) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface SystemStub { 16 | } 17 | -------------------------------------------------------------------------------- /system-stubs-testng/src/main/java/uk/org/webcompere/systemstubs/testng/SystemStubsListener.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import org.testng.IInvokedMethod; 5 | import org.testng.IInvokedMethodListener; 6 | import org.testng.ITestResult; 7 | import uk.org.webcompere.systemstubs.resource.TestResource; 8 | 9 | import java.lang.reflect.AccessibleObject; 10 | import java.lang.reflect.Field; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.Objects; 14 | 15 | import static java.util.stream.Collectors.toList; 16 | import static uk.org.webcompere.systemstubs.resource.Resources.executeCleanup; 17 | 18 | /** 19 | * Add this to a test class with: 20 | * 21 | *
 22 |  * @@Listeners(SystemStubsListener.class)
 23 |  * public class MyTestClass {
 24 |  *
 25 |  * }
 26 |  * 
27 | * This causes any of the system stubs objects, that inherit {@link TestResource} to 28 | * become active during tests. It will also instantiate any objects not initialized in the 29 | * initializer list. 30 | */ 31 | public class SystemStubsListener implements IInvokedMethodListener { 32 | @Override 33 | public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { 34 | List stubs = ensureAllStubsAreInstantiated(method); 35 | if (method.isTestMethod()) { 36 | try { 37 | for (TestResource stub: stubs) { 38 | stub.setup(); 39 | } 40 | } catch (Exception e) { 41 | throw new AssertionError("Could not set up stubs", e); 42 | } 43 | } 44 | } 45 | 46 | @Override 47 | public void afterInvocation(IInvokedMethod method, ITestResult testResult) { 48 | if (method.isTestMethod()) { 49 | try { 50 | executeCleanup(getAllStubs(method)); 51 | } catch (Exception e) { 52 | throw new AssertionError("Could not tidy up stubs", e); 53 | } 54 | } 55 | } 56 | 57 | private static TestResource readSystemStubResource(Field field, Object testObject) { 58 | if (!TestResource.class.isAssignableFrom(field.getType())) { 59 | throw new IllegalArgumentException("Cannot use @SystemStub with non TestResource object in field " + 60 | field.getName() + " this one's a " + 61 | field.getType().getCanonicalName()); 62 | } 63 | try { 64 | makeAccessible(field); 65 | return (TestResource)field.get(testObject); 66 | } catch (Exception e) { 67 | throw new AssertionError("Cannot read field " + field.getName(), e); 68 | } 69 | } 70 | 71 | private static List getAllStubs(IInvokedMethod method) { 72 | var testObject = method.getTestMethod().getInstance(); 73 | var fields = testObject.getClass().getDeclaredFields(); 74 | return Arrays.stream(fields) 75 | .filter(field -> field.isAnnotationPresent(SystemStub.class)) 76 | .map(field -> readSystemStubResource(field, testObject)) 77 | .filter(Objects::nonNull) 78 | .collect(toList()); 79 | } 80 | 81 | private static T makeAccessible(T object) { 82 | if (!object.isAccessible()) { 83 | object.setAccessible(true); 84 | } 85 | return object; 86 | } 87 | 88 | private static List ensureAllStubsAreInstantiated(IInvokedMethod method) { 89 | var testObject = method.getTestMethod().getInstance(); 90 | var fields = testObject.getClass().getDeclaredFields(); 91 | return Arrays.stream(fields) 92 | .filter(field -> field.isAnnotationPresent(SystemStub.class)) 93 | .map(field -> instantiateIfNecessary(field, testObject)) 94 | .collect(toList()); 95 | } 96 | 97 | @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", 98 | justification = "Generic catch block provided as lots can go wrong when using reflection") 99 | private static TestResource instantiateIfNecessary(Field field, Object testObject) { 100 | if (!TestResource.class.isAssignableFrom(field.getType())) { 101 | throw new IllegalArgumentException("Cannot use @SystemStub with non TestResource object in field " + 102 | field.getName() + " this one's a " + 103 | field.getType().getCanonicalName()); 104 | } 105 | 106 | try { 107 | makeAccessible(field); 108 | var currentObject = field.get(testObject); 109 | if (currentObject == null) { 110 | var newInstance = field.getType().getDeclaredConstructor().newInstance(); 111 | field.set(testObject, newInstance); 112 | return (TestResource) newInstance; 113 | } 114 | return (TestResource) currentObject; 115 | } catch (Exception e) { 116 | throw new AssertionError("Cannot access field " + field.getName(), e); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /system-stubs-testng/src/test/java/uk/org/webcompere/systemstubs/testng/SystemStubsPluginWhenStubIsBlankTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng; 2 | 3 | import org.testng.annotations.BeforeTest; 4 | import org.testng.annotations.Listeners; 5 | import org.testng.annotations.Test; 6 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | @Listeners(SystemStubsListener.class) 11 | public class SystemStubsPluginWhenStubIsBlankTest { 12 | 13 | @SystemStub 14 | private EnvironmentVariables environmentVariables; 15 | 16 | @BeforeTest 17 | public void beforeTest() { 18 | // even though the stub looks to be null, it's instantiated by here 19 | environmentVariables.set("setinbefore", "yes"); 20 | } 21 | 22 | @Test 23 | public void noEnvironmentVariable() { 24 | assertThat(System.getenv("scooby")).isBlank(); 25 | } 26 | 27 | @Test 28 | public void hasEnvironmentVariable() { 29 | environmentVariables.set("foo", "bar"); 30 | 31 | assertThat(System.getenv("foo")).isEqualTo("bar"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /system-stubs-testng/src/test/java/uk/org/webcompere/systemstubs/testng/SystemStubsPluginWhenStubIsDefinedTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng; 2 | 3 | import org.testng.IInvokedMethod; 4 | import org.testng.annotations.*; 5 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | @Listeners(SystemStubsListener.class) 10 | public class SystemStubsPluginWhenStubIsDefinedTest { 11 | 12 | @SystemStub 13 | private EnvironmentVariables environmentVariables = new EnvironmentVariables(); 14 | 15 | @BeforeTest 16 | public void beforeTest() { 17 | environmentVariables.set("setinbefore", "yes"); 18 | 19 | // shouldn't apply yet, as we're not inside a test 20 | assertThat(System.getenv("setinbefore")).isNotEqualTo("yes"); 21 | } 22 | 23 | @Test 24 | public void noEnvironmentVariable() { 25 | assertThat(System.getenv("scooby")).isBlank(); 26 | } 27 | 28 | @Test 29 | public void hasEnvironmentVariable() { 30 | environmentVariables.set("foo", "bar"); 31 | 32 | assertThat(System.getenv("foo")).isEqualTo("bar"); 33 | } 34 | 35 | @Test 36 | public void environmentSetInBeforeWillApplyInTest() { 37 | assertThat(System.getenv("setinbefore")).isEqualTo("yes"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /system-stubs-testng/src/test/java/uk/org/webcompere/systemstubs/testng/examples/CaptureSystemOutTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng.examples; 2 | 3 | import org.testng.annotations.BeforeTest; 4 | import org.testng.annotations.Listeners; 5 | import org.testng.annotations.Test; 6 | import uk.org.webcompere.systemstubs.stream.SystemOut; 7 | import uk.org.webcompere.systemstubs.testng.SystemStub; 8 | import uk.org.webcompere.systemstubs.testng.SystemStubsListener; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @Listeners(SystemStubsListener.class) 13 | public class CaptureSystemOutTest { 14 | 15 | @SystemStub 16 | private SystemOut out; 17 | 18 | @BeforeTest 19 | public void beforeTest() { 20 | out.clear(); 21 | } 22 | 23 | @Test 24 | public void canReadThingsSentToSystemOut() { 25 | // simulate the system under test writing to std out 26 | System.out.println("Can I assert this?"); 27 | 28 | assertThat(out.getText()).startsWith("Can I assert this?"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /system-stubs-testng/src/test/java/uk/org/webcompere/systemstubs/testng/examples/SystemStubsWithoutPluginTest.java: -------------------------------------------------------------------------------- 1 | package uk.org.webcompere.systemstubs.testng.examples; 2 | 3 | import org.testng.annotations.AfterTest; 4 | import org.testng.annotations.BeforeTest; 5 | import org.testng.annotations.Listeners; 6 | import org.testng.annotations.Test; 7 | import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; 8 | import uk.org.webcompere.systemstubs.testng.SystemStub; 9 | import uk.org.webcompere.systemstubs.testng.SystemStubsListener; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | 13 | public class SystemStubsWithoutPluginTest { 14 | 15 | private EnvironmentVariables environmentVariables = new EnvironmentVariables(); 16 | 17 | @BeforeTest 18 | public void beforeTest() throws Exception { 19 | environmentVariables.set("setinbefore", "yes"); 20 | 21 | environmentVariables.setup(); 22 | } 23 | 24 | @AfterTest 25 | public void afterTest() throws Exception { 26 | environmentVariables.teardown(); 27 | } 28 | 29 | @Test 30 | public void noEnvironmentVariable() { 31 | assertThat(System.getenv("scooby")).isBlank(); 32 | } 33 | 34 | @Test 35 | public void hasEnvironmentVariable() { 36 | environmentVariables.set("foo", "bar"); 37 | 38 | assertThat(System.getenv("foo")).isEqualTo("bar"); 39 | } 40 | 41 | @Test 42 | public void environmentSetInBeforeWillApplyInTest() { 43 | assertThat(System.getenv("setinbefore")).isEqualTo("yes"); 44 | } 45 | } 46 | --------------------------------------------------------------------------------