/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo Framework
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.view.internal.states.components;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.springframework.test.util.ReflectionTestUtils.setField;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qcadoo.localization.api.TranslationService;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.EntityMessagesHolder;
import com.qcadoo.model.api.EntityOpResult;
import com.qcadoo.model.api.FieldDefinition;
import com.qcadoo.model.api.validators.ErrorMessage;
import com.qcadoo.model.internal.DefaultEntity;
import com.qcadoo.model.internal.ExpressionServiceImpl;
import com.qcadoo.model.internal.types.StringType;
import com.qcadoo.security.api.SecurityRolesService;
import com.qcadoo.view.api.ViewDefinitionState;
import com.qcadoo.view.internal.api.InternalComponentState;
import com.qcadoo.view.internal.components.FieldComponentPattern;
import com.qcadoo.view.internal.components.FieldComponentState;
import com.qcadoo.view.internal.components.form.FormComponentPattern;
import com.qcadoo.view.internal.components.form.FormComponentState;
import com.qcadoo.view.internal.states.AbstractComponentState;
import com.qcadoo.view.internal.states.AbstractStateTest;
public class FormComponentStateTest extends AbstractStateTest {
private Entity entity;
private ViewDefinitionState viewDefinitionState;
private FieldComponentState name;
private FormComponentState form;
private DataDefinition dataDefinition;
private FieldDefinition fieldDefinition;
private TranslationService translationService;
private ApplicationContext applicationContext;
@Before
public void init() throws Exception {
entity = mock(Entity.class);
given(entity.getField("name")).willReturn("text");
viewDefinitionState = mock(ViewDefinitionState.class);
translationService = mock(TranslationService.class);
fieldDefinition = mock(FieldDefinition.class);
given(fieldDefinition.getType()).willReturn(new StringType());
given(fieldDefinition.getName()).willReturn("name");
dataDefinition = mock(DataDefinition.class, RETURNS_DEEP_STUBS);
given(dataDefinition.get(12L)).willReturn(null);
given(dataDefinition.get(13L)).willReturn(entity);
given(dataDefinition.getPluginIdentifier()).willReturn("plugin");
given(dataDefinition.getName()).willReturn("name");
given(dataDefinition.getField("name")).willReturn(fieldDefinition);
given(dataDefinition.delete(any(Long.class))).willReturn(EntityOpResult.successfull());
given(dataDefinition.create(anyLong())).willAnswer(new Answer<Entity>() {
@Override
public Entity answer(final InvocationOnMock invocation) throws Throwable {
Long id = (Long) invocation.getArguments()[0];
return new DefaultEntity(dataDefinition, id);
}
});
FieldComponentPattern namePattern = mock(FieldComponentPattern.class);
given(namePattern.isRequired()).willReturn(false);
given(namePattern.isPersistent()).willReturn(true);
name = new FieldComponentState(namePattern);
name.setTranslationService(translationService);
name.setName("name");
name.initialize(new JSONObject(), Locale.ENGLISH);
FormComponentPattern pattern = mock(FormComponentPattern.class);
given(pattern.getExpressionNew()).willReturn(null);
given(pattern.getExpressionEdit()).willReturn("'static expression'");
applicationContext = mock(ApplicationContext.class);
setField(pattern, "applicationContext", applicationContext);
SecurityRolesService securityRolesService = mock(SecurityRolesService.class);
given(applicationContext.getBean(SecurityRolesService.class)).willReturn(securityRolesService);
form = new FormComponentState(pattern);
form.setDataDefinition(dataDefinition);
form.setTranslationService(translationService);
form.addFieldEntityIdChangeListener("name", name);
form.initialize(new JSONObject(ImmutableMap.of("components", new JSONObject())), Locale.ENGLISH);
new ExpressionServiceImpl().init();
}
@Test
public void shouldInitialeFormWithEntityId() throws Exception {
// given
FormComponentPattern pattern = mock(FormComponentPattern.class);
given(pattern.getExpressionNew()).willReturn(null);
given(pattern.getExpressionEdit()).willReturn(null);
setField(pattern, "applicationContext", applicationContext);
InternalComponentState componentState = new FormComponentState(pattern);
JSONObject json = new JSONObject();
JSONObject jsonContent = new JSONObject();
jsonContent.put(FormComponentState.JSON_ENTITY_ID, 13L);
json.put(AbstractComponentState.JSON_CONTENT, jsonContent);
JSONObject jsonChildren = new JSONObject();
json.put(AbstractComponentState.JSON_CHILDREN, jsonChildren);
// when
componentState.initialize(json, Locale.ENGLISH);
// then
assertEquals(13L, componentState.getFieldValue());
}
@Test
public void shouldInitialeFormWithNullEntityId() throws Exception {
// given
FormComponentPattern pattern = mock(FormComponentPattern.class);
given(pattern.getExpressionNew()).willReturn(null);
given(pattern.getExpressionEdit()).willReturn(null);
setField(pattern, "applicationContext", applicationContext);
InternalComponentState componentState = new FormComponentState(pattern);
JSONObject json = new JSONObject();
JSONObject jsonContent = new JSONObject();
jsonContent.put(FormComponentState.JSON_ENTITY_ID, (String) null);
json.put(AbstractComponentState.JSON_CONTENT, jsonContent);
JSONObject jsonChildren = new JSONObject();
json.put(AbstractComponentState.JSON_CHILDREN, jsonChildren);
// when
componentState.initialize(json, Locale.ENGLISH);
// then
assertNull(componentState.getFieldValue());
}
@Test
public void shouldRenderFormEntityId() throws Exception {
// given
TranslationService translationService = mock(TranslationService.class);
DataDefinition dataDefinition = mock(DataDefinition.class);
FormComponentPattern pattern = mock(FormComponentPattern.class);
given(pattern.getExpressionNew()).willReturn(null);
given(pattern.getExpressionEdit()).willReturn("2");
setField(pattern, "applicationContext", applicationContext);
AbstractComponentState componentState = new FormComponentState(pattern);
componentState.setTranslationService(translationService);
componentState.setDataDefinition(dataDefinition);
componentState.setFieldValue(13L);
componentState.initialize(new JSONObject(ImmutableMap.of("components", new JSONObject())), Locale.ENGLISH);
// when
JSONObject json = componentState.render();
// then
assertEquals(13L, json.getJSONObject(AbstractComponentState.JSON_CONTENT).getLong(FormComponentState.JSON_ENTITY_ID));
}
@Test
public void shouldHaveMessageIfEntityIsNotExistsAndEntityIdIsNotNull() throws Exception {
// given
form.setFieldValue(12L);
given(translationService.translate(eq("null.entityNotFound"), eq("qcadooView.message.entityNotFound"), any(Locale.class)))
.willReturn("translated entityNotFound");
// when
form.performEvent(viewDefinitionState, "initialize", new String[0]);
// then
assertFalse(form.isValid());
assertTrue(form.render().toString().contains("translated entityNotFound"));
}
@Test
public void shouldClearFormIfEntityIsNotExistsAndEntityIdIsNull() throws Exception {
// given
form.setFieldValue(null);
// when
form.performEvent(viewDefinitionState, "initialize", new String[0]);
// then
assertNull(form.getFieldValue());
}
@Test
public void shouldResetForm() throws Exception {
// given
form.setFieldValue(13L);
// when
form.performEvent(viewDefinitionState, "reset", new String[0]);
// then
assertEquals("text", name.getFieldValue());
}
@Test
public void shouldClearFormEntity() throws Exception {
// given
form.setFieldValue(13L);
// when
form.performEvent(viewDefinitionState, "clear", new String[0]);
// then
assertNull(name.getFieldValue());
assertNull(form.getFieldValue());
}
@Test
public void shouldDeleteFormEntity() throws Exception {
// given
name.setFieldValue("text");
form.setFieldValue(13L);
// when
form.performEvent(viewDefinitionState, "delete", new String[0]);
// then
assertNull(name.getFieldValue());
verify(dataDefinition).delete(13L);
assertNull(form.getFieldValue());
}
@Test
public void shouldNotDeleteFormEntity() throws Exception {
// given
EntityMessagesHolder messagesHolder = mock(EntityMessagesHolder.class);
final String message = "some.message";
ErrorMessage errorMessage = new ErrorMessage(message);
given(messagesHolder.getGlobalErrors()).willReturn(Lists.newArrayList(errorMessage));
Map<String, ErrorMessage> fieldErrors = Maps.newHashMap();
fieldErrors.put("name", errorMessage);
given(messagesHolder.getErrors()).willReturn(fieldErrors);
EntityOpResult result = EntityOpResult.failure(messagesHolder);
given(dataDefinition.delete(13L)).willReturn(result);
name.setFieldValue("text");
form.setFieldValue(13L);
// when
form.performEvent(viewDefinitionState, "delete", new String[0]);
// then
assertNotNull(name.getFieldValue());
verify(dataDefinition).delete(13L);
assertEquals(13L, form.getFieldValue());
}
@Test
public void shouldSaveFormEntity() throws Exception {
// given
Entity entity = new DefaultEntity(dataDefinition, null, Collections.singletonMap("name", (Object) "text"));
Entity savedEntity = new DefaultEntity(dataDefinition, 13L, Collections.singletonMap("name", (Object) "text2"));
given(dataDefinition.create(null)).willReturn(new DefaultEntity(dataDefinition));
given(dataDefinition.save(eq(entity))).willReturn(savedEntity);
name.setFieldValue("text");
form.setFieldValue(null);
// when
form.performEvent(viewDefinitionState, "save", new String[0]);
// then
verify(dataDefinition).save(eq(entity));
assertEquals("text2", name.getFieldValue());
assertEquals(13L, form.getFieldValue());
assertTrue(form.isValid());
}
@Test
public void shouldCopyFormEntity() throws Exception {
// given
Entity copiedEntity = new DefaultEntity(dataDefinition, 14L, Collections.singletonMap("name", (Object) "text(1)"));
given(dataDefinition.copy(13L)).willReturn(Collections.singletonList(copiedEntity));
given(dataDefinition.get(14L)).willReturn(copiedEntity);
name.setFieldValue("text");
form.setFieldValue(13L);
// when
form.performEvent(viewDefinitionState, "copy", new String[0]);
// then
verify(dataDefinition).copy(13L);
verify(dataDefinition).get(14L);
assertEquals("text(1)", name.getFieldValue());
assertEquals(14L, form.getFieldValue());
}
@Test
public void shouldUseContextWhileSaving() throws Exception {
// given
Entity entity = new DefaultEntity(dataDefinition, 13L, Collections.singletonMap("name", (Object) "text2"));
Entity savedEntity = new DefaultEntity(dataDefinition, 13L, Collections.singletonMap("name", (Object) "text2"));
given(dataDefinition.create(13L)).willReturn(new DefaultEntity(dataDefinition, 13L));
given(dataDefinition.save(eq(entity))).willReturn(savedEntity);
given(dataDefinition.getFields().keySet()).willReturn(Collections.singleton("name"));
name.setFieldValue("text");
JSONObject json = new JSONObject();
JSONObject jsonContext = new JSONObject();
jsonContext.put("id", 14L);
jsonContext.put("name", "text2");
JSONObject jsonContent = new JSONObject();
jsonContent.put(FormComponentState.JSON_ENTITY_ID, 13L);
json.put(AbstractComponentState.JSON_CONTEXT, jsonContext);
json.put(AbstractComponentState.JSON_CONTENT, jsonContent);
json.put(AbstractComponentState.JSON_CHILDREN, new JSONObject());
form.initialize(json, Locale.ENGLISH);
// when
form.performEvent(viewDefinitionState, "save", new String[0]);
// then
verify(dataDefinition).save(eq(entity));
assertEquals("text2", name.getFieldValue());
assertEquals(13L, form.getFieldValue());
assertTrue(form.isValid());
}
@Test
public void shouldHaveValidationErrors() throws Exception {
// given
Entity entity = new DefaultEntity(dataDefinition, null, Collections.singletonMap("name", (Object) "text"));
Entity savedEntity = new DefaultEntity(dataDefinition, null, Collections.singletonMap("name", (Object) "text2"));
savedEntity.addGlobalError("global.error");
savedEntity.addError(fieldDefinition, "field.error");
given(translationService.translate(eq("global.error"), any(Locale.class))).willReturn("translated global error");
given(translationService.translate(eq("field.error"), any(Locale.class))).willReturn("translated field error");
given(dataDefinition.create(null)).willReturn(new DefaultEntity(dataDefinition));
given(dataDefinition.save(eq(entity))).willReturn(savedEntity);
name.setFieldValue("text");
form.setFieldValue(null);
// when
form.performEvent(viewDefinitionState, "save", new String[0]);
// then
verify(dataDefinition).save(eq(entity));
assertFalse(form.isValid());
assertTrue(form.render().toString().contains("translated global error"));
}
@Test
public void shouldReturnPersistedEntityWithIncludedFormValues() throws Exception {
// given
Long id = 14L;
String nameFieldName = "name";
String nameFieldFormValue = "new name";
String numberFieldName = "number";
String numberFieldValue = "0003";
Entity formEntity = new DefaultEntity(dataDefinition, id, Maps.<String, Object> newHashMap());
formEntity.setField(nameFieldName, nameFieldFormValue);
Entity alreadyPersistedEntity = new DefaultEntity(dataDefinition, id, Maps.<String, Object> newHashMap());
alreadyPersistedEntity.setField(nameFieldName, "old name value");
alreadyPersistedEntity.setField(numberFieldName, numberFieldValue);
given(dataDefinition.get(id)).willReturn(alreadyPersistedEntity);
form.setEntity(formEntity);
// when
Entity resultEntity = form.getPersistedEntityWithIncludedFormValues();
// then
verify(dataDefinition).get(id);
assertEquals(id, resultEntity.getId());
assertEquals(nameFieldFormValue, resultEntity.getStringField(nameFieldName));
assertEquals(numberFieldValue, resultEntity.getStringField(numberFieldName));
assertEquals(2, resultEntity.getFields().size());
}
@Test
public void shouldReturnEntityWithFormValuesIfEntityWasDeletedByAnotherUser() throws Exception {
// given
Long id = 14L;
String nameFieldName = "name";
String nameFieldFormValue = "new name";
String numberFieldName = "number";
Entity formEntity = new DefaultEntity(dataDefinition, id, Maps.<String, Object> newHashMap());
formEntity.setField(nameFieldName, nameFieldFormValue);
given(dataDefinition.get(id)).willReturn(null);
form.setEntity(formEntity);
// when
Entity resultEntity = form.getPersistedEntityWithIncludedFormValues();
// then
verify(dataDefinition).get(id);
assertEquals(id, resultEntity.getId());
assertEquals(nameFieldFormValue, resultEntity.getStringField(nameFieldName));
assertNull(resultEntity.getStringField(numberFieldName));
assertEquals(1, resultEntity.getFields().size());
}
@Test
public void shouldReturnEntityWithFormValuesIfEntityDoesNotHaveId() throws Exception {
// given
String nameFieldName = "name";
String nameFieldFormValue = "new name";
String numberFieldName = "number";
Entity formEntity = new DefaultEntity(dataDefinition, null, Maps.<String, Object> newHashMap());
formEntity.setField(nameFieldName, nameFieldFormValue);
given(dataDefinition.get(anyLong())).willReturn(null);
form.setEntity(formEntity);
// when
Entity resultEntity = form.getPersistedEntityWithIncludedFormValues();
// then
verify(dataDefinition, never()).get(anyLong());
verify(dataDefinition, never()).get(null);
assertNull(resultEntity.getId());
assertEquals(nameFieldFormValue, resultEntity.getStringField(nameFieldName));
assertNull(resultEntity.getStringField(numberFieldName));
assertEquals(1, resultEntity.getFields().size());
}
@Test
public void shouldReturnEntityWithOnlyFormValues() throws Exception {
// given
String nameFieldName = "name";
String nameFieldFormValue = "new name";
String numberFieldName = "number";
Entity formEntity = new DefaultEntity(dataDefinition, null, Maps.<String, Object> newHashMap());
formEntity.setField(nameFieldName, nameFieldFormValue);
form.setEntity(formEntity);
// when
Entity resultEntity = form.getEntity();
// then
verify(dataDefinition, never()).get(anyLong());
verify(dataDefinition, never()).get(null);
assertNull(resultEntity.getId());
assertEquals(nameFieldFormValue, resultEntity.getStringField(nameFieldName));
assertNull(resultEntity.getStringField(numberFieldName));
assertEquals(1, resultEntity.getFields().size());
}
@Test
public void shouldReturnEntityWithOnlyFormValuesEvenIfEntityIsAlreadyPersisted() throws Exception {
// given
Long id = 14L;
String nameFieldName = "name";
String nameFieldFormValue = "new name";
String numberFieldName = "number";
String numberFieldValue = "0003";
Entity formEntity = new DefaultEntity(dataDefinition, id, Maps.<String, Object> newHashMap());
formEntity.setField(nameFieldName, nameFieldFormValue);
Entity alreadyPersistedEntity = new DefaultEntity(dataDefinition, id, Maps.<String, Object> newHashMap());
alreadyPersistedEntity.setField(nameFieldName, "old name value");
alreadyPersistedEntity.setField(numberFieldName, numberFieldValue);
given(dataDefinition.get(id)).willReturn(alreadyPersistedEntity);
form.setEntity(formEntity);
// when
Entity resultEntity = form.getEntity();
// then
verify(dataDefinition, never()).get(id);
assertEquals(id, resultEntity.getId());
assertEquals(nameFieldFormValue, resultEntity.getStringField(nameFieldName));
assertNull(resultEntity.getStringField(numberFieldName));
assertEquals(1, resultEntity.getFields().size());
}
}