Some final keywords, by Eclipse
[online-glom:gwt-glom.git] / src / test / java / org / glom / web / server / libglom / DocumentTest.java
1 /*
2  * Copyright (C) 2009, 2010, 2011 Openismus GmbH
3  *
4  * This file is part of gwt-glom
5  *
6  * gwt-glom is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * gwt-glom is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with gwt-glom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package org.glom.web.server.libglom;
21
22 import static org.hamcrest.CoreMatchers.is;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertThat;
26 import static org.junit.Assert.assertTrue;
27
28 import java.net.URL;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.apache.commons.lang3.StringUtils;
34 import org.glom.web.shared.DataItem;
35 import org.glom.web.shared.libglom.Field;
36 import org.glom.web.shared.libglom.NumericFormat;
37 import org.glom.web.shared.libglom.Relationship;
38 import org.glom.web.shared.libglom.Report;
39 import org.glom.web.shared.libglom.layout.LayoutGroup;
40 import org.glom.web.shared.libglom.layout.LayoutItem;
41 import org.glom.web.shared.libglom.layout.LayoutItemField;
42 import org.glom.web.shared.libglom.layout.LayoutItemNotebook;
43 import org.glom.web.shared.libglom.layout.LayoutItemPortal;
44 import org.glom.web.shared.libglom.layout.SortClause;
45 import org.glom.web.shared.libglom.layout.TableToViewDetails;
46 import org.glom.web.shared.libglom.layout.reportparts.LayoutItemGroupBy;
47 import org.junit.AfterClass;
48 import org.junit.BeforeClass;
49 import org.junit.Test;
50
51 /**
52  * Simple test to ensure that the generated bindings are working.
53  */
54 public class DocumentTest {
55
56         private static Document document;
57         private static String locale = ""; // This means the original locale.
58         static String testUriMusicCollection = "";
59         static String testUriFilmManager = "";
60
61         @BeforeClass
62         static public void setUp() {
63                 URL url = DocumentTest.class.getResource("example_music_collection.glom");
64                 assertTrue(url != null);
65                 testUriMusicCollection = url.toString();
66                 assertTrue(!StringUtils.isEmpty(testUriMusicCollection));
67
68                 url = DocumentTest.class.getResource("example_film_manager.glom");
69                 assertTrue(url != null);
70                 testUriFilmManager = url.toString();
71                 assertTrue(!StringUtils.isEmpty(testUriMusicCollection));
72
73                 document = new Document();
74                 document.setFileURI(testUriMusicCollection);
75                 final boolean retval = document.load();
76                 assertTrue(retval);
77         }
78
79         @AfterClass
80         static public void tearDown() {
81         }
82
83         @Test
84         public void testDocumentInfo() {
85                 assertThat(document.getDatabaseTitleOriginal(), is("Music Collection"));
86                 assertThat(document.getDefaultTable(), is("artists"));
87         }
88
89         @Test
90         public void testLocales() {
91                 final List<String> localeIDs = document.getTranslationAvailableLocales();
92                 assertEquals(8, localeIDs.size());
93
94                 String tables = localeIDs.get(0);
95                 for (int i = 1; i < localeIDs.size(); i++) {
96                         tables += ", " + localeIDs.get(i);
97                 }
98                 assertThat(tables, is("en, cs, de, es, fr, gl, pt_BR, sl"));
99         }
100
101         @Test
102         public void testReadTableNames() {
103                 final List<String> tableNames = document.getTableNames();
104                 assertEquals(4, tableNames.size());
105
106                 String tables = tableNames.get(0);
107                 for (int i = 1; i < tableNames.size(); i++) {
108                         tables += ", " + tableNames.get(i);
109                 }
110                 assertThat(tables, is("artists, albums, songs, publishers"));
111         }
112
113         @Test
114         public void testReadTableFieldSizes() {
115
116                 List<Field> fields = document.getTableFields("albums");
117                 assertEquals(6, fields.size());
118
119                 Field field = fields.get(0);
120                 String titles = field.getTitleOrName(locale);
121                 for (int i = 1; i < fields.size(); i++) {
122                         field = fields.get(i);
123                         titles += ", " + field.getTitleOrName(locale);
124                 }
125
126                 // TODO: The sequence is not important. It's only important that they are all there.
127                 assertThat(titles, is("Publisher ID, Artist ID, Album ID, Name, Year, Comments"));
128
129                 fields = document.getTableFields("artists");
130                 assertEquals(4, fields.size());
131
132                 field = fields.get(0);
133                 titles = field.getTitleOrName(locale);
134                 for (int i = 1; i < fields.size(); i++) {
135                         field = fields.get(i);
136                         titles += ", " + field.getTitleOrName(locale);
137                 }
138
139                 // TODO: The sequence is not important. It's only important that they are all there.
140                 assertThat(titles, is("Artist ID, Name, Description, Comments"));
141
142                 fields = document.getTableFields("publishers");
143                 assertEquals(3, fields.size());
144
145                 field = fields.get(0);
146                 titles = field.getTitleOrName(locale);
147                 for (int i = 1; i < fields.size(); i++) {
148                         field = fields.get(i);
149                         titles += ", " + field.getTitleOrName(locale);
150                 }
151
152                 // TODO: The sequence is not important. It's only important that they are all there.
153                 assertThat(titles, is("Name, Publisher ID, Comments"));
154
155                 fields = document.getTableFields("songs");
156                 assertEquals(4, fields.size());
157
158                 field = fields.get(0);
159                 titles = field.getTitleOrName(locale);
160                 for (int i = 1; i < fields.size(); i++) {
161                         field = fields.get(i);
162                         titles += ", " + field.getTitleOrName(locale);
163                 }
164
165                 // TODO: The sequence is not important. It's only important that they are all there.
166                 assertThat(titles, is("Song ID, Album ID, Name, Comments"));
167         }
168
169         @Test
170         public void testReadTableExampleRows() {
171                 final List<Map<String, DataItem>> exampleRows = document.getExampleRows("albums");
172                 assertFalse(exampleRows.isEmpty());
173
174                 final Map<String, DataItem> row = exampleRows.get(0);
175                 assertFalse(row.isEmpty());
176         }
177
178         @Test
179         public void testReadLayoutListInfo() {
180                 final String[] tables = { "albums", "artists", "publishers", "songs" };
181                 final int[] sortClauseSizes = { 0, 1, 1, 1 };
182                 final int[] layoutFieldSizes = { 7, 4, 3, 4 };
183
184                 for (int i = 0; i < tables.length; i++) {
185                         final List<LayoutGroup> layoutList = document.getDataLayoutGroups("list", tables[i]);
186                         assertTrue(!layoutList.isEmpty());
187                         final List<LayoutItem> layoutItems = layoutList.get(0).getItems();
188                         final List<LayoutItemField> layoutFields = new ArrayList<LayoutItemField>();
189                         final SortClause sortClause = new SortClause(); // TODO: Why use a SortClause instead of a List?
190                         final int numItems = safeLongToInt(layoutItems.size());
191                         for (int j = 0; j < numItems; j++) {
192                                 final LayoutItem item = layoutItems.get(j);
193
194                                 if (item instanceof LayoutItemField) {
195                                         final LayoutItemField field = (LayoutItemField) item;
196                                         layoutFields.add(field);
197                                         final Field details = field.getFullFieldDetails();
198                                         if (details != null && details.getPrimaryKey()) {
199                                                 sortClause.add(new SortClause.SortField(field, true)); // ascending
200                                         }
201                                 }
202                         }
203                         assertEquals(sortClauseSizes[i], sortClause.size());
204                         assertEquals(layoutFieldSizes[i], safeLongToInt(layoutFields.size()));
205                 }
206         }
207
208         /*
209          * This tests if getting values from a NumericFormat object is working. This test was failing with a JVM crash when
210          * using the glom_sharedptr macro with Glom::UsesRelationship and Glom::Formatting.
211          */
212         @Test
213         public void testGetNumericFormat() {
214                 final List<String> tableNames = document.getTableNames();
215
216                 for (int i = 0; i < tableNames.size(); i++) {
217                         final String table = tableNames.get(i);
218                         final List<LayoutGroup> layoutList = document.getDataLayoutGroups("list", table);
219                         assertTrue(!layoutList.isEmpty());
220                         final LayoutGroup firstgroup = layoutList.get(0);
221                         assertTrue(firstgroup != null);
222                         final List<LayoutItem> layoutItems = firstgroup.getItems();
223                         final int numItems = safeLongToInt(layoutItems.size());
224                         for (int j = 0; j < numItems; j++) {
225                                 final LayoutItem item = layoutItems.get(j);
226                                 assertTrue(item != null);
227
228                                 if (item instanceof LayoutItemField) {
229                                         final LayoutItemField itemField = (LayoutItemField) item;
230                                         // don't keep a reference to the FeildFormatting object
231                                         final NumericFormat numFormat = itemField.getFormattingUsed().getNumericFormat();
232                                         assertTrue(numFormat != null);
233
234                                         // get the values
235                                         final boolean altForegroundColorForNegatives = numFormat.getUseAltForegroundColorForNegatives();
236                                         final String currencySymbol = numFormat.getCurrencySymbol();
237                                         final long decimalPlaces = numFormat.getDecimalPlaces();
238                                         final boolean decimalPlacesRestricted = numFormat.getDecimalPlacesRestricted();
239                                         final boolean useThousandsSepator = numFormat.getUseThousandsSeparator();
240                                         final String alternativeColorForNegatives = NumericFormat
241                                                         .getAlternativeColorForNegativesAsHTMLColor();
242                                         final long defaultPrecision = NumericFormat.getDefaultPrecision();
243
244                                         // Simulate a garbage collection
245                                         System.gc();
246                                         System.runFinalization();
247
248                                         // re-get the values and test
249                                         assertEquals(altForegroundColorForNegatives, numFormat.getUseAltForegroundColorForNegatives());
250                                         assertEquals(currencySymbol, numFormat.getCurrencySymbol());
251                                         assertEquals(decimalPlaces, numFormat.getDecimalPlaces());
252                                         assertEquals(decimalPlacesRestricted, numFormat.getDecimalPlacesRestricted());
253                                         assertEquals(useThousandsSepator, numFormat.getUseThousandsSeparator());
254                                         assertEquals(alternativeColorForNegatives,
255                                                         NumericFormat.getAlternativeColorForNegativesAsHTMLColor());
256                                         assertEquals(defaultPrecision, NumericFormat.getDefaultPrecision());
257
258                                 }
259                         }
260                 }
261         }
262
263         /*
264          * A smoke test for the methods added to LayoutItemField for accessing methods in Glom::UsesRelationship.
265          */
266         @Test
267         public void testUsesRelationshipMethods() {
268                 final String table = "albums";
269                 final List<LayoutGroup> layoutList = document.getDataLayoutGroups("list", table);
270                 final List<LayoutItem> layoutItems = layoutList.get(0).getItems();
271
272                 String names = null, hasRelationshipNames = null, tablesUsed = null;
273                 final LayoutItem firstItem = layoutItems.get(0);
274
275                 if (firstItem instanceof LayoutItemField) {
276                         final LayoutItemField firstItemField = (LayoutItemField) firstItem;
277                         names = firstItemField.getName();
278                         hasRelationshipNames = "" + firstItemField.getHasRelationshipName();
279                         tablesUsed = firstItemField.getTableUsed(table);
280                 }
281                 final int numItems = safeLongToInt(layoutItems.size());
282                 for (int j = 1; j < numItems; j++) {
283                         final LayoutItem item = layoutItems.get(j);
284
285                         if (item instanceof LayoutItemField) {
286                                 final LayoutItemField itemField = (LayoutItemField) item;
287                                 names += ", " + itemField.getName();
288                                 hasRelationshipNames += ", " + itemField.getHasRelationshipName();
289                                 tablesUsed += ", " + itemField.getTableUsed(table);
290                         }
291                 }
292                 assertEquals("name, year, artist_id, name, publisher_id, name, comments", names);
293                 assertEquals("false, false, false, true, false, true, false", hasRelationshipNames);
294                 assertEquals("albums, albums, albums, artists, albums, publishers, albums", tablesUsed);
295         }
296
297         @Test
298         public void testGetSuitableTableToViewDetails() {
299
300                 // Create a new document for the film manager
301                 final Document filmManagerDocument = new Document();
302                 filmManagerDocument.setFileURI(testUriFilmManager);
303                 final boolean retval = filmManagerDocument.load();
304                 assertTrue(retval);
305
306                 // Get the "Scene Cast" related list portal. This relies on specific details of the film manager details
307                 // view layout. I've included safety checks that will fail if the layout changes.
308                 final List<LayoutGroup> detailsLayout = filmManagerDocument.getDataLayoutGroups("details", "scenes");
309                 assertEquals(3, detailsLayout.size());
310
311                 LayoutGroup layoutGroup = detailsLayout.get(1);
312                 assertEquals("details", layoutGroup.getName());
313
314                 layoutGroup = detailsLayout.get(2);
315                 assertEquals("details_lower", layoutGroup.getName());
316
317                 List<LayoutItem> items = layoutGroup.getItems();
318                 assertEquals(2, items.size());
319
320                 final LayoutItem notebookItem = items.get(0);
321                 assertEquals("notebook", notebookItem.getName());
322                 assertTrue(notebookItem instanceof LayoutItemNotebook);
323                 final LayoutItemNotebook notebook = (LayoutItemNotebook) notebookItem;
324                 items = notebook.getItems();
325                 assertEquals(7, items.size());
326                 final LayoutItem portalItem = items.get(0);
327                 assertTrue(portalItem instanceof LayoutItemPortal);
328                 final LayoutItemPortal portal = (LayoutItemPortal) portalItem;
329                 assertTrue(portal != null);
330
331                 assertEquals(portal.getRelationshipNameUsed(), "scene_cast");
332
333                 // call getSuitableTableToCiewDetails
334                 final TableToViewDetails viewDetails = filmManagerDocument.getPortalSuitableTableToViewDetails(portal);
335                 assertTrue(viewDetails != null);
336
337                 // Simulate a garbage collection
338                 System.gc();
339                 System.runFinalization();
340
341                 // Check if things are working like we expect
342                 assertEquals("characters", viewDetails.tableName);
343                 assertTrue(viewDetails.usesRelationship != null);
344                 final Relationship relationship = viewDetails.usesRelationship.getRelationship();
345                 assertTrue(relationship != null);
346                 assertEquals("cast", relationship.getName());
347                 assertTrue(viewDetails.usesRelationship.getRelatedRelationship() == null);
348
349         }
350
351         @Test
352         public void testReadReportNames() {
353                 final List<String> reportNames = document.getReportNames("albums");
354                 assertEquals(1, reportNames.size()); // TODO: Test something with more reports.
355
356                 String reports = reportNames.get(0);
357                 for (int i = 1; i < reportNames.size(); i++) {
358                         reports += ", " + reportNames.get(i);
359                 }
360                 assertThat(reports, is("albums_by_artist"));
361         }
362
363         @Test
364         public void testReadReportStructure() {
365                 final Report report = document.getReport("albums", "albums_by_artist");
366                 assertTrue(report != null);
367                 final LayoutGroup layoutGroup = report.getLayoutGroup();
368                 assertTrue(layoutGroup != null);
369                 final List<LayoutItem> layoutItems = layoutGroup.getItems();
370                 final int numItems = safeLongToInt(layoutItems.size());
371                 assertEquals(1, numItems);
372
373                 LayoutItem layoutItem = layoutItems.get(0);
374                 assertTrue(layoutItem != null);
375                 final LayoutGroup asGroup = (LayoutGroup) layoutItem;
376                 assertTrue(asGroup != null);
377                 final LayoutItemGroupBy groupby = (LayoutItemGroupBy) layoutItem;
378                 assertTrue(groupby != null);
379
380                 assertTrue(groupby.getHasFieldGroupBy());
381                 final LayoutItemField fieldGroupBy = groupby.getFieldGroupBy();
382                 assertTrue(fieldGroupBy != null);
383                 assertThat(fieldGroupBy.getName(), is("artist_id"));
384
385                 final LayoutGroup groupSecondaries = groupby.getSecondaryFields();
386                 assertTrue(groupSecondaries != null);
387
388                 final List<LayoutItem> innerItems = groupby.getItems();
389                 assertTrue(innerItems != null);
390                 final int numInnerItems = safeLongToInt(innerItems.size());
391                 assertEquals(2, numInnerItems);
392
393                 layoutItem = innerItems.get(0);
394                 assertTrue(layoutItem != null);
395                 assertTrue(layoutItem instanceof LayoutItemField);
396                 LayoutItemField field = (LayoutItemField) layoutItem;
397                 assertTrue(field != null);
398                 assertThat(field.getName(), is("name"));
399                 assertThat(field.getGlomType(), is(Field.GlomFieldType.TYPE_TEXT));
400
401                 layoutItem = innerItems.get(1);
402                 assertTrue(layoutItem != null);
403                 assertTrue(layoutItem instanceof LayoutItemField);
404                 field = (LayoutItemField) layoutItem;
405                 assertTrue(field != null);
406                 assertThat(field.getName(), is("year"));
407                 assertThat(field.getGlomType(), is(Field.GlomFieldType.TYPE_NUMERIC));
408         }
409
410         // Test thread class that runs all the tests.
411         private class TestThread implements Runnable {
412
413                 @Override
414                 public void run() {
415                         for (int i = 0; i < 20; i++) {
416                                 testDocumentInfo();
417                                 testGetNumericFormat();
418                                 testGetSuitableTableToViewDetails();
419                                 testReadLayoutListInfo();
420                                 testReadTableFieldSizes();
421                                 testReadTableNames();
422                                 testUsesRelationshipMethods();
423                         }
424                 }
425         }
426
427         /*
428          * Tests threaded access.
429          */
430         @Test
431         public void testThreadedAccess() throws InterruptedException {
432                 // create the threads
433                 final Thread thread1 = new Thread(new TestThread());
434                 final Thread thread2 = new Thread(new TestThread());
435                 final Thread thread3 = new Thread(new TestThread());
436                 final Thread thread4 = new Thread(new TestThread());
437
438                 // start the threads
439                 thread1.start();
440                 thread2.start();
441                 thread3.start();
442                 thread4.start();
443
444                 // wait for the treads to finish
445                 try {
446                         thread1.join();
447                 } catch (final InterruptedException e) {
448                         System.out.println("Thread 1 had a problem finishing. " + e);
449                         throw e;
450                 }
451
452                 try {
453                         thread2.join();
454                 } catch (final InterruptedException e) {
455                         System.out.println("Thread 2 had a problem finishing. " + e);
456                         throw e;
457                 }
458
459                 try {
460                         thread3.join();
461                 } catch (final InterruptedException e) {
462                         System.out.println("Thread 3 had a problem finishing. " + e);
463                         throw e;
464                 }
465
466                 try {
467                         thread4.join();
468                 } catch (final InterruptedException e) {
469                         System.out.println("Thread 4 had a problem finishing. " + e);
470                         throw e;
471                 }
472         }
473
474         /*
475          * This method safely converts longs from libglom into ints. This method was taken from stackoverflow:
476          * 
477          * http://stackoverflow.com/questions/1590831/safely-casting-long-to-int-in-java
478          */
479         private static int safeLongToInt(final long l) {
480                 if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
481                         throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
482                 }
483                 return (int) l;
484         }
485
486 }