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