BuilderFuzzer.java

// Copyright 2023 Google LLC
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import org.apache.commons.lang3.builder.Builder;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.DiffBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ReflectionDiffBuilder;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/** This fuzzer targets the methods of the classes in the buidler package */
public class BuilderFuzzer {
  private static final ToStringStyle[] styles = {
    ToStringStyle.DEFAULT_STYLE, ToStringStyle.JSON_STYLE,
    ToStringStyle.MULTI_LINE_STYLE, ToStringStyle.NO_CLASS_NAME_STYLE,
    ToStringStyle.NO_FIELD_NAMES_STYLE, ToStringStyle.SHORT_PREFIX_STYLE,
    ToStringStyle.SIMPLE_STYLE
  };
  private static CompareToBuilder compareTo;
  private static DiffBuilder diff;
  private static EqualsBuilder equals;
  private static HashCodeBuilder hashCode;
  private static ReflectionDiffBuilder reflectionDiff;
  private static ReflectionToStringBuilder reflectionToString;

  public static void fuzzerTestOneInput(FuzzedDataProvider data) {
    try {
      Builder builder = null;
      ToStringStyle styleChoice = data.pickValue(styles);
      Integer choice = data.consumeInt(1, 10);
      Object obj1 = getRandomObject(data);
      Object obj2 = getRandomObject(data);

      initializeBuilder(obj1, obj2, styleChoice);

      switch (choice) {
        case 1:
          CompareToBuilder.reflectionCompare(obj1, obj2);
          break;
        case 2:
          builder = compareTo.append(Object.class.cast(obj1), Object.class.cast(obj2));
          break;
        case 3:
          builder =
              diff.append(
                  data.consumeRemainingAsString(),
                  Object.class.cast(obj1),
                  Object.class.cast(obj2));
          break;
        case 4:
          EqualsBuilder.reflectionEquals(obj1, obj2, data.consumeBoolean());
          break;
        case 5:
          builder = equals.append(Object.class.cast(obj1), Object.class.cast(obj2));
          break;
        case 6:
          HashCodeBuilder.reflectionHashCode(obj1, data.consumeBoolean());
          HashCodeBuilder.reflectionHashCode(obj2, data.consumeBoolean());
          break;
        case 7:
          builder = hashCode.append(Object.class.cast(obj1)).append(Object.class.cast(obj2));
          break;
        case 8:
          builder = reflectionDiff;
          break;
        case 9:
          ReflectionToStringBuilder.toString(obj1, styleChoice);
          ReflectionToStringBuilder.toString(obj2, styleChoice);
          break;
        case 10:
          builder = reflectionToString.reflectionAppendArray(obj1).reflectionAppendArray(obj2);
          break;
      }

      if (builder != null) {
        builder.build();
      }
    } catch (IllegalArgumentException | ClassCastException e) {
      // Known exception
    }
  }

  private static void initializeBuilder(Object obj1, Object obj2, ToStringStyle style) {
    compareTo = new CompareToBuilder();
    diff = new DiffBuilder(obj1, obj2, style);
    equals = new EqualsBuilder();
    hashCode = new HashCodeBuilder();
    reflectionDiff = new ReflectionDiffBuilder(obj1, obj2, style);
    reflectionToString = new ReflectionToStringBuilder(obj1, style);
  }

  private static Object getRandomObject(FuzzedDataProvider data) {
    Object obj = null;

    switch (data.consumeInt(1, 18)) {
      case 1:
        obj = data.consumeBoolean();
        break;
      case 2:
        obj = data.consumeBooleans(data.remainingBytes());
        break;
      case 3:
        obj = data.consumeBytes(data.remainingBytes());
        break;
      case 4:
        obj = data.consumeByte();
        break;
      case 5:
        obj = data.consumeChar();
        break;
      case 6:
        obj = data.consumeString(data.remainingBytes()).toCharArray();
        break;
      case 7:
        obj = data.consumeDouble();
        break;
      case 8:
        double[] doubleArray = new double[data.consumeInt(1, 5)];
        for (Integer i = 0; i < doubleArray.length; i++) {
          doubleArray[i] = data.consumeDouble();
        }
        obj = doubleArray;
        break;
      case 9:
        obj = data.consumeFloat();
        break;
      case 10:
        float[] floatArray = new float[data.consumeInt(1, 5)];
        for (Integer i = 0; i < floatArray.length; i++) {
          floatArray[i] = data.consumeFloat();
        }
        obj = floatArray;
        break;
      case 11:
        obj = data.consumeInt();
        break;
      case 12:
        obj = data.consumeInts(data.remainingBytes());
        break;
      case 13:
        obj = data.consumeLong();
        break;
      case 14:
        obj = data.consumeLongs(data.remainingBytes());
        break;
      case 15:
        obj = data.consumeShort();
        break;
      case 16:
        obj = data.consumeShorts(data.remainingBytes());
        break;
      case 17:
        obj = data.consumeString(data.remainingBytes());
        break;
      case 18:
        String[] strArray = new String[data.consumeInt(1, 5)];
        for (Integer i = 0; i < strArray.length; i++) {
          strArray[i] = data.consumeString(data.remainingBytes());
        }
        obj = strArray;
        break;
    }

    return obj;
  }
}