Skip to content

Package: GridControlDetailPanelRenderer_PTest

GridControlDetailPanelRenderer_PTest

nameinstructionbranchcomplexitylinemethod
GridControlDetailPanelRenderer_PTest()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
after()
M: 8 C: 7
47%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 3
75%
M: 0 C: 1
100%
afterClass()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
beforeClass()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getChild(Control, Class, int)
M: 0 C: 40
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
getControl(Control, Class, String)
M: 0 C: 26
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getControlHelper(Control, Class, String, boolean[])
M: 0 C: 67
100%
M: 1 C: 15
94%
M: 1 C: 8
89%
M: 0 C: 14
100%
M: 0 C: 1
100%
init()
M: 0 C: 18
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
lambda$0(InvocationOnMock)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
mockViewModelContext(VView, EObject)
M: 0 C: 105
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 16
100%
M: 0 C: 1
100%
testDetailReused()
M: 0 C: 187
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 37
100%
M: 0 C: 1
100%
testEnabledChangeAppliedToDetailView_DoesNotOverrideReadonlyTrue()
M: 0 C: 92
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
testEnabledChangeAppliedToDetailView_OriginalReadonlyFalse()
M: 0 C: 105
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 21
100%
M: 0 C: 1
100%
testEnabledChangeAppliedToDetailView_OriginalReadonlyTrue()
M: 0 C: 92
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
testGetView()
M: 0 C: 65
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 14
100%
M: 0 C: 1
100%
testReadonlyChangeAppliedToDetailView_DoesNotOverrideEnabledFalse()
M: 0 C: 92
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
testReadonlyChangeAppliedToDetailView_OriginalReadonlyFalse()
M: 0 C: 92
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
testReadonlyChangeAppliedToDetailView_OriginalReadonlyTrue()
M: 0 C: 92
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
testSashForm()
M: 1 C: 97
99%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 19
100%
M: 0 C: 1
100%
testScroll()
M: 0 C: 109
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 26
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Lucas Koehler - initial API and implementation
13: * Christian W. Damus - bug 527686
14: ******************************************************************************/
15: package org.eclipse.emf.ecp.view.spi.table.nebula.grid;
16:
17: import static org.hamcrest.CoreMatchers.is;
18: import static org.hamcrest.CoreMatchers.notNullValue;
19: import static org.hamcrest.CoreMatchers.sameInstance;
20: import static org.hamcrest.Matchers.instanceOf;
21: import static org.junit.Assert.assertEquals;
22: import static org.junit.Assert.assertFalse;
23: import static org.junit.Assert.assertThat;
24: import static org.junit.Assert.assertTrue;
25: import static org.junit.Assert.fail;
26: import static org.junit.Assume.assumeThat;
27: import static org.mockito.Matchers.any;
28: import static org.mockito.Mockito.mock;
29: import static org.mockito.Mockito.when;
30:
31: import java.io.ByteArrayOutputStream;
32: import java.io.PrintStream;
33: import java.text.MessageFormat;
34: import java.util.Collections;
35:
36: import org.eclipse.emf.common.util.ECollections;
37: import org.eclipse.emf.ecore.EAttribute;
38: import org.eclipse.emf.ecore.EClass;
39: import org.eclipse.emf.ecore.EObject;
40: import org.eclipse.emf.ecore.EReference;
41: import org.eclipse.emf.ecore.EcoreFactory;
42: import org.eclipse.emf.ecore.EcorePackage;
43: import org.eclipse.emf.ecore.util.EcoreUtil;
44: import org.eclipse.emf.ecp.view.internal.table.nebula.grid.GridTestsUtil;
45: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
46: import org.eclipse.emf.ecp.view.spi.context.ViewModelContextFactory;
47: import org.eclipse.emf.ecp.view.spi.model.VElement;
48: import org.eclipse.emf.ecp.view.spi.model.VView;
49: import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
50: import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
51: import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
52: import org.eclipse.emf.ecp.view.spi.swt.masterdetail.DetailViewCache;
53: import org.eclipse.emf.ecp.view.spi.table.model.DetailEditing;
54: import org.eclipse.emf.ecp.view.spi.table.model.VTableControl;
55: import org.eclipse.emf.ecp.view.spi.util.swt.ImageRegistryService;
56: import org.eclipse.emf.ecp.view.table.test.common.TableControlHandle;
57: import org.eclipse.emf.ecp.view.table.test.common.TableTestUtil;
58: import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
59: import org.eclipse.emf.ecp.view.test.common.swt.spi.DatabindingClassRunner;
60: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTTestUtil;
61: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper;
62: import org.eclipse.emf.ecp.view.test.common.swt.spi.SWTViewTestHelper.RendererResult;
63: import org.eclipse.emfforms.spi.common.converter.EStructuralFeatureValueConverterService;
64: import org.eclipse.emfforms.spi.common.report.ReportService;
65: import org.eclipse.emfforms.spi.core.services.databinding.emf.EMFFormsDatabindingEMF;
66: import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
67: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
68: import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService;
69: import org.eclipse.emfforms.spi.swt.core.EMFFormsNoRendererException;
70: import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory;
71: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription;
72: import org.eclipse.jface.viewers.StructuredSelection;
73: import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
74: import org.eclipse.nebula.widgets.grid.Grid;
75: import org.eclipse.swt.SWT;
76: import org.eclipse.swt.custom.SashForm;
77: import org.eclipse.swt.custom.ScrolledComposite;
78: import org.eclipse.swt.widgets.Composite;
79: import org.eclipse.swt.widgets.Control;
80: import org.eclipse.swt.widgets.Label;
81: import org.eclipse.swt.widgets.Shell;
82: import org.eclipse.swt.widgets.Text;
83: import org.junit.After;
84: import org.junit.AfterClass;
85: import org.junit.Before;
86: import org.junit.BeforeClass;
87: import org.junit.Test;
88: import org.junit.runner.RunWith;
89: import org.mockito.stubbing.Answer;
90: import org.osgi.framework.Bundle;
91:
92: /**
93: * Unit tests for the {@link GridControlDetailPanelRenderer}.
94: *
95: * @author Lucas Koehler
96: *
97: */
98: @RunWith(DatabindingClassRunner.class)
99: public class GridControlDetailPanelRenderer_PTest {
100:
101:         private static String log;
102:         private static PrintStream systemErr;
103:         private Shell shell;
104:         private EObject domainElement;
105:
106:         @BeforeClass
107:         public static void beforeClass() {
108:                 systemErr = System.err;
109:                 System.setErr(new PrintStreamWrapper(systemErr));
110:         }
111:
112:         @AfterClass
113:         public static void afterClass() {
114:                 System.setErr(systemErr);
115:         }
116:
117:         @Before
118:         public void init() {
119:                 log = "";
120:                 shell = SWTViewTestHelper.createShell();
121:
122:                 final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
123:                 eClass.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass());
124:                 domainElement = eClass;
125:         }
126:
127:         @After
128:         public void after() {
129:                 shell.dispose();
130:•                if (!log.isEmpty()) {
131:                         fail("Unexpected log to System.err: " + log);
132:                 }
133:         }
134:
135:         /**
136:          * Tests that a sash form is used in order to allow resizing of the grid and detail panel composites.
137:          */
138:         @Test
139:         public void testSashForm() throws NoRendererFoundException,
140:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
141:                 // setup model
142:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
143:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
144:                 //
145:                 final Control render = SWTViewTestHelper.render(handle.getTableControl(), domainElement, shell);
146:                 assertTrue(render instanceof Composite);
147:                 final Composite border = getChild(getChild(render, Composite.class, 0), Composite.class, 1);
148:                 assertEquals("The grid and detail should be surrounded by a common border", SWT.BORDER,
149:                         border.getStyle() & SWT.BORDER);
150:                 final SashForm sashForm = getChild(border, SashForm.class, 0);
151:                 assertEquals("The SashForm should have exactly two child composites: one for the grid and one for the detail.",
152:                         2, sashForm.getChildren().length);
153:                 final int[] weights = sashForm.getWeights();
154:                 assertEquals(2, weights.length);
155:                 assertTrue("The table composite should have a lower relative weight in the sash than the detail",
156:•                        weights[0] < weights[1]);
157:                 final Composite gridWrapperComposite = getChild(sashForm, Composite.class, 0);
158:                 final Composite gridComposite = getChild(gridWrapperComposite, Composite.class, 0);
159:                 getChild(gridComposite, Grid.class, 0);
160:                 getChild(sashForm, Composite.class, 1);
161:         }
162:
163:         /**
164:          * Tests that a horizontal and vertical scrollbar appears if the detail is to small.
165:          */
166:         @Test
167:         public void testScroll() throws NoRendererFoundException,
168:                 NoPropertyDescriptorFoundExeption, EMFFormsNoRendererException {
169:                 shell.setSize(100, 200);
170:                 shell.open();
171:                 SWTTestUtil.waitForUIThread();
172:                 // setup model
173:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns();
174:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
175:                 //
176:                 final RendererResult renderControl = SWTViewTestHelper.renderControl(handle.getTableControl(), domainElement,
177:                         shell);
178:                 shell.layout();
179:                 SWTTestUtil.waitForUIThread();
180:                 final GridTableViewer tableViewer = GridTestsUtil.getTableViewerFromRenderer(renderControl.getRenderer());
181:                 final Control render = renderControl.getControl().get();
182:                 assertTrue(render instanceof Composite);
183:                 final Composite border = getChild(getChild(render, Composite.class, 0), Composite.class, 1);
184:                 assertEquals("The grid and detail should be surrounded by a common border", SWT.BORDER,
185:                         border.getStyle() & SWT.BORDER);
186:                 final SashForm sashForm = getChild(border, SashForm.class, 0);
187:                 tableViewer.setSelection(new StructuredSelection(tableViewer.getElementAt(0)));
188:                 final ScrolledComposite scrolledComposite = getChild(sashForm, ScrolledComposite.class, 1);
189:                 assertFalse(scrolledComposite.getAlwaysShowScrollBars());
190:                 assertTrue(scrolledComposite.getHorizontalBar().isVisible());
191:                 assertTrue(scrolledComposite.getVerticalBar().isVisible());
192:
193:                 // modify shell to force no scroll
194:                 shell.setSize(1000, 1000);
195:                 assertFalse(scrolledComposite.getHorizontalBar().isVisible());
196:                 assertFalse(scrolledComposite.getVerticalBar().isVisible());
197:
198:                 shell.close();
199:         }
200:
201:         @Test
202:         public void testGetView() {
203:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(mock(VTableControl.class),
204:                         mock(ViewModelContext.class), mock(ReportService.class), mock(EMFFormsDatabindingEMF.class),
205:                         mock(EMFFormsLabelProvider.class), mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class),
206:                         mock(EMFFormsEditSupport.class), mock(EStructuralFeatureValueConverterService.class),
207:                         mock(EMFFormsLocalizationService.class));
208:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
209:                 final EReference eReference = EcoreFactory.eINSTANCE.createEReference();
210:                 renderer.createDetailManager(shell);
211:                 final VView viewAttribute1 = renderer.getView(eAttribute);
212:                 final VView viewReference = renderer.getView(eReference);
213:                 assertFalse(EcoreUtil.equals(viewAttribute1, viewReference));
214:                 final VView viewAttribute2 = renderer.getView(eAttribute);
215:                 assertTrue(EcoreUtil.equals(viewAttribute1, viewAttribute2));
216:         }
217:
218:         /**
219:          * If the detail view is not configured as readonly, the table sets it to read only when the table is disabled.
220:          * Furthermore, the detail's readonly state is resetted when the table is enabled again.
221:          */
222:         @Test
223:         public void testEnabledChangeAppliedToDetailView_OriginalReadonlyFalse() {
224:                 final VTableControl control = mock(VTableControl.class);
225:                 final VView detailView = VViewFactory.eINSTANCE.createView();
226:                 detailView.setReadonly(false);
227:                 when(control.getDetailView()).thenReturn(detailView);
228:                 when(control.isEffectivelyEnabled()).thenReturn(true);
229:                 when(control.isEffectivelyReadonly()).thenReturn(false);
230:
231:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
232:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
233:
234:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
235:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
236:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
237:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
238:
239:                 renderer.renderSelectedObject(shell, eAttribute);
240:
241:                 assertFalse(detailView.isReadonly());
242:                 when(control.isEffectivelyEnabled()).thenReturn(false);
243:                 renderer.applyEnable();
244:                 assertTrue(detailView.isReadonly());
245:                 when(control.isEffectivelyEnabled()).thenReturn(true);
246:                 renderer.applyEnable();
247:                 assertFalse(detailView.isReadonly());
248:         }
249:
250:         /** If the detail view is configured as readonly, it must always stay readonly. */
251:         @Test
252:         public void testEnabledChangeAppliedToDetailView_OriginalReadonlyTrue() {
253:                 final VTableControl control = mock(VTableControl.class);
254:                 final VView detailView = VViewFactory.eINSTANCE.createView();
255:                 detailView.setReadonly(true);
256:                 when(control.getDetailView()).thenReturn(detailView);
257:                 when(control.isEffectivelyEnabled()).thenReturn(false);
258:                 when(control.isEffectivelyReadonly()).thenReturn(false);
259:
260:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
261:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
262:
263:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
264:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
265:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
266:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
267:
268:                 renderer.renderSelectedObject(shell, eAttribute);
269:
270:                 assertTrue(detailView.isReadonly());
271:                 when(control.isEffectivelyEnabled()).thenReturn(true);
272:                 renderer.applyEnable();
273:                 assertTrue(detailView.isReadonly());
274:         }
275:
276:         /**
277:          * If the table is read only, enabling it must not set the detail's readonly flag to false.
278:          */
279:         @Test
280:         public void testEnabledChangeAppliedToDetailView_DoesNotOverrideReadonlyTrue() {
281:                 final VTableControl control = mock(VTableControl.class);
282:                 final VView detailView = VViewFactory.eINSTANCE.createView();
283:                 detailView.setReadonly(false);
284:                 when(control.getDetailView()).thenReturn(detailView);
285:                 when(control.isEffectivelyEnabled()).thenReturn(false);
286:                 when(control.isEffectivelyReadonly()).thenReturn(true);
287:
288:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
289:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
290:
291:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
292:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
293:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
294:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
295:
296:                 renderer.renderSelectedObject(shell, eAttribute);
297:
298:                 assertTrue(detailView.isReadonly());
299:                 when(control.isEffectivelyEnabled()).thenReturn(true);
300:                 renderer.applyEnable();
301:                 assertTrue(detailView.isReadonly());
302:         }
303:
304:         /**
305:          * If the detail view is not configured as readonly, the table sets it to read only when the table is set to
306:          * readonly.
307:          */
308:         @Test
309:         public void testReadonlyChangeAppliedToDetailView_OriginalReadonlyFalse() {
310:                 final VTableControl control = mock(VTableControl.class);
311:                 final VView detailView = VViewFactory.eINSTANCE.createView();
312:                 detailView.setReadonly(false);
313:                 when(control.getDetailView()).thenReturn(detailView);
314:                 when(control.isEffectivelyEnabled()).thenReturn(true);
315:                 when(control.isEffectivelyReadonly()).thenReturn(false);
316:
317:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
318:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
319:
320:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
321:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
322:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
323:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
324:
325:                 renderer.renderSelectedObject(shell, eAttribute);
326:
327:                 assertFalse(detailView.isReadonly());
328:                 when(control.isEffectivelyReadonly()).thenReturn(true);
329:                 renderer.applyReadOnly();
330:                 assertTrue(detailView.isReadonly());
331:         }
332:
333:         /** If the detail view is configured as readonly, it must always stay readonly. */
334:         @Test
335:         public void testReadonlyChangeAppliedToDetailView_OriginalReadonlyTrue() {
336:                 final VTableControl control = mock(VTableControl.class);
337:                 final VView detailView = VViewFactory.eINSTANCE.createView();
338:                 detailView.setReadonly(true);
339:                 when(control.getDetailView()).thenReturn(detailView);
340:                 when(control.isEffectivelyEnabled()).thenReturn(true);
341:                 when(control.isEffectivelyReadonly()).thenReturn(true);
342:
343:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
344:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
345:
346:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
347:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
348:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
349:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
350:
351:                 renderer.renderSelectedObject(shell, eAttribute);
352:
353:                 assertTrue(detailView.isReadonly());
354:                 when(control.isEffectivelyReadonly()).thenReturn(false);
355:                 renderer.applyEnable();
356:                 assertTrue(detailView.isReadonly());
357:         }
358:
359:         /**
360:          * If the table is disabled, setting its read only flag to false, must not set the detail's readonly flag to false.
361:          */
362:         @Test
363:         public void testReadonlyChangeAppliedToDetailView_DoesNotOverrideEnabledFalse() {
364:                 final VTableControl control = mock(VTableControl.class);
365:                 final VView detailView = VViewFactory.eINSTANCE.createView();
366:                 detailView.setReadonly(false);
367:                 when(control.getDetailView()).thenReturn(detailView);
368:                 when(control.isEffectivelyEnabled()).thenReturn(false);
369:                 when(control.isEffectivelyReadonly()).thenReturn(true);
370:
371:                 final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
372:                 final ViewModelContext context = mockViewModelContext(detailView, eAttribute);
373:
374:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(control, context,
375:                         mock(ReportService.class), mock(EMFFormsDatabindingEMF.class), mock(EMFFormsLabelProvider.class),
376:                         mock(VTViewTemplateProvider.class), mock(ImageRegistryService.class), mock(EMFFormsEditSupport.class),
377:                         mock(EStructuralFeatureValueConverterService.class), mock(EMFFormsLocalizationService.class));
378:
379:                 renderer.renderSelectedObject(shell, eAttribute);
380:
381:                 assertTrue(detailView.isReadonly());
382:                 when(control.isEffectivelyReadonly()).thenReturn(false);
383:                 renderer.applyEnable();
384:                 assertTrue(detailView.isReadonly());
385:         }
386:
387:         /**
388:          * Verify the reuse of detail renderings with caching.
389:          */
390:         @Test
391:         public void testDetailReused() throws NoRendererFoundException, NoPropertyDescriptorFoundExeption,
392:                 EMFFormsNoRendererException {
393:
394:                 final TableControlHandle handle = TableTestUtil.createInitializedTableWithoutTableColumns(
395:                         EcorePackage.Literals.ECLASS__ESTRUCTURAL_FEATURES);
396:                 handle.getTableControl().setDetailEditing(DetailEditing.WITH_PANEL);
397:
398:                 final EAttribute a1 = EcoreFactory.eINSTANCE.createEAttribute();
399:                 a1.setName("a1");
400:                 final EAttribute a2 = EcoreFactory.eINSTANCE.createEAttribute();
401:                 a2.setName("a2");
402:                 domainElement.eSet(EcorePackage.Literals.ECLASS__ESTRUCTURAL_FEATURES, ECollections.asEList(a1, a2));
403:
404:                 final ViewModelContext context = ViewModelContextFactory.INSTANCE.createViewModelContext(
405:                         handle.getTableControl(), domainElement,
406:                         Collections.singletonMap(DetailViewCache.DETAIL_VIEW_CACHE_SIZE, 5));
407:
408:                 final GridControlDetailPanelRenderer renderer = new GridControlDetailPanelRenderer(handle.getTableControl(),
409:                         context,
410:                         context.getService(ReportService.class), context.getService(EMFFormsDatabindingEMF.class),
411:                         context.getService(EMFFormsLabelProvider.class),
412:                         context.getService(VTViewTemplateProvider.class), context.getService(ImageRegistryService.class),
413:                         context.getService(EMFFormsEditSupport.class),
414:                         context.getService(EStructuralFeatureValueConverterService.class),
415:                         context.getService(EMFFormsLocalizationService.class));
416:                 renderer.init();
417:
418:                 final SWTGridDescription grid = renderer
419:                         .getGridDescription(GridDescriptionFactory.INSTANCE.createEmptyGridDescription());
420:                 final Control render = renderer.render(grid.getGrid().get(0), shell);
421:                 renderer.finalizeRendering(shell);
422:
423:                 assertThat(render, instanceOf(Composite.class));
424:                 final Composite border = getChild(getChild(render, Composite.class, 0), Composite.class, 1);
425:                 final SashForm sashForm = getChild(border, SashForm.class, 0);
426:                 assumeThat("SashForm malformed", sashForm.getChildren().length, is(2));
427:                 final Composite detailComposite = getChild(sashForm, Composite.class, 1);
428:                 final GridTableViewer tableViewer = GridTestsUtil.getTableViewerFromRenderer(renderer);
429:
430:                 // Select an attribute
431:                 tableViewer.setSelection(new StructuredSelection(a1));
432:
433:                 final Text nameText = getControl(detailComposite, Text.class, "Name");
434:                 assertThat(nameText.getText(), is("a1"));
435:
436:                 // Select another attribute
437:                 tableViewer.setSelection(new StructuredSelection(a2));
438:
439:                 assertThat("Details not reused", getControl(detailComposite, Text.class, "Name"), sameInstance(nameText));
440:                 assertThat(nameText.getText(), is("a2"));
441:         }
442:
443:         //
444:         // Test framework
445:         //
446:
447:         private ViewModelContext mockViewModelContext(final VView detailView, final EObject domainObject) {
448:                 final ReportService reportService = mock(ReportService.class);
449:
450:                 final EMFFormsLocalizationService l10nService = mock(EMFFormsLocalizationService.class);
451:                 final Answer<String> l10nAnwer = invocation -> String.format("String for key '%s'",
452:                         invocation.getArguments()[1]);
453:                 when(l10nService.getString(any(Bundle.class), any(String.class))).then(l10nAnwer);
454:                 when(l10nService.getString(any(Class.class), any(String.class))).then(l10nAnwer);
455:
456:                 final ViewModelContext context = mock(ViewModelContext.class);
457:                 when(context.getService(ReportService.class)).thenReturn(reportService);
458:                 when(context.getService(EMFFormsLocalizationService.class)).thenReturn(l10nService);
459:
460:                 final ViewModelContext childContext = mock(ViewModelContext.class);
461:                 when(childContext.getDomainModel()).thenReturn(domainObject);
462:                 when(childContext.getViewModel()).thenReturn(detailView);
463:                 when(childContext.getService(ReportService.class)).thenReturn(reportService);
464:                 when(childContext.getService(EMFFormsLocalizationService.class)).thenReturn(l10nService);
465:
466:                 when(context.getChildContext(any(EObject.class), any(VElement.class), any(VView.class)))
467:                         .thenReturn(childContext);
468:
469:                 return context;
470:         }
471:
472:         private <T> T getChild(Control parent, Class<T> type, int index) {
473:                 assertTrue(MessageFormat.format("The Control {0} is not a composite => No children can be retrieved", parent),
474:                         parent instanceof Composite);
475:                 final Composite composite = (Composite) parent;
476:                 final Control child = composite.getChildren()[index];
477:                 assertTrue(MessageFormat.format("Child {0} is not of required type {1}", child, type.getName()),
478:                         type.isInstance(child));
479:                 return type.cast(child);
480:         }
481:
482:         private <T> T getControl(Control root, Class<T> type, String afterLabel) {
483:                 final T result = getControlHelper(root, type, afterLabel, new boolean[1]);
484:                 assertThat(String.format("No %s found after label '%s'", type.getSimpleName(), afterLabel),
485:                         result, notNullValue());
486:                 return result;
487:         }
488:
489:         private <T> T getControlHelper(Control control, Class<T> type, String afterLabel, boolean[] foundLabel) {
490:•                if (type.isInstance(control) && foundLabel[0]) {
491:                         return type.cast(control);
492:                 }
493:•                if (control instanceof Label) {
494:                         final Label label = (Label) control;
495:•                        if (foundLabel[0]) {
496:                                 // Next label? Give up search
497:                                 return null;
498:                         }
499:•                        if (label.getText().equals(afterLabel)) {
500:                                 foundLabel[0] = true;
501:                         }
502:                 }
503:•                if (control instanceof Composite) {
504:                         // Descend
505:•                        for (final Control next : ((Composite) control).getChildren()) {
506:                                 final T result = getControlHelper(next, type, afterLabel, foundLabel);
507:•                                if (result != null) {
508:                                         return result;
509:                                 }
510:                         }
511:                 }
512:                 return null;
513:         }
514:
515:         private static class PrintStreamWrapper extends PrintStream {
516:
517:                 private final PrintStream printStream;
518:
519:                 PrintStreamWrapper(PrintStream printStream) {
520:                         super(new ByteArrayOutputStream());
521:                         this.printStream = printStream;
522:                 }
523:
524:                 @Override
525:                 public void print(String s) {
526:                         log = log.concat("\n" + s);
527:                         printStream.print(s + "\n");
528:                 }
529:         }
530: }