Add a Field class and implement some loading of it in Document.
[online-glom:gwt-glom.git] / src / test / java / org / glom / web / shared / libglom / DocumentTest.java
1 /*
2  * Copyright (C) 2009, 2010, 2011 Openismus GmbH
3  *
4  * This file is part of Java-libglom.
5  *
6  * Java-libglom 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  * Java-libglom 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 Java-libglom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package org.glom.web.shared.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.util.List;
28
29 import org.glom.web.shared.libglom.Document;
30 import org.glom.libglom.Glom;
31 import org.glom.libglom.LayoutFieldVector;
32 import org.glom.libglom.LayoutGroup;
33 import org.glom.libglom.LayoutGroupVector;
34 import org.glom.libglom.LayoutItem;
35 import org.glom.libglom.LayoutItem_GroupBy;
36 import org.glom.libglom.LayoutItemVector;
37 import org.glom.libglom.LayoutItem_Field;
38 import org.glom.libglom.LayoutItem_Notebook;
39 import org.glom.libglom.LayoutItem_Portal;
40 import org.glom.libglom.NumericFormat;
41 import org.glom.libglom.Relationship;
42 import org.glom.libglom.SortClause;
43 import org.glom.libglom.SortFieldPair;
44 import org.glom.libglom.StringVector;
45 import org.junit.AfterClass;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48
49 /**
50  * Simple test to ensure that the generated bindings are working.
51  */
52 public class DocumentTest {
53
54         private static Document document;
55         private static String locale = ""; //This means the original locale.
56         final static String testUriMusicCollection = "src/test/java/org/glom/web/shared/libglom/example_music_collection.glom";
57         final static String testUriFilmManager = "src/test/java/org/glom/web/shared/libglom/example_film_manager.glom";
58
59         @BeforeClass
60         static public void setUp() {
61                 document = new Document();
62                 document.set_file_uri(testUriMusicCollection);
63                 int error = 0;
64                 boolean retval = document.load(error);
65                 assertTrue(retval);
66                 assertEquals(error, 0);
67         }
68
69         @AfterClass
70         static public void tearDown() {
71                 Glom.libglom_deinit();
72         }
73
74         @Test
75         public void testDocumentInfo() {
76                 assertThat(document.get_database_title_original(), is("Music Collection"));
77                 assertThat(document.get_default_table(), is("artists"));
78         }
79
80         @Test
81         public void testReadTableNames() {
82                 StringVector tableNames = document.get_table_names();
83                 assertEquals(4, tableNames.size());
84
85                 String tables = tableNames.get(0);
86                 for (int i = 1; i < tableNames.size(); i++) {
87                         tables += ", " + tableNames.get(i);
88                 }
89                 assertThat(tables, is("artists, albums, songs, publishers"));
90         }
91
92         @Test
93         public void testReadTableFieldSizes() {
94
95                 List<Field> fields = document.get_table_fields("albums");
96                 assertEquals(6, fields.size());
97
98                 Field field = fields.get(0);
99                 String titles = field.get_title_or_name(locale);
100                 for (int i = 1; i < fields.size(); i++) {
101                         field = fields.get(i);
102                         titles += ", " + field.get_title_or_name(locale);
103                 }
104                 assertThat(titles, is("Album ID, Comments, Name, Artist ID, Publisher ID, Year"));
105
106                 fields = document.get_table_fields("artists");
107                 assertEquals(4, fields.size());
108
109                 field = fields.get(0);
110                 titles = field.get_title_or_name(locale);
111                 for (int i = 1; i < fields.size(); i++) {
112                         field = fields.get(i);
113                         titles += ", " + field.get_title_or_name(locale);
114                 }
115                 assertThat(titles, is("Artist ID, Description, Comments, Name"));
116
117                 fields = document.get_table_fields("publishers");
118                 assertEquals(3, fields.size());
119
120                 field = fields.get(0);
121                 titles = field.get_title_or_name(locale);
122                 for (int i = 1; i < fields.size(); i++) {
123                         field = fields.get(i);
124                         titles += ", " + field.get_title_or_name(locale);
125                 }
126                 assertThat(titles, is("Publisher ID, Comments, Name"));
127
128                 fields = document.get_table_fields("songs");
129                 assertEquals(4, fields.size());
130
131                 field = fields.get(0);
132                 titles = field.get_title_or_name(locale);
133                 for (int i = 1; i < fields.size(); i++) {
134                         field = fields.get(i);
135                         titles += ", " + field.get_title_or_name(locale);
136                 }
137                 assertThat(titles, is("Song ID, Comments, Album ID, Name"));
138         }
139
140         @Test
141         public void testReadLayoutListInfo() {
142                 String[] tables = { "albums", "artists", "publishers", "songs" };
143                 int[] sortClauseSizes = { 0, 1, 1, 1 };
144                 int[] layoutFieldSizes = { 7, 4, 3, 4 };
145
146                 for (int i = 0; i < tables.length; i++) {
147                         LayoutGroupVector layoutList = document.get_data_layout_groups("list", tables[i]);
148                         LayoutItemVector layoutItems = layoutList.get(0).get_items();
149                         LayoutFieldVector layoutFields = new LayoutFieldVector();
150                         SortClause sortClause = new SortClause();
151                         int numItems = safeLongToInt(layoutItems.size());
152                         for (int j = 0; j < numItems; j++) {
153                                 LayoutItem item = layoutItems.get(j);
154                                 LayoutItem_Field field = LayoutItem_Field.cast_dynamic(item);
155                                 if (field != null) {
156                                         layoutFields.add(field);
157                                         Field details = field.get_full_field_details();
158                                         if (details != null && details.get_primary_key()) {
159                                                 sortClause.add(new SortFieldPair(field, true)); // ascending
160                                         }
161                                 }
162                         }
163                         assertEquals(sortClauseSizes[i], sortClause.size());
164                         assertEquals(layoutFieldSizes[i], safeLongToInt(layoutFields.size()));
165                 }
166         }
167
168         /*
169          * This tests if getting values from a NumericFormat object is working. This test was failing with a JVM crash when
170          * using the glom_sharedptr macro with Glom::UsesRelationship and Glom::Formatting.
171          */
172         @Test
173         public void testGetNumericFormat() {
174                 StringVector tableNames = document.get_table_names();
175
176                 for (int i = 0; i < tableNames.size(); i++) {
177                         String table = tableNames.get(i);
178                         LayoutGroupVector layoutList = document.get_data_layout_groups("list", table);
179                         LayoutItemVector layoutItems = layoutList.get(0).get_items();
180                         int numItems = safeLongToInt(layoutItems.size());
181                         for (int j = 0; j < numItems; j++) {
182                                 LayoutItem item = layoutItems.get(j);
183                                 LayoutItem_Field item_field = LayoutItem_Field.cast_dynamic(item);
184                                 if (item_field != null) {
185                                         // don't keep a reference to the FeildFormatting object
186                                         NumericFormat numFormat = item_field.get_formatting_used().get_numeric_format();
187
188                                         // get the values
189                                         boolean altForegroundColorForNegatives = numFormat.get_alt_foreground_color_for_negatives();
190                                         String currencySymbol = numFormat.get_currency_symbol();
191                                         long decimalPlaces = numFormat.get_decimal_places();
192                                         boolean decimalPlacesRestricted = numFormat.get_decimal_places_restricted();
193                                         boolean useThousandsSepator = numFormat.get_use_thousands_separator();
194                                         String alternativeColorForNegatives = NumericFormat.get_alternative_color_for_negatives();
195                                         long defaultPrecision = NumericFormat.get_default_precision();
196
197                                         // Simulate a garbage collection
198                                         System.gc();
199                                         System.runFinalization();
200
201                                         // re-get the values and test
202                                         assertEquals(altForegroundColorForNegatives, numFormat.get_alt_foreground_color_for_negatives());
203                                         assertEquals(currencySymbol, numFormat.get_currency_symbol());
204                                         assertEquals(decimalPlaces, numFormat.get_decimal_places());
205                                         assertEquals(decimalPlacesRestricted, numFormat.get_decimal_places_restricted());
206                                         assertEquals(useThousandsSepator, numFormat.get_use_thousands_separator());
207                                         assertEquals(alternativeColorForNegatives, NumericFormat.get_alternative_color_for_negatives());
208                                         assertEquals(defaultPrecision, NumericFormat.get_default_precision());
209
210                                 }
211                         }
212                 }
213         }
214
215         /*
216          * A smoke test for the methods added to LayoutItem_Field for accessing methods in Glom::UsesRelationship.
217          */
218         @Test
219         public void testUsesRelationshipMethods() {
220                 String table = "albums";
221                 LayoutGroupVector layoutList = document.get_data_layout_groups("list", table);
222                 LayoutItemVector layoutItems = layoutList.get(0).get_items();
223
224                 String names = null, hasRelationshipNames = null, tablesUsed = null;
225                 LayoutItem firstItem = layoutItems.get(0);
226                 LayoutItem_Field firstItemField = LayoutItem_Field.cast_dynamic(firstItem);
227                 if (firstItemField != null) {
228                         names = firstItemField.get_name();
229                         hasRelationshipNames = "" + firstItemField.get_has_relationship_name();
230                         tablesUsed = firstItemField.get_table_used(table);
231                 }
232                 int numItems = safeLongToInt(layoutItems.size());
233                 for (int j = 1; j < numItems; j++) {
234                         LayoutItem item = layoutItems.get(j);
235                         LayoutItem_Field itemField = LayoutItem_Field.cast_dynamic(item);
236                         if (itemField != null) {
237                                 names += ", " + itemField.get_name();
238                                 hasRelationshipNames += ", " + itemField.get_has_relationship_name();
239                                 tablesUsed += ", " + itemField.get_table_used(table);
240                         }
241                 }
242                 assertEquals("name, year, artist_id, name, publisher_id, name, comments", names);
243                 assertEquals("false, false, false, true, false, true, false", hasRelationshipNames);
244                 assertEquals("albums, albums, albums, artists, albums, publishers, albums", tablesUsed);
245         }
246
247         @Test
248         public void testGetSuitableTableToViewDetails() {
249
250                 // Create a new document for the film manager
251                 Document filmManagerDocument = new Document();
252                 filmManagerDocument.set_file_uri(testUriFilmManager);
253                 int error = 0;
254                 boolean retval = filmManagerDocument.load(error);
255                 assertTrue(retval);
256                 assertEquals(error, 0);
257
258                 // Get the "Scene Cast" related list portal. This relies on specific details of the film manager details
259                 // view layout. I've included safety checks that will fail if the layout changes.
260                 LayoutGroupVector detailsLayout = filmManagerDocument.get_data_layout_groups("details", "scenes");
261                 assertEquals(3, detailsLayout.size());
262
263                 LayoutGroup layoutGroup = detailsLayout.get(1);
264                 assertEquals("details", layoutGroup.get_name());
265
266                 layoutGroup = detailsLayout.get(2);
267                 assertEquals("details_lower", layoutGroup.get_name());
268
269                 LayoutItemVector items = layoutGroup.get_items();
270                 assertEquals(2, items.size());
271
272                 LayoutItem notebookItem = items.get(0);
273                 assertEquals("notebook", notebookItem.get_name());
274                 LayoutItem_Notebook notebook = LayoutItem_Notebook.cast_dynamic(notebookItem);
275                 items = notebook.get_items();
276                 assertEquals(7, items.size());
277                 LayoutItem portalItem = items.get(0);
278                 LayoutItem_Portal portal = LayoutItem_Portal.cast_dynamic(portalItem);
279                 assertTrue(portal != null);
280
281                 // call get_suitable_table_to_view_details
282                 StringBuffer navigation_table_name = new StringBuffer();
283                 LayoutItem_Field navigation_relationship = new LayoutItem_Field(); // LayoutItem_Field is being used in place of
284                                                                                                                                                         // UsesRelationship
285                 //TODO: portal.get_suitable_table_to_view_details(navigation_table_name, navigation_relationship, filmManagerDocument);
286
287                 // Simulate a garbage collection
288                 System.gc();
289                 System.runFinalization();
290
291                 // Check if things are working like we expect
292                 assertEquals("characters", navigation_table_name.toString());
293                 assertTrue(navigation_relationship != null);
294                 Relationship relationship = navigation_relationship.get_relationship();
295                 assertTrue(relationship != null);
296                 assertEquals("cast", relationship.get_name());
297                 assertTrue(navigation_relationship.get_related_relationship() == null);
298
299         }
300
301         @Test
302         public void testReadReportNames() {
303                 StringVector reportNames = document.get_report_names("albums");
304                 assertEquals(1, reportNames.size()); //TODO: Test something with more reports.
305
306                 String reports = reportNames.get(0);
307                 for (int i = 1; i < reportNames.size(); i++) {
308                         reports += ", " + reportNames.get(i);
309                 }
310                 assertThat(reports, is("albums_by_artist"));
311         }
312
313         @Test
314         public void testReadReportStructure() {
315                 Report report = document.get_report("albums", "albums_by_artist");
316                 assertTrue(report != null);
317                 LayoutGroup layoutGroup = report.get_layout_group();
318                 assertTrue(layoutGroup != null);
319                 LayoutItemVector layoutItems = layoutGroup.get_items();
320                 final int numItems = safeLongToInt(layoutItems.size());
321                 assertEquals(1, numItems);
322
323                 LayoutItem layoutItem = layoutItems.get(0);
324                 assertTrue(layoutItem != null);
325                 LayoutGroup asGroup = LayoutGroup.cast_dynamic(layoutItem);
326                 assertTrue(asGroup != null);
327                 LayoutItem_GroupBy groupby = LayoutItem_GroupBy.cast_dynamic(layoutItem);
328                 assertTrue(groupby != null);
329
330                 assertTrue(groupby.get_has_field_group_by());
331                 LayoutItem_Field fieldGroupBy = groupby.get_field_group_by();
332                 assertTrue(fieldGroupBy != null);
333                 assertThat(fieldGroupBy.get_name(), is("artist_id"));
334
335                 LayoutGroup groupSecondaries = groupby.get_secondary_fields();
336                 assertTrue(groupSecondaries != null);
337
338                 LayoutItemVector innerItems = groupby.get_items();
339                 assertTrue(innerItems != null);
340                 final int numInnerItems = safeLongToInt(innerItems.size());
341                 assertEquals(2, numInnerItems);
342
343                 layoutItem = layoutItems.get(0);
344                 assertTrue(layoutItem != null);
345                 LayoutItem_Field field = LayoutItem_Field.cast_dynamic(layoutItem);
346                 assertTrue(field != null);
347                 assertThat(field.get_name(), is("name"));
348                 assertThat(field.get_glom_type(), is(Field.glom_field_type.TYPE_TEXT));
349
350                 layoutItem = layoutItems.get(1);
351                 assertTrue(layoutItem != null);
352                 field = LayoutItem_Field.cast_dynamic(layoutItem);
353                 assertTrue(field != null);
354                 assertThat(field.get_name(), is("year"));
355                 assertThat(field.get_glom_type(), is(Field.glom_field_type.TYPE_NUMERIC));
356         }
357
358         // Test thread class that runs all the tests.
359         private class TestThread implements Runnable {
360
361                 public void run() {
362                         for (int i = 0; i < 20; i++) {
363                                 testDocumentInfo();
364                                 testGetNumericFormat();
365                                 testGetSuitableTableToViewDetails();
366                                 testReadLayoutListInfo();
367                                 testReadTableFieldSizes();
368                                 testReadTableNames();
369                                 testUsesRelationshipMethods();
370                         }
371                 }
372         }
373
374         /*
375          * Tests threaded access to java-libglom.
376          */
377         @Test
378         public void testThreadedAccess() throws InterruptedException {
379                 // create the threads
380                 Thread thread1 = new Thread(new TestThread());
381                 Thread thread2 = new Thread(new TestThread());
382                 Thread thread3 = new Thread(new TestThread());
383                 Thread thread4 = new Thread(new TestThread());
384
385                 // start the threads
386                 thread1.start();
387                 thread2.start();
388                 thread3.start();
389                 thread4.start();
390
391                 // wait for the treads to finish
392                 try {
393                         thread1.join();
394                 } catch (InterruptedException e) {
395                         System.out.println("Thread 1 had a problem finishing. " + e);
396                         throw e;
397                 }
398
399                 try {
400                         thread2.join();
401                 } catch (InterruptedException e) {
402                         System.out.println("Thread 2 had a problem finishing. " + e);
403                         throw e;
404                 }
405
406                 try {
407                         thread3.join();
408                 } catch (InterruptedException e) {
409                         System.out.println("Thread 3 had a problem finishing. " + e);
410                         throw e;
411                 }
412
413                 try {
414                         thread4.join();
415                 } catch (InterruptedException e) {
416                         System.out.println("Thread 4 had a problem finishing. " + e);
417                         throw e;
418                 }
419         }
420
421         /*
422          * This method safely converts longs from libglom into ints. This method was taken from stackoverflow:
423          * 
424          * http://stackoverflow.com/questions/1590831/safely-casting-long-to-int-in-java
425          */
426         private static int safeLongToInt(long l) {
427                 if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
428                         throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
429                 }
430                 return (int) l;
431         }
432
433 }