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