/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.specmodels.model; import javax.lang.model.element.Modifier; import java.lang.annotation.Annotation; import java.util.List; import com.facebook.litho.annotations.ShouldUpdate; import com.facebook.litho.specmodels.internal.ImmutableList; import com.facebook.litho.testing.specmodels.TestMethodParamModel; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; import com.squareup.javapoet.WildcardTypeName; import org.junit.Before; import org.junit.Test; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Tests {@link PureRenderValidation} */ public class PureRenderValidationTest { public interface PureRenderSpecModel extends SpecModel, HasPureRender {} private final PureRenderSpecModel mSpecModel = mock(PureRenderSpecModel.class); private final PropModel mPropModel = mock(PropModel.class); private final MethodParamModel mMethodParamModel = mock(MethodParamModel.class); private final Object mDelegateMethodRepresentedObject1 = new Object(); private final Object mParamRepresentedObject1 = new Object(); private final Object mParamRepresentedObject2 = new Object(); private final Object mParamRepresentedObject3 = new Object(); private final Object mParamRepresentedObject4 = new Object(); private DelegateMethodModel mDelegateMethod; @Before public void setup() { when(mSpecModel.isPureRender()).thenReturn(true); when(mSpecModel.getProps()).thenReturn(ImmutableList.of(mPropModel)); mDelegateMethod = new DelegateMethodModel( ImmutableList.<Annotation>of(new Annotation() { @Override public Class<? extends Annotation> annotationType() { return ShouldUpdate.class; } }), ImmutableList.<Modifier>of(), "method", TypeName.BOOLEAN, ImmutableList.<MethodParamModel>of(), mDelegateMethodRepresentedObject1); when(mSpecModel.getDelegateMethods()).thenReturn(ImmutableList.of(mDelegateMethod)); } @Test public void testShouldUpdateDefinedButNotPureRender() { when(mSpecModel.isPureRender()).thenReturn(false); List<SpecModelValidationError> validationErrors = PureRenderValidation.validate(mSpecModel); assertThat(validationErrors).hasSize(1); assertThat(validationErrors.get(0).element).isEqualTo(mDelegateMethodRepresentedObject1); assertThat(validationErrors.get(0).message).isEqualTo( "Specs defining a method annotated with @ShouldUpdate should also set " + "isPureRender = true in the top-level spec annotation."); } @Test public void testNoPropWithSameName() { when(mPropModel.getName()).thenReturn("name1"); when(mMethodParamModel.getName()).thenReturn("name2"); when(mMethodParamModel.getRepresentedObject()).thenReturn(mParamRepresentedObject2); mDelegateMethod = new DelegateMethodModel( mDelegateMethod.annotations, mDelegateMethod.modifiers, mDelegateMethod.name, mDelegateMethod.returnType, ImmutableList.of(mMethodParamModel), mDelegateMethod.representedObject); when(mSpecModel.getDelegateMethods()).thenReturn(ImmutableList.of(mDelegateMethod)); List<SpecModelValidationError> validationErrors = PureRenderValidation.validate(mSpecModel); assertThat(validationErrors).hasSize(1); assertThat(validationErrors.get(0).element).isEqualTo(mParamRepresentedObject2); assertThat(validationErrors.get(0).message).isEqualTo( "Names of parameters for a method annotated with @ShouldUpdate should match a " + "declared Prop of the same name."); } @Test public void testShouldUpdateParamTypeNotValid() { when(mPropModel.getName()).thenReturn("name"); when(mPropModel.getType()).thenReturn(TypeName.INT); MethodParamModel methodParamModel1 = TestMethodParamModel.newBuilder() .type(TypeName.INT) .name("name") .representedObject(mParamRepresentedObject1) .build(); MethodParamModel methodParamModel2 = TestMethodParamModel.newBuilder() .type(ParameterizedTypeName.get( ClassName.bestGuess("com.facebook.litho.Output"), TypeVariableName.get("T"))) .name("name") .representedObject(mParamRepresentedObject2) .build(); MethodParamModel methodParamModel3 = TestMethodParamModel.newBuilder() .type(ParameterizedTypeName.get( ClassNames.DIFF, TypeVariableName.get("S"), TypeVariableName.get("T"))) .name("name") .representedObject(mParamRepresentedObject3) .build(); MethodParamModel methodParamModel4 = TestMethodParamModel.newBuilder() .type(ParameterizedTypeName.get( ClassNames.DIFF, WildcardTypeName.subtypeOf(ClassName.bestGuess("java.lang.Object")))) .name("name") .representedObject(mParamRepresentedObject4) .build(); MethodParamModel methodParamModel5 = TestMethodParamModel.newBuilder() .type(ParameterizedTypeName.get( ClassNames.DIFF, ClassName.get("java.lang", "Integer"))) .name("name") .build(); mDelegateMethod = new DelegateMethodModel( mDelegateMethod.annotations, mDelegateMethod.modifiers, mDelegateMethod.name, mDelegateMethod.returnType, ImmutableList.of( methodParamModel1, methodParamModel2, methodParamModel3, methodParamModel4, methodParamModel5), mDelegateMethodRepresentedObject1); when(mSpecModel.getDelegateMethods()).thenReturn(ImmutableList.of(mDelegateMethod)); List<SpecModelValidationError> validationErrors = PureRenderValidation.validate(mSpecModel); assertThat(validationErrors).hasSize(4); assertThat(validationErrors.get(0).element).isSameAs(mParamRepresentedObject1); assertThat(validationErrors.get(0).message) .isEqualTo("Types of parameters for a method annotated with @ShouldUpdate should be " + "Diff<T>, where T is the type of the declared Prop of the same name."); assertThat(validationErrors.get(1).element).isSameAs(mParamRepresentedObject2); assertThat(validationErrors.get(1).message) .isEqualTo("Types of parameters for a method annotated with @ShouldUpdate should be " + "Diff<T>, where T is the type of the declared Prop of the same name."); assertThat(validationErrors.get(2).element).isSameAs(mParamRepresentedObject3); assertThat(validationErrors.get(2).message) .isEqualTo("Types of parameters for a method annotated with @ShouldUpdate should be " + "Diff<T>, where T is the type of the declared Prop of the same name."); assertThat(validationErrors.get(3).element).isSameAs(mParamRepresentedObject4); assertThat(validationErrors.get(3).message) .isEqualTo("Types of parameters for a method annotated with @ShouldUpdate should be " + "Diff<T>, where T is the type of the declared Prop of the same name."); } }