chromium/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ModuleFactoryOverrides.java

// Copyright 2018 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.chrome.browser.dependency_injection;

import androidx.annotation.Nullable;

import java.util.HashMap;
import java.util.Map;

/**
 * This class is for overriding factories of Modules in tests. See also ModuleOverridesRule.
 *
 * The chosen approach for substituting dagger bindings in integrational tests is to override
 * Modules, without touching Components. Substituting the entire structure of Components in each
 * suite of tests is unreasonably cumbersome.
 *
 * Overriding the Modules themselves would not be a good enough solution in general,
 * because modules have parameters known only at creation time (such as parameters extracted from
 * Intent extras in an activity). Plus, in some tests there might be multiple instances of Modules
 * of the same type. Thus, instead of Modules we need to override factories of Modules.
 *
 * The factory overrides are set by tests as the first step of initialization. The production code
 * then calls {@link #getOverrideFor} to obtain the overridden factory, if any.
 *
 * Note that for unit tests you don't need to use this: create an instance of tested class directly
 * with "new", and pass the mocks.
 */
public class ModuleFactoryOverrides {
    @Nullable private static Map<Class<?>, Object> sOverrides;

    /** Override the Module factory of specified type. */
    static void setOverride(Class<?> factoryClass, Object override) {
        if (sOverrides == null) {
            sOverrides = new HashMap<>();
        }
        sOverrides.put(factoryClass, override);
    }

    /** Clear all overrides */
    static void clearOverrides() {
        sOverrides = null;
    }

    /** Returns an overridden factory for the given factory class, if present. */
    @Nullable
    @SuppressWarnings("unchecked") // Unsafe cast occurs only in test environment
    public static <T> T getOverrideFor(Class<T> factoryClass) {
        if (sOverrides == null) {
            return null;
        }
        Object overriddenFactory = sOverrides.get(factoryClass);
        if (overriddenFactory != null) {
            return (T) overriddenFactory;
        }
        return null;
    }

    private ModuleFactoryOverrides() {}
}