001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2024-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.common.context.testlib; 019 020import dev.enola.common.context.Singleton; 021 022import org.junit.rules.TestRule; 023import org.junit.runner.Description; 024import org.junit.runners.model.Statement; 025 026/** JUnit <code>@ClassRule</code> (or even just <code>@Rule</code>) for {@link Singleton}. */ 027public class SingletonRule implements TestRule { 028 029 /** Intended to be statically imported into *Test classes. */ 030 public static SingletonRule $(Singleton<?>... singletons) { 031 return new SingletonRule(singletons, true); 032 } 033 034 public static SingletonRule onlyReset(Singleton<?>... singletons) { 035 return new SingletonRule(singletons, false); 036 } 037 038 private final Singleton<?>[] singletons; 039 private boolean doNotReset = false; 040 041 private SingletonRule(Singleton<?>[] singletons, boolean get) { 042 if (get) 043 for (var singleton : singletons) 044 // This may throw IllegalStateException (which is what we want) 045 singleton.get(); 046 this.singletons = singletons; 047 } 048 049 @Override 050 public Statement apply(Statement base, Description description) { 051 return statement(base); 052 } 053 054 private <T> Statement statement(Statement base) { 055 return new Statement() { 056 @Override 057 public void evaluate() throws Throwable { 058 try { 059 base.evaluate(); 060 } finally { 061 if (!doNotReset) 062 for (var singleton : singletons) 063 try { 064 singleton.reset(); 065 } catch (IllegalStateException ignored) { 066 // IGNORE! 067 } 068 doNotReset = false; 069 } 070 } 071 }; 072 } 073 074 public void doNotReset() { 075 this.doNotReset = true; 076 } 077}