package org.ovirt.engine.ui.common.binding; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner.Silent; import org.ovirt.engine.ui.common.idhandler.WithElementId; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.HelpInfo; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JField; @RunWith(Silent.class) public class ElementIdTypeParserTest { @Mock private TreeLogger logger; @Mock private JClassType interfaceType; @Mock private JClassType ownerType; @Mock private JField ownerTypeField1; @Mock private JField ownerTypeField2; @Mock private JField ownerTypeParentField; @Mock private JField ownerTypeParentFieldTypeSubField1; @Mock private JClassType ownerTypeParentFieldTypeSubField1Type; @Mock private JField ownerTypeParentFieldTypeSubField2; @Mock private JField field; private ElementIdTypeParser tested; @Before public void setUp() throws UnableToCompleteException { when(logger.branch(nullable(TreeLogger.Type.class), anyString(), nullable(Throwable.class), nullable(HelpInfo.class))).thenReturn(logger); tested = new ElementIdTypeParser(logger, interfaceType) { @Override JClassType resolveOwnerType(JClassType interfaceToImplement) throws UnableToCompleteException { return ownerType; } }; stubPassingField(field, mock(JClassType.class), "field"); //$NON-NLS-1$ JClassType ownerTypeParent = mock(JClassType.class); Set<? extends JClassType> ownerTypeFlattenedSupertypeHierarchy = new HashSet<>( Arrays.asList(ownerType, ownerTypeParent)); doReturn(ownerTypeFlattenedSupertypeHierarchy).when(ownerType).getFlattenedSupertypeHierarchy(); when(ownerType.getFields()).thenReturn(new JField[] { ownerTypeField1, ownerTypeField2 }); when(ownerTypeParent.getFields()).thenReturn(new JField[] { ownerTypeParentField }); when(ownerType.getName()).thenReturn("OwnerTypeName"); //$NON-NLS-1$ JClassType ownerTypeParentFieldType = mock(JClassType.class, "ownerTypeParentFieldType"); //$NON-NLS-1$ stubPassingField(ownerTypeField1, mock(JClassType.class), "ownerTypeField1"); //$NON-NLS-1$ stubPassingField(ownerTypeField2, mock(JClassType.class), "ownerTypeField2"); //$NON-NLS-1$ stubPassingField(ownerTypeParentField, ownerTypeParentFieldType, "ownerTypeParentField"); //$NON-NLS-1$ Set<? extends JClassType> ownerTypeParentFieldTypeFlattenedSupertypeHierarchy = Collections.singleton(ownerTypeParentFieldType); doReturn(ownerTypeParentFieldTypeFlattenedSupertypeHierarchy).when(ownerTypeParentFieldType) .getFlattenedSupertypeHierarchy(); when(ownerTypeParentFieldType.getFields()).thenReturn(new JField[] { ownerTypeParentFieldTypeSubField1, ownerTypeParentFieldTypeSubField2 }); stubPassingField(ownerTypeParentFieldTypeSubField1, ownerTypeParentFieldTypeSubField1Type, "ownerTypeParentFieldTypeSubField1"); //$NON-NLS-1$ stubPassingField(ownerTypeParentFieldTypeSubField2, mock(JClassType.class), "ownerTypeParentFieldTypeSubField2"); //$NON-NLS-1$ } void stubPassingField(JField field, JClassType fieldType, String fieldName) { WithElementId idAnnotation = mock(WithElementId.class); when(field.isPrivate()).thenReturn(false); when(field.isStatic()).thenReturn(false); when(field.getType()).thenReturn(fieldType); when(field.getName()).thenReturn(fieldName); when(fieldType.isClass()).thenReturn(fieldType); when(field.getAnnotation(WithElementId.class)).thenReturn(idAnnotation); when(idAnnotation.value()).thenReturn(""); //$NON-NLS-1$ when(idAnnotation.processType()).thenReturn(true); } @Test public void processField_private() { when(field.isPrivate()).thenReturn(true); verifyProcessFieldReturns(false); } @Test public void processField_defaultAccess() { when(field.isDefaultAccess()).thenReturn(true); verifyProcessFieldReturns(true); } @Test public void processField_protected() { when(field.isProtected()).thenReturn(true); verifyProcessFieldReturns(true); } @Test public void processField_public() { when(field.isPublic()).thenReturn(true); verifyProcessFieldReturns(true); } @Test public void processField_static() { when(field.isStatic()).thenReturn(true); verifyProcessFieldReturns(false); } @Test public void processField_final() { when(field.isFinal()).thenReturn(true); verifyProcessFieldReturns(true); } @Test public void processField_primitiveType() { JClassType fieldType = mock(JClassType.class); when(field.getType()).thenReturn(fieldType); when(fieldType.isClass()).thenReturn(null); verifyProcessFieldReturns(false); } @Test public void processField_missingIdAnnotation() { when(field.getAnnotation(WithElementId.class)).thenReturn(null); verifyProcessFieldReturns(false); } void verifyProcessFieldReturns(boolean expected) { boolean processField = tested.processField(field); assertThat(processField, is(equalTo(expected))); } @Test public void doParse_defaultBehavior() throws UnableToCompleteException { tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ List<ElementIdStatement> expected = Arrays.asList( getExpectedStatement("ownerTypeParentField", "IdPrefix_ownerTypeParentField"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeParentField.ownerTypeParentFieldTypeSubField1", //$NON-NLS-1$ "IdPrefix_ownerTypeParentField_ownerTypeParentFieldTypeSubField1"), //$NON-NLS-1$ getExpectedStatement("ownerTypeParentField.ownerTypeParentFieldTypeSubField2", //$NON-NLS-1$ "IdPrefix_ownerTypeParentField_ownerTypeParentFieldTypeSubField2"), //$NON-NLS-1$ getExpectedStatement("ownerTypeField1", "IdPrefix_ownerTypeField1"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField2", "IdPrefix_ownerTypeField2")); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(tested.statements.size(), is(equalTo(expected.size()))); assertThat(tested.statements.containsAll(expected), is(equalTo(true))); } @Test public void doParse_customFieldId() throws UnableToCompleteException { stubFieldIdAnnotation(ownerTypeParentField, "ownerTypeParentFieldCustomId", true); //$NON-NLS-1$ tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(tested.statements.contains(getExpectedStatement( "ownerTypeParentField", "IdPrefix_ownerTypeParentFieldCustomId")), is(equalTo(true))); //$NON-NLS-1$ //$NON-NLS-2$ } @Test(expected = UnableToCompleteException.class) public void doParse_duplicateFieldIds() throws UnableToCompleteException { stubFieldIdAnnotation(ownerTypeParentFieldTypeSubField1, "customId", true); //$NON-NLS-1$ stubFieldIdAnnotation(ownerTypeParentFieldTypeSubField2, "customId", true); //$NON-NLS-1$ tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void doParse_limitedFieldTypeRecursion() throws UnableToCompleteException { stubFieldIdAnnotation(ownerTypeParentField, "", false); //$NON-NLS-1$ tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ List<ElementIdStatement> expected = Arrays.asList( getExpectedStatement("ownerTypeParentField", "IdPrefix_ownerTypeParentField"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField1", "IdPrefix_ownerTypeField1"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField2", "IdPrefix_ownerTypeField2")); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(tested.statements.size(), is(equalTo(expected.size()))); assertThat(tested.statements.containsAll(expected), is(equalTo(true))); } @Test(expected = UnableToCompleteException.class) public void doParse_unhandledFieldTypeRecursion() throws UnableToCompleteException { Set<? extends JClassType> ownerTypeParentFieldTypeSubField1TypeFlattenedSupertypeHierarchy = Collections.singleton(ownerTypeParentFieldTypeSubField1Type); doReturn(ownerTypeParentFieldTypeSubField1TypeFlattenedSupertypeHierarchy) .when(ownerTypeParentFieldTypeSubField1Type).getFlattenedSupertypeHierarchy(); when(ownerTypeParentFieldTypeSubField1Type.getFields()).thenReturn(new JField[] { ownerTypeParentField }); tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ } @Test public void doParse_handledFieldTypeRecursion() throws UnableToCompleteException { Set<? extends JClassType> ownerTypeParentFieldTypeSubField1TypeFlattenedSupertypeHierarchy = Collections.singleton(ownerTypeParentFieldTypeSubField1Type); doReturn(ownerTypeParentFieldTypeSubField1TypeFlattenedSupertypeHierarchy) .when(ownerTypeParentFieldTypeSubField1Type).getFlattenedSupertypeHierarchy(); when(ownerTypeParentFieldTypeSubField1Type.getFields()).thenReturn(new JField[] { ownerTypeParentField }); stubFieldIdAnnotation(ownerTypeParentField, "", false); //$NON-NLS-1$ tested.doParse(ownerType, new ArrayList<JClassType>(), ".", "IdPrefix"); //$NON-NLS-1$ //$NON-NLS-2$ List<ElementIdStatement> expected = Arrays.asList( getExpectedStatement("ownerTypeParentField", "IdPrefix_ownerTypeParentField"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField1", "IdPrefix_ownerTypeField1"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField2", "IdPrefix_ownerTypeField2")); //$NON-NLS-1$ //$NON-NLS-2$ assertThat(tested.statements.size(), is(equalTo(expected.size()))); assertThat(tested.statements.containsAll(expected), is(equalTo(true))); } @Test public void parseStatements_defaultBehavior() throws UnableToCompleteException { tested.parseStatements(); List<ElementIdStatement> expected = Arrays.asList( getExpectedStatement("ownerTypeParentField", "OwnerTypeName_ownerTypeParentField"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeParentField.ownerTypeParentFieldTypeSubField1", //$NON-NLS-1$ "OwnerTypeName_ownerTypeParentField_ownerTypeParentFieldTypeSubField1"), //$NON-NLS-1$ getExpectedStatement("ownerTypeParentField.ownerTypeParentFieldTypeSubField2", //$NON-NLS-1$ "OwnerTypeName_ownerTypeParentField_ownerTypeParentFieldTypeSubField2"), //$NON-NLS-1$ getExpectedStatement("ownerTypeField1", "OwnerTypeName_ownerTypeField1"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement("ownerTypeField2", "OwnerTypeName_ownerTypeField2"), //$NON-NLS-1$ //$NON-NLS-2$ getExpectedStatement(null, "OwnerTypeName") //$NON-NLS-1$ ); assertThat(tested.statements.size(), is(equalTo(expected.size()))); assertThat(tested.statements.containsAll(expected), is(equalTo(true))); } void stubFieldIdAnnotation(JField field, String fieldId, boolean processType) { WithElementId idAnnotation = mock(WithElementId.class); when(field.getAnnotation(WithElementId.class)).thenReturn(idAnnotation); when(idAnnotation.value()).thenReturn(fieldId); when(idAnnotation.processType()).thenReturn(processType); } ElementIdStatement getExpectedStatement(String pathToField, String elementId) { String fieldExpression = ElementIdHandlerGenerator.ElementIdHandler_generateAndSetIds_owner; if (pathToField != null) { fieldExpression += "." + pathToField; //$NON-NLS-1$ } return new ElementIdStatement(fieldExpression, elementId); } }