chromium/base/test/android/javatests/src/org/chromium/base/test/transit/ConditionStatus.java

// Copyright 2024 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.transit;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;

import org.chromium.base.TimeUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * The return value of {@link Condition#checkWithSuppliers()}.
 *
 * <p>Includes whether the condition is fulfilled, an optional message and the timestamp of the
 * check.
 */
public class ConditionStatus {

    private static final int TRUNCATE_STATUS_UPDATE = 300;

    /** Lifecycle phases of ConditionalState. */
    @IntDef({
        ConditionStatus.Status.NOT_FULFILLED,
        ConditionStatus.Status.FULFILLED,
        ConditionStatus.Status.ERROR,
        ConditionStatus.Status.AWAITING
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Status {
        int NOT_FULFILLED = 0;
        int FULFILLED = 1;
        int ERROR = 2;
        int AWAITING = 3;
    }

    private final long mTimestamp;
    private final @Status int mStatus;
    private @Nullable String mMessage;

    ConditionStatus(@Status int status, @Nullable String message) {
        mTimestamp = TimeUtils.currentTimeMillis();
        mStatus = status;
        if (message != null) {
            if (message.length() > TRUNCATE_STATUS_UPDATE) {
                mMessage = message.substring(0, TRUNCATE_STATUS_UPDATE);
            } else {
                mMessage = message;
            }
        }
    }

    public boolean isFulfilled() {
        return mStatus == Status.FULFILLED;
    }

    public boolean isError() {
        return mStatus == Status.ERROR;
    }

    public boolean isAwaiting() {
        return mStatus == Status.AWAITING;
    }

    public @Status int getStatus() {
        return mStatus;
    }

    public @Nullable String getMessage() {
        return mMessage;
    }

    public long getTimestamp() {
        return mTimestamp;
    }

    void amendMessage(String otherMessage) {
        if (mMessage != null) {
            mMessage = mMessage + "  " + otherMessage;
        } else {
            mMessage = otherMessage;
        }
    }

    String getMessageAsGate() {
        StringBuilder fullMessage = new StringBuilder();
        fullMessage.append("<Gate: ");
        String statusMessage =
                switch (mStatus) {
                    case Status.FULFILLED -> "REQUIRED";
                    case Status.NOT_FULFILLED -> "NOT REQ";
                    case Status.ERROR -> "ERROR";
                    case Status.AWAITING -> "AWAITING";
                    default -> throw new IllegalStateException();
                };
        fullMessage.append(statusMessage);
        if (mMessage != null) {
            fullMessage.append(" | ");
            fullMessage.append(mMessage);
        }
        fullMessage.append(">");
        return fullMessage.toString();
    }

    /**
     * Create a {@link ConditionStatusWithResult} to return a status with a result from {@link
     * ConditionWithResult#resolveWithSuppliers()}.
     *
     * <p>All statuses exception AWAITING can return a result.
     */
    public <T> ConditionStatusWithResult<T> withResult(T result) {
        assert mStatus != Status.AWAITING;
        return new ConditionStatusWithResult<>(this, result);
    }

    /**
     * Create a {@link ConditionStatusWithResult} to return a status without a result from {@link
     * ConditionWithResult#resolveWithSuppliers()}.
     */
    public <T> ConditionStatusWithResult<T> withoutResult() {
        return new ConditionStatusWithResult<>(this, /* result= */ null);
    }
}