2 * Copyright (C) 2009, 2010, 2011 Openismus GmbH
4 * This file is part of gwt-glom
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.
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
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/>.
20 package org.glom.web.server.libglom;
22 import static org.hamcrest.CoreMatchers.is;
23 import static org.junit.Assert.*;
26 import java.util.ArrayList;
27 import java.util.List;
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;
52 * Simple test to ensure that the generated bindings are working.
54 public class DocumentTest {
56 private static Document document;
57 private static String defaultLocale = "";
58 private static String germanLocale = "de";
59 static String testUriMusicCollection = "";
60 static String testUriFilmManager = "";
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));
69 url = DocumentTest.class.getResource("example_film_manager.glom");
70 assertTrue(url != null);
71 testUriFilmManager = url.toString();
72 assertTrue(!StringUtils.isEmpty(testUriFilmManager));
74 document = new Document();
75 document.setFileURI(testUriMusicCollection);
76 final boolean retval = document.load();
81 static public void tearDown() {
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"));
93 public void testLocales() {
94 final List<String> localeIDs = document.getTranslationAvailableLocales();
95 assertEquals(11, localeIDs.size());
97 String tables = localeIDs.get(0);
98 for (int i = 1; i < localeIDs.size(); i++) {
99 tables += ", " + localeIDs.get(i);
101 assertThat(tables, is("cs, de, el, es, fr, gl, id, lv, pt_BR, sl, en"));
105 public void testReadTableNames() {
106 final List<String> tableNames = document.getTableNames();
107 assertEquals(4, tableNames.size());
109 String tables = tableNames.get(0);
110 for (int i = 1; i < tableNames.size(); i++) {
111 tables += ", " + tableNames.get(i);
113 assertThat(tables, is("artists, albums, songs, publishers"));
116 String getTitles(final List<Field> list, final String locale) {
118 for (int i = 0; i < list.size(); i++) {
119 final Translatable item = list.get(i);
125 result += item.getTitleOrName(locale);
132 public void testReadTableFieldSizes() {
134 List<Field> fields = document.getTableFields("albums");
135 assertEquals(6, fields.size());
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"));
141 fields = document.getTableFields("artists");
142 assertEquals(4, fields.size());
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"));
148 fields = document.getTableFields("publishers");
149 assertEquals(3, fields.size());
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"));
156 fields = document.getTableFields("songs");
157 assertEquals(4, fields.size());
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"));
165 public void testReadTableExampleRows() {
166 final List<Map<String, DataItem>> exampleRows = document.getExampleRows("albums");
167 assertFalse(exampleRows.isEmpty());
169 final Map<String, DataItem> row = exampleRows.get(0);
170 assertFalse(row.isEmpty());
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 };
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);
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
198 assertEquals(sortClauseSizes[i], sortClause.size());
199 assertEquals(layoutFieldSizes[i], safeLongToInt(layoutFields.size()));
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.
208 public void testGetNumericFormat() {
209 final List<String> tableNames = document.getTableNames();
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);
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);
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();
239 // Simulate a garbage collection
241 System.runFinalization();
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());
259 * A smoke test for the methods added to LayoutItemField for accessing methods in Glom::UsesRelationship.
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();
267 String names = null, hasRelationshipNames = null, tablesUsed = null;
268 final LayoutItem firstItem = layoutItems.get(0);
270 if (firstItem instanceof LayoutItemField) {
271 final LayoutItemField firstItemField = (LayoutItemField) firstItem;
272 names = firstItemField.getName();
273 hasRelationshipNames = "" + firstItemField.getHasRelationshipName();
274 tablesUsed = firstItemField.getTableUsed(table);
276 final int numItems = safeLongToInt(layoutItems.size());
277 for (int j = 1; j < numItems; j++) {
278 final LayoutItem item = layoutItems.get(j);
280 if (item instanceof LayoutItemField) {
281 final LayoutItemField itemField = (LayoutItemField) item;
282 names += ", " + itemField.getName();
283 hasRelationshipNames += ", " + itemField.getHasRelationshipName();
284 tablesUsed += ", " + itemField.getTableUsed(table);
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);
293 public void testLayoutItemText() {
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();
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());
306 LayoutGroup layoutGroup = detailsLayout.get(1);
307 assertEquals(Document.LAYOUT_NAME_DETAILS, layoutGroup.getName());
309 final List<LayoutItem> items = layoutGroup.getItems();
311 final LayoutItem item = items.get(1);
312 assertTrue(item instanceof LayoutItemText);
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.");
322 public void testGetSuitableTableToViewDetails() {
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();
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());
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));
340 layoutGroup = detailsLayout.get(2);
341 assertEquals("details_lower", layoutGroup.getName());
343 List<LayoutItem> items = layoutGroup.getItems();
344 assertEquals(2, items.size());
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);
357 assertEquals("scene_cast", portal.getRelationshipNameUsed());
358 assertEquals("Cast", portal.getTitle(defaultLocale));
359 assertEquals("Szene Besetzung", portal.getTitle(germanLocale));
361 // call getSuitableTableToViewDetails
362 final TableToViewDetails viewDetails = filmManagerDocument.getPortalSuitableTableToViewDetails(portal);
363 assertTrue(viewDetails != null);
365 // Simulate a garbage collection
367 System.runFinalization();
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);
380 public void testReadReportNames() {
381 final List<String> reportNames = document.getReportNames("albums");
382 assertEquals(1, reportNames.size()); // TODO: Test something with more reports.
384 String reports = reportNames.get(0);
385 for (int i = 1; i < reportNames.size(); i++) {
386 reports += ", " + reportNames.get(i);
388 assertThat(reports, is("albums_by_artist"));
392 public void testReadReportStructure() {
393 final Report report = document.getReport("albums", "albums_by_artist");
394 assertTrue(report != null);
396 assertThat(report.getTitle(defaultLocale), is("Albums By Artist"));
397 assertThat(report.getTitle(germanLocale), is("Alben nach Künstler"));
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);
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);
412 assertTrue(groupby.getHasFieldGroupBy());
413 final LayoutItemField fieldGroupBy = groupby.getFieldGroupBy();
414 assertTrue(fieldGroupBy != null);
415 assertThat(fieldGroupBy.getName(), is("artist_id"));
417 final LayoutGroup groupSecondaries = groupby.getSecondaryFields();
418 assertTrue(groupSecondaries != null);
420 final List<LayoutItem> innerItems = groupby.getItems();
421 assertTrue(innerItems != null);
422 final int numInnerItems = safeLongToInt(innerItems.size());
423 assertEquals(2, numInnerItems);
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));
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));
442 // Test thread class that runs all the tests.
443 private class TestThread implements Runnable {
447 for (int i = 0; i < 20; i++) {
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();
462 * Tests threaded access.
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());
478 // wait for the treads to finish
481 } catch (final InterruptedException e) {
482 System.out.println("Thread 1 had a problem finishing. " + e);
488 } catch (final InterruptedException e) {
489 System.out.println("Thread 2 had a problem finishing. " + e);
495 } catch (final InterruptedException e) {
496 System.out.println("Thread 3 had a problem finishing. " + e);
502 } catch (final InterruptedException e) {
503 System.out.println("Thread 4 had a problem finishing. " + e);
509 * This method safely converts longs from libglom into ints. This method was taken from stackoverflow:
511 * http://stackoverflow.com/questions/1590831/safely-casting-long-to-int-in-java
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.");