1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.compatibility.common.util;
18 
19 import androidx.annotation.NonNull;
20 
21 import org.junit.rules.TestRule;
22 import org.junit.runner.Description;
23 import org.junit.runners.model.Statement;
24 
25 import java.util.Objects;
26 
27 /**
28  * JUnit rule used to restore a state after the test is run.
29  *
30  * <p>It stores the current state before the test, and restores it after the test (if necessary).
31  *
32  * @param <T> value type
33  */
34 public class StateKeeperRule<T> implements TestRule {
35 
36     private final StateManager<T> mStateManager;
37 
38     /**
39      * Default constructor.
40      *
41      * @param stateManager abstraction used to mange the state.
42      */
StateKeeperRule(@onNull StateManager<T> stateManager)43     public StateKeeperRule(@NonNull StateManager<T> stateManager) {
44         mStateManager = Objects.requireNonNull(stateManager);
45     }
46 
47     /**
48      * Hook for subclasses.
49      */
preEvaluate(@uppressWarnings"unused") Description description)50     protected void preEvaluate(@SuppressWarnings("unused") Description description) {
51     }
52 
53     /**
54      * Hook for subclasses.
55      */
postEvaluate(@uppressWarnings"unused") Description description)56     protected void postEvaluate(@SuppressWarnings("unused") Description description) {
57     }
58 
59     @Override
apply(Statement base, Description description)60     public Statement apply(Statement base, Description description) {
61         return new Statement() {
62 
63             @Override
64             public void evaluate() throws Throwable {
65                 final T previousValue = mStateManager.get();
66                 preEvaluate(description);
67                 try {
68                     base.evaluate();
69                 } finally {
70                     final T currentValue = mStateManager.get();
71                     if (!Objects.equals(previousValue, currentValue)) {
72                         mStateManager.set(previousValue);
73                     }
74                 }
75                 postEvaluate(description);
76             }
77         };
78     }
79 }
80