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