blob: ba8fe723fa5f90fa1d94ed0f231fc0d2b3fdab22 [file] [log] [blame]
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.entities;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
/**
* Entity detailing the result of evaluating a predicate.
*
* <p>Example - branch:refs/heads/foo and has:unresolved
*
* <p>The above predicate is an "And" predicate having two child predicates:
*
* <ul>
* <li>branch:refs/heads/foo
* <li>has:unresolved
* </ul>
*
* <p>Each child predicate as well as the parent contains the result of its evaluation.
*/
@AutoValue
public abstract class PredicateResult {
abstract ImmutableList<PredicateResult> childPredicateResults();
/** We only set this field for leaf predicates. */
public abstract String predicateString();
/** true if the predicate is passing for a given change. */
public abstract boolean status();
/**
* An explanation of the predicate result.
*
* <p>This is used to provide more information about complex atoms, which may otherwise be opaque
* and hard to debug.
*
* <p>This will be empty for most predicate results and all non-leaf predicates.
*/
public abstract String explanation();
/** Returns a list of leaf predicate results whose {@link PredicateResult#status()} is true. */
public ImmutableList<String> getPassingAtoms() {
return getAtoms(/* status= */ true).stream()
.map(PredicateResult::predicateString)
.collect(ImmutableList.toImmutableList());
}
/** Returns a list of leaf predicate results whose {@link PredicateResult#status()} is false. */
public ImmutableList<String> getFailingAtoms() {
return getAtoms(/* status= */ false).stream()
.map(PredicateResult::predicateString)
.collect(ImmutableList.toImmutableList());
}
public ImmutableMap<String, String> getAtomExplanations() {
return getAtoms().stream()
.collect(
ImmutableMap.toImmutableMap(
PredicateResult::predicateString, PredicateResult::explanation, (a, b) -> a));
}
/** Returns the list of leaf {@link PredicateResult}. */
private ImmutableList<PredicateResult> getAtoms() {
ImmutableList.Builder<PredicateResult> atomsList = ImmutableList.builder();
getAtomsRecursively(atomsList);
return atomsList.build();
}
/**
* Returns the list of leaf {@link PredicateResult} whose {@link #status()} is equal to the {@code
* status} parameter.
*/
private ImmutableList<PredicateResult> getAtoms(boolean status) {
ImmutableList.Builder<PredicateResult> atomsList = ImmutableList.builder();
getAtomsRecursively(atomsList, status);
return atomsList.build();
}
private void getAtomsRecursively(ImmutableList.Builder<PredicateResult> list) {
if (!predicateString().isEmpty()) {
list.add(this);
return;
}
childPredicateResults().forEach(c -> c.getAtomsRecursively(list));
}
private void getAtomsRecursively(ImmutableList.Builder<PredicateResult> list, boolean status) {
if (!predicateString().isEmpty() && status() == status) {
list.add(this);
return;
}
childPredicateResults().forEach(c -> c.getAtomsRecursively(list, status));
}
public static Builder builder() {
return new AutoValue_PredicateResult.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
protected abstract ImmutableList.Builder<PredicateResult> childPredicateResultsBuilder();
public abstract Builder predicateString(String value);
public abstract Builder status(boolean value);
public abstract Builder explanation(String value);
@CanIgnoreReturnValue
public Builder addChildPredicateResult(PredicateResult result) {
childPredicateResultsBuilder().add(result);
return this;
}
public abstract PredicateResult build();
}
}