/** * *************************************************************************** * 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.patterns.components; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.test.util.ReflectionTestUtils.getField; import static org.springframework.test.util.ReflectionTestUtils.setField; import java.util.Locale; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.json.JSONArray; import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.google.common.collect.ImmutableMap; import com.qcadoo.localization.api.TranslationService; import com.qcadoo.model.api.DataDefinition; import com.qcadoo.model.api.FieldDefinition; import com.qcadoo.model.api.types.BelongsToType; import com.qcadoo.model.api.types.HasManyType; import com.qcadoo.model.internal.types.EnumType; import com.qcadoo.model.internal.types.IntegerType; import com.qcadoo.model.internal.types.StringType; import com.qcadoo.plugin.api.PluginStateResolver; import com.qcadoo.plugin.internal.PluginUtilsService; import com.qcadoo.security.api.SecurityRolesService; import com.qcadoo.view.api.ComponentState; import com.qcadoo.view.api.components.GridComponent; import com.qcadoo.view.internal.ComponentDefinition; import com.qcadoo.view.internal.ComponentOption; import com.qcadoo.view.internal.api.InternalViewDefinition; import com.qcadoo.view.internal.api.InternalViewDefinitionState; import com.qcadoo.view.internal.components.TextInputComponentPattern; import com.qcadoo.view.internal.components.grid.GridComponentColumn; import com.qcadoo.view.internal.components.grid.GridComponentPattern; import com.qcadoo.view.internal.patterns.AbstractComponentPattern; import com.qcadoo.view.internal.patterns.AbstractPatternTest; import com.qcadoo.view.internal.xml.ViewDefinitionParser; import com.qcadoo.view.internal.xml.ViewDefinitionParserImpl; public class GridComponentPatternTest extends AbstractPatternTest { private ApplicationContext applicationContext; private TranslationService translationService; @Before public void init() throws Exception { applicationContext = mock(ApplicationContext.class); translationService = mock(TranslationService.class); } @Test public void shouldInitializeOptions() throws Exception { // given DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); given(translationService.translate(Mockito.anyString(), Mockito.any(Locale.class))).willReturn("i18n"); FieldDefinition nameFieldDefinition = mock(FieldDefinition.class); given(nameFieldDefinition.getType()).willReturn(new EnumType(translationService, "", true, "v1", "v2")); FieldDefinition numberFieldDefinition = mock(FieldDefinition.class); given(numberFieldDefinition.getType()).willReturn(new IntegerType()); FieldDefinition productFieldDefinition = mock(FieldDefinition.class); given(productFieldDefinition.getType()).willReturn(new StringType()); given(dataDefinition.getField("name")).willReturn(nameFieldDefinition); given(dataDefinition.getField("number")).willReturn(numberFieldDefinition); given(dataDefinition.getField("product")).willReturn(productFieldDefinition); given(dataDefinition.isPrioritizable()).willReturn(true); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("correspondingView", ImmutableMap.of("value", "plugin/details"))); pattern.addOption(new ComponentOption("correspondingComponent", ImmutableMap.of("value", "window.form"))); pattern.addOption(new ComponentOption("paginable", ImmutableMap.of("value", "true"))); pattern.addOption(new ComponentOption("creatable", ImmutableMap.of("value", "true"))); pattern.addOption(new ComponentOption("deletable", ImmutableMap.of("value", "true"))); pattern.addOption(new ComponentOption("width", ImmutableMap.of("value", "200"))); pattern.addOption(new ComponentOption("height", ImmutableMap.of("value", "400"))); pattern.addOption(new ComponentOption("lookup", ImmutableMap.of("value", "true"))); pattern.addOption(new ComponentOption("searchable", ImmutableMap.of("value", "name,number,product"))); pattern.addOption(new ComponentOption("orderable", ImmutableMap.of("value", "name,number"))); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); pattern.addOption(new ComponentOption("column", ImmutableMap.of("name", "number", "fields", "number", "link", "true", "width", "200"))); pattern.addOption(new ComponentOption("column", ImmutableMap.of("name", "name", "fields", "name", "hidden", "true"))); pattern.addOption(new ComponentOption("column", ImmutableMap.of("name", "product", "expression", "#product['name']"))); // when pattern.initialize(); // then JSONObject options = getJsOptions(pattern); assertEquals("plugin/details", options.getString("correspondingView")); assertEquals("window.form", options.getString("correspondingComponent")); assertFalse(options.getBoolean("fullscreen")); assertTrue(options.getBoolean("paginable")); assertTrue(options.getBoolean("lookup")); assertTrue(options.getBoolean("creatable")); assertTrue(options.getBoolean("deletable")); assertTrue(options.getBoolean("prioritizable")); assertEquals(200, options.getInt("width")); assertEquals(400, options.getInt("height")); assertEquals(2, options.getJSONArray("orderableColumns").length()); assertEquals("number", options.getJSONArray("orderableColumns").getString(0)); assertEquals("name", options.getJSONArray("orderableColumns").getString(1)); assertEquals(3, options.getJSONArray("searchableColumns").length()); assertEquals("number", options.getJSONArray("searchableColumns").getString(0)); assertEquals("product", options.getJSONArray("searchableColumns").getString(1)); assertEquals("name", options.getJSONArray("searchableColumns").getString(2)); assertFalse(options.has("belongsToFieldName")); assertEquals(3, options.getJSONArray("columns").length()); JSONObject number = options.getJSONArray("columns").getJSONObject(0); JSONObject name = options.getJSONArray("columns").getJSONObject(1); JSONObject product = options.getJSONArray("columns").getJSONObject(2); assertEquals("number", number.getString("name")); assertTrue(number.getBoolean("link")); assertFalse(number.getBoolean("hidden")); assertEquals(200, number.getInt("width")); assertEquals("right", number.getString("align")); assertFalse(number.has("filterValues")); assertEquals("name", name.getString("name")); assertFalse(name.getBoolean("link")); assertTrue(name.getBoolean("hidden")); assertEquals(100, name.getInt("width")); assertEquals("left", name.getString("align")); assertEquals(2, name.getJSONObject("filterValues").length()); assertEquals("i18n", name.getJSONObject("filterValues").getString("v1")); assertEquals("i18n", name.getJSONObject("filterValues").getString("v2")); assertEquals("product", product.getString("name")); assertFalse(product.getBoolean("link")); assertFalse(product.getBoolean("hidden")); assertEquals(100, product.getInt("width")); assertEquals("left", product.getString("align")); assertFalse(product.has("filterValues")); } @Test public void shouldHaveDefaultValues() throws Exception { // given DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); // when pattern.initialize(); // then JSONObject options = getJsOptions(pattern); assertFalse(options.has("correspondingView")); assertFalse(options.has("correspondingComponent")); assertFalse(options.has("belongsToFieldName")); assertTrue(options.getBoolean("paginable")); assertFalse(options.getBoolean("lookup")); assertFalse(options.getBoolean("creatable")); assertFalse(options.getBoolean("deletable")); assertFalse(options.getBoolean("prioritizable")); assertFalse(options.getBoolean("fullscreen")); assertEquals(300, options.getInt("width")); assertEquals(300, options.getInt("height")); assertEquals(0, options.getJSONArray("orderableColumns").length()); assertEquals(0, options.getJSONArray("searchableColumns").length()); assertEquals(0, options.getJSONArray("columns").length()); } @Test public void shouldBeFullscreen() throws Exception { // given DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("fullscreen", ImmutableMap.of("value", "true"))); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); // when pattern.initialize(); // then JSONObject options = getJsOptions(pattern); assertTrue(options.getBoolean("fullscreen")); assertEquals(0, options.getInt("width")); assertEquals(0, options.getInt("height")); } @Test public void shouldHaveScopeFieldName() throws Exception { // given DataDefinition dataDefinition = mock(DataDefinition.class); BelongsToType belongsToFieldType = mock(BelongsToType.class); FieldDefinition belongsToFieldDefinition = mock(FieldDefinition.class); given(belongsToFieldDefinition.getName()).willReturn("joinName"); given(belongsToFieldDefinition.getType()).willReturn(belongsToFieldType); given(belongsToFieldDefinition.getDataDefinition()).willReturn(dataDefinition); HasManyType hasManyFieldType = mock(HasManyType.class); given(hasManyFieldType.getJoinFieldName()).willReturn("joinName"); given(hasManyFieldType.getDataDefinition()).willReturn(dataDefinition); FieldDefinition hasManyFieldDefinition = mock(FieldDefinition.class); given(hasManyFieldDefinition.getName()).willReturn("fieldName"); given(hasManyFieldDefinition.getType()).willReturn(hasManyFieldType); given(hasManyFieldDefinition.getDataDefinition()).willReturn(dataDefinition); given(dataDefinition.getField("field")).willReturn(hasManyFieldDefinition); given(dataDefinition.getField("joinName")).willReturn(belongsToFieldDefinition); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); AbstractComponentPattern sourceComponent = new TextInputComponentPattern(getComponentDefinition("component", viewDefinition)); setField(sourceComponent, "dataDefinition", dataDefinition); setField(sourceComponent, "initialized", true); given(viewDefinition.getComponentByReference("component")).willReturn(sourceComponent); ComponentDefinition componentDefinition = getComponentDefinition("grid", null, "#{component}.field", null, viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); // when pattern.initialize(); // then JSONObject options = getJsOptions(pattern); assertEquals("joinName", options.getString("belongsToFieldName")); } @Test public void shouldReturnState() throws Exception { // given InternalViewDefinitionState viewDefinitionState = mock(InternalViewDefinitionState.class); DataDefinition dataDefinition = mock(DataDefinition.class); BelongsToType belongsToFieldType = mock(BelongsToType.class); FieldDefinition belongsToFieldDefinition = mock(FieldDefinition.class); given(belongsToFieldDefinition.getName()).willReturn("joinName"); given(belongsToFieldDefinition.getType()).willReturn(belongsToFieldType); HasManyType hasManyFieldType = mock(HasManyType.class); given(hasManyFieldType.getJoinFieldName()).willReturn("joinName"); given(hasManyFieldType.getDataDefinition()).willReturn(dataDefinition); FieldDefinition hasManyFieldDefinition = mock(FieldDefinition.class); given(hasManyFieldDefinition.getName()).willReturn("fieldName"); given(hasManyFieldDefinition.getType()).willReturn(hasManyFieldType); given(dataDefinition.getField("field")).willReturn(hasManyFieldDefinition); given(dataDefinition.getField("joinName")).willReturn(belongsToFieldDefinition); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); AbstractComponentPattern sourceComponent = new TextInputComponentPattern(getComponentDefinition("component", viewDefinition)); setField(sourceComponent, "dataDefinition", dataDefinition); setField(sourceComponent, "initialized", true); given(viewDefinition.getComponentByReference("component")).willReturn(sourceComponent); ComponentDefinition componentDefinition = getComponentDefinition("grid", null, "#{component}.field", null, viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); pattern.initialize(); // when ComponentState state = pattern.createComponentState(viewDefinitionState); // then assertTrue(state instanceof GridComponent); assertEquals(belongsToFieldDefinition, getField(state, "belongsToFieldDefinition")); assertEquals(getField(pattern, "columns"), getField(state, "columns")); } @Test public void shouldParsePredefinedFilters() throws Exception { // given DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); SecurityRolesService securityRolesService = mock(SecurityRolesService.class); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); ViewDefinitionParser parser = new ViewDefinitionParserImpl(); setField(parser, "securityRolesService", securityRolesService); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.newDocument(); Node componentNode = doc.createElement("root"); Node predefinedFiltersNode = doc.createElement("predefinedFilters"); componentNode.appendChild(predefinedFiltersNode); Element predefinedFilter1 = doc.createElement("predefinedFilter"); predefinedFilter1.setAttribute("name", "filter1"); predefinedFiltersNode.appendChild(predefinedFilter1); Element predefinedFilter2 = doc.createElement("predefinedFilter"); predefinedFilter2.setAttribute("name", "filter2"); predefinedFiltersNode.appendChild(predefinedFilter2); Element orderNode = doc.createElement("filterOrder"); orderNode.setAttribute("column", "testCol"); orderNode.setAttribute("direction", "desc"); predefinedFilter2.appendChild(orderNode); Element filterNode1 = doc.createElement("filterRestriction"); filterNode1.setAttribute("column", "testCol1"); filterNode1.setAttribute("value", "testVal1"); predefinedFilter2.appendChild(filterNode1); Element filterNode2 = doc.createElement("filterRestriction"); filterNode2.setAttribute("column", "testCol2"); filterNode2.setAttribute("value", "testVal2"); predefinedFilter2.appendChild(filterNode2); pattern.initialize(); // when pattern.parse(componentNode, parser); // then JSONObject options = getJsOptions(pattern); JSONArray filtersArray = options.getJSONArray("predefinedFilters"); assertNotNull(filtersArray); assertEquals(2, filtersArray.length()); assertEquals("filter1", filtersArray.getJSONObject(0).get("label")); assertEquals("name", filtersArray.getJSONObject(0).get("orderColumn")); assertEquals("asc", filtersArray.getJSONObject(0).get("orderDirection")); assertEquals(0, filtersArray.getJSONObject(0).getJSONObject("filter").length()); assertEquals("filter2", filtersArray.getJSONObject(1).get("label")); assertEquals("testCol", filtersArray.getJSONObject(1).get("orderColumn")); assertEquals("desc", filtersArray.getJSONObject(1).get("orderDirection")); assertEquals(2, filtersArray.getJSONObject(1).getJSONObject("filter").length()); assertEquals("testVal1", filtersArray.getJSONObject(1).getJSONObject("filter").getString("testCol1")); assertEquals("testVal2", filtersArray.getJSONObject(1).getJSONObject("filter").getString("testCol2")); } @Test public void shouldFilterOutColumnsInvisibleForTenant() throws Exception { // given PluginStateResolver pluginStateResolver = mock(PluginStateResolver.class); PluginUtilsService pluginUtil = new PluginUtilsService(pluginStateResolver); pluginUtil.init(); given(pluginStateResolver.isEnabled("disabledPlugin")).willReturn(false); InternalViewDefinitionState viewDefinitionState = mock(InternalViewDefinitionState.class); DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); componentDefinition.setDataDefinition(dataDefinition); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); FieldDefinition nameFieldDefinition = mock(FieldDefinition.class); given(nameFieldDefinition.getType()).willReturn(new EnumType(translationService, "", true, "v1", "v2")); given(dataDefinition.getField("name")).willReturn(nameFieldDefinition); pattern.addOption(new ComponentOption("column", ImmutableMap.of("name", "name", "fields", "name", "hidden", "true"))); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); pattern.addColumn("invisible", "name", null, false, 100, false, false, "disabledPlugin"); pattern.initialize(); // when ComponentState state = pattern.createComponentState(viewDefinitionState); // then assertTrue(state instanceof GridComponent); @SuppressWarnings("unchecked") Map<String, GridComponentColumn> patternColumns = (Map<String, GridComponentColumn>) getField(pattern, "columns"); @SuppressWarnings("unchecked") Map<String, GridComponentColumn> stateColumns = (Map<String, GridComponentColumn>) getField(state, "columns"); assertEquals(2, patternColumns.size()); assertEquals(1, stateColumns.size()); assertTrue(patternColumns.keySet().contains("name")); assertNotNull(patternColumns.get("name")); assertTrue(patternColumns.keySet().contains("invisible")); assertNotNull(patternColumns.get("invisible")); assertTrue(stateColumns.keySet().contains("name")); assertNotNull(stateColumns.get("name")); assertFalse(stateColumns.keySet().contains("invisible")); assertNull(stateColumns.get("invisible")); } @Test public void shouldNotFilterOutColumnsVisibleForTenant() throws Exception { // given PluginStateResolver pluginStateResolver = mock(PluginStateResolver.class); PluginUtilsService pluginUtil = new PluginUtilsService(pluginStateResolver); pluginUtil.init(); given(pluginStateResolver.isEnabled("disabledPlugin")).willReturn(true); InternalViewDefinitionState viewDefinitionState = mock(InternalViewDefinitionState.class); DataDefinition dataDefinition = mock(DataDefinition.class); InternalViewDefinition viewDefinition = mock(InternalViewDefinition.class); given(viewDefinition.getDataDefinition()).willReturn(dataDefinition); ComponentDefinition componentDefinition = getComponentDefinition("grid", viewDefinition); componentDefinition.setTranslationService(translationService); componentDefinition.setApplicationContext(applicationContext); componentDefinition.setDataDefinition(dataDefinition); GridComponentPattern pattern = new GridComponentPattern(componentDefinition); FieldDefinition nameFieldDefinition = mock(FieldDefinition.class); given(nameFieldDefinition.getType()).willReturn(new EnumType(translationService, "", true, "v1", "v2")); given(dataDefinition.getField("name")).willReturn(nameFieldDefinition); pattern.addOption(new ComponentOption("column", ImmutableMap.of("name", "name", "fields", "name", "hidden", "true"))); pattern.addOption(new ComponentOption("order", ImmutableMap.of("column", "name", "direction", "asc"))); pattern.addColumn("invisible", "name", null, false, 100, false, false, "disabledPlugin"); pattern.initialize(); // when ComponentState state = pattern.createComponentState(viewDefinitionState); // then assertTrue(state instanceof GridComponent); @SuppressWarnings("unchecked") Map<String, GridComponentColumn> patternColumns = (Map<String, GridComponentColumn>) getField(pattern, "columns"); @SuppressWarnings("unchecked") Map<String, GridComponentColumn> stateColumns = (Map<String, GridComponentColumn>) getField(state, "columns"); assertEquals(2, patternColumns.size()); assertEquals(2, stateColumns.size()); assertTrue(patternColumns.keySet().contains("name")); assertNotNull(patternColumns.get("name")); assertTrue(patternColumns.keySet().contains("invisible")); assertNotNull(patternColumns.get("invisible")); assertTrue(stateColumns.keySet().contains("name")); assertNotNull(stateColumns.get("name")); assertTrue(stateColumns.keySet().contains("invisible")); assertNotNull(stateColumns.get("invisible")); } }