chromium/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferencesContext.java

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.base.test.util;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import androidx.annotation.GuardedBy;

import org.chromium.base.Log;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/** ContextWrapper that causes SharedPreferences to not persist to disk. */
public class InMemorySharedPreferencesContext extends ApplicationContextWrapper {
    private static final String TAG = "InMemorySharedPrefs";

    // Ordered map so that log order is consistent.
    @GuardedBy("mSharedPreferences")
    protected final Map<String, InMemorySharedPreferences> mSharedPreferences = new TreeMap<>();

    public InMemorySharedPreferencesContext(Context base) {
        super(base);
    }

    @Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        // Pass through multidex prefs to avoid excessive multidex extraction on KitKat.
        if (name.endsWith("multidex.version")) {
            return getBaseContext().getSharedPreferences(name, mode);
        }
        synchronized (mSharedPreferences) {
            if (!mSharedPreferences.containsKey(name)) {
                mSharedPreferences.put(name, new InMemorySharedPreferences());
            }
            return mSharedPreferences.get(name);
        }
    }

    public void resetSharedPreferences() {
        synchronized (mSharedPreferences) {
            int beforeSize = size();
            // Clear each instance rather than the map in case there are any registered listeners
            // or cached references to them.
            for (var entry : mSharedPreferences.entrySet()) {
                String name = entry.getKey();
                InMemorySharedPreferences prefs = entry.getValue();
                Set<String> lines = prefs.toDebugLines();
                prefs.reset();
                if (!lines.isEmpty()) {
                    String joined = TextUtils.join("\n  ", lines);
                    Log.i(TAG, "Cleared all shared prefs from %s:\n  %s", name, joined);
                }
            }
            int afterSize = size();
            Log.i(TAG, "Cleared %s shared prefs via test runner.", beforeSize - afterSize);
        }
    }

    /**
     * Creates a copy of all shared preferences, which can be restored via
     * restoreSharedPreferencesSnapshot().
     */
    public void createSharedPreferencesSnapshot() {
        synchronized (mSharedPreferences) {
            // Clear each instance rather than the map in case there are any registered listeners
            // or cached references to them.
            for (var prefs : mSharedPreferences.values()) {
                prefs.createSnapshot();
            }
            int numFiles = mSharedPreferences.size();
            Log.i(TAG, "Snapshotted shared prefs (%s files, %s total entries)", numFiles, size());
        }
    }

    /**
     * Restores shared preferences to their state the last time createSharedPreferencesSnapshot()
     * was called.
     */
    public void restoreSharedPreferencesSnapshot() {
        synchronized (mSharedPreferences) {
            int beforeSize = size();
            // Clear each instance rather than the map in case there are any registered listeners
            // or cached references to them.
            for (var entry : mSharedPreferences.entrySet()) {
                String name = entry.getKey();
                InMemorySharedPreferences prefs = entry.getValue();
                prefs.restoreSnapshot(name);
            }
            int afterSize = size();
            Log.i(TAG, "Cleared %s shared prefs via test runner.", afterSize - beforeSize);
        }
    }

    @GuardedBy("mSharedPreferences")
    private int size() {
        int ret = 0;
        for (var prefs : mSharedPreferences.values()) {
            ret += prefs.size();
        }
        return ret;
    }
}