Back to Repositories

Validating Array Binding Annotations in ButterKnife

This test suite validates the functionality of array binding in ButterKnife, focusing on the @BindArray annotation implementation. It ensures proper handling of TypedArray resources and validates type safety constraints for array bindings.

Test Coverage Overview

The test suite provides comprehensive coverage of the @BindArray annotation functionality.

Key areas tested include:
  • TypedArray resource binding validation
  • Type safety enforcement for array bindings
  • Generated binding code verification
  • Error handling for unsupported array types

Implementation Analysis

The testing approach utilizes JUnit framework with Google’s compile-testing library for annotation processing validation. The tests employ a combination of positive and negative test cases to verify both successful compilation scenarios and proper error handling.

Key patterns include:
  • Compile-time annotation processing verification
  • Generated code structure validation
  • Resource binding implementation checking

Technical Details

Testing tools and configuration:
  • JUnit test framework
  • ButterKnifeProcessor for annotation processing
  • JavaFileObjects for source code manipulation
  • Google Truth assertions for compile-time validation
  • Custom compiler options for processing verification

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through thorough validation of both positive and negative scenarios.

Notable practices include:
  • Explicit error message validation
  • Generated code structure verification
  • Comprehensive type safety checking
  • Clean test organization with clear separation of concerns

jakewharton/butterknife

butterknife-runtime/src/test/java/butterknife/BindArrayTest.java

            
package butterknife;

import butterknife.compiler.ButterKnifeProcessor;
import com.google.testing.compile.JavaFileObjects;
import javax.tools.JavaFileObject;
import org.junit.Test;

import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;

public final class BindArrayTest {
  @Test public void typedArray() throws Exception {
    JavaFileObject source = JavaFileObjects.forSourceString("test.Test", ""
        + "package test;\n"
        + "import butterknife.BindArray;\n"
        + "import android.content.res.TypedArray;\n"
        + "public class Test {\n"
        + "  @BindArray(1) TypedArray one;\n"
        + "}"
    );

    JavaFileObject bindingSource = JavaFileObjects.forSourceString("test/Test_ViewBinding", ""
        + "// Generated code from Butter Knife. Do not modify!\n"
        + "package test;\n"
        + "import android.content.Context;\n"
        + "import android.content.res.Resources;\n"
        + "import android.view.View;\n"
        + "import androidx.annotation.CallSuper;\n"
        + "import androidx.annotation.UiThread;\n"
        + "import butterknife.Unbinder;\n"
        + "import java.lang.Deprecated;\n"
        + "import java.lang.Override;\n"
        + "import java.lang.SuppressWarnings;\n"
        + "public class Test_ViewBinding implements Unbinder {\n"
        + "  /**\n"
        + "   * @deprecated Use {@link #Test_ViewBinding(Test, Context)} for direct creation.\n"
        + "   *     Only present for runtime invocation through {@code ButterKnife.bind()}.\n"
        + "   */\n"
        + "  @Deprecated\n"
        + "  @UiThread\n"
        + "  public Test_ViewBinding(Test target, View source) {\n"
        + "    this(target, source.getContext());\n"
        + "  }\n"
        + "  @UiThread\n"
        + "  @SuppressWarnings(\"ResourceType\")\n"
        + "  public Test_ViewBinding(Test target, Context context) {\n"
        + "    Resources res = context.getResources();\n"
        + "    target.one = res.obtainTypedArray(1);\n"
        + "  }\n"
        + "  @Override\n"
        + "  @CallSuper\n"
        + "  public void unbind() {\n"
        + "  }\n"
        + "}"
    );

    assertAbout(javaSource()).that(source)
        .withCompilerOptions("-Xlint:-processing")
        .processedWith(new ButterKnifeProcessor())
        .compilesWithoutWarnings()
        .and()
        .generatesSources(bindingSource);
  }

  @Test public void typeMustBeSupported() {
    JavaFileObject source = JavaFileObjects.forSourceString("test.Test", ""
        + "package test;\n"
        + "import butterknife.BindArray;\n"
        + "public class Test {\n"
        + "  @BindArray(1) String one;\n"
        + "}"
    );

    assertAbout(javaSource()).that(source)
        .processedWith(new ButterKnifeProcessor())
        .failsToCompile()
        .withErrorContaining(
            "@BindArray field type must be one of: String[], int[], CharSequence[], "
                + "android.content.res.TypedArray. (test.Test.one)")
        .in(source).onLine(4);
  }
}