1010
1111import static org .hamcrest .CoreMatchers .containsString ;
1212import static org .hamcrest .CoreMatchers .is ;
13+ import static org .hamcrest .CoreMatchers .nullValue ;
1314import static org .hamcrest .MatcherAssert .assertThat ;
1415import static org .mockito .Mockito .mock ;
16+ import static org .mockito .Mockito .spy ;
1517import static org .mockito .Mockito .when ;
18+ import static org .mockito .Mockito .withSettings ;
19+ import static schemacrawler .test .utility .crawl .LightCatalogUtility .lightCatalog ;
1620import static schemacrawler .test .utility .crawl .LightCatalogUtility .lightNamedObject ;
1721
22+ import java .util .Collection ;
1823import java .util .List ;
1924import org .junit .jupiter .api .Test ;
25+ import schemacrawler .ermodel .implementation .ERModelBuilder ;
26+ import schemacrawler .ermodel .model .ERModel ;
27+ import schemacrawler .ermodel .model .Entity ;
28+ import schemacrawler .ermodel .model .Relationship ;
29+ import schemacrawler .ermodel .model .RelationshipCardinality ;
30+ import schemacrawler .schema .Catalog ;
2031import schemacrawler .schema .Column ;
2132import schemacrawler .schema .ColumnReference ;
2233import schemacrawler .schema .ForeignKey ;
2334import schemacrawler .schema .Index ;
2435import schemacrawler .schema .NamedObject ;
36+ import schemacrawler .schema .NamedObjectKey ;
37+ import schemacrawler .schema .PartialDatabaseObject ;
2538import schemacrawler .schema .PrimaryKey ;
2639import schemacrawler .schema .Table ;
40+ import schemacrawler .schema .TableReference ;
41+ import schemacrawler .schema .TableType ;
42+ import schemacrawler .schema .View ;
2743import schemacrawler .test .utility .crawl .LightColumn ;
44+ import schemacrawler .test .utility .crawl .LightColumnReference ;
2845import schemacrawler .test .utility .crawl .LightForeignKey ;
2946import schemacrawler .test .utility .crawl .LightPrimaryKey ;
3047import schemacrawler .test .utility .crawl .LightTable ;
@@ -34,6 +51,110 @@ public class ScriptSupportTest {
3451
3552 private final ScriptSupport support = new ScriptSupport ();
3653
54+ @ Test
55+ public void cardinality () {
56+ // Null FK → unknown
57+ assertThat (support .cardinality (null ), is (RelationshipCardinality .unknown ));
58+
59+ // FK whose table is a PartialDatabaseObject → unknown
60+ final Table partialTable =
61+ mock (Table .class , withSettings ().extraInterfaces (PartialDatabaseObject .class ));
62+ final TableReference fkWithPartialTable = mock (TableReference .class );
63+ when (fkWithPartialTable .getForeignKeyTable ()).thenReturn (partialTable );
64+ assertThat (support .cardinality (fkWithPartialTable ), is (RelationshipCardinality .unknown ));
65+
66+ // Non-unique (no PK/index on FK table) + non-optional
67+ // (LightForeignKey.isOptional() = false)
68+ // → one_many
69+ final LightTable pkTable = new LightTable ("pk_table" );
70+ final LightTable fkTableOneMay = new LightTable ("fk_table_one_many" );
71+ final LightColumn fkCol1 = fkTableOneMay .addColumn ("fk_col" );
72+ final LightColumn pkCol1 = pkTable .addColumn ("pk_col1" );
73+ final LightForeignKey fkOneMay = new LightForeignKey ("FK_ONE_MANY" , fkCol1 , pkCol1 );
74+ assertThat (support .cardinality (fkOneMay ), is (RelationshipCardinality .one_many ));
75+
76+ // Unique (FK col matches FK-table's PK) + non-optional → one_one
77+ final LightTable fkTableOneOne = new LightTable ("fk_table_one_one" );
78+ final LightColumn fkCol2 = fkTableOneOne .addColumn ("fk_col" );
79+ final LightColumn pkCol2 = pkTable .addColumn ("pk_col2" );
80+ fkTableOneOne .setPrimaryKey (new LightPrimaryKey (fkCol2 ));
81+ final LightForeignKey fkOneOne = new LightForeignKey ("FK_ONE_ONE" , fkCol2 , pkCol2 );
82+ assertThat (support .cardinality (fkOneOne ), is (RelationshipCardinality .one_one ));
83+
84+ // Non-unique + optional (mocked TableReference) → zero_many
85+ final LightTable fkTableZeroMany = new LightTable ("fk_table_zero_many" );
86+ final LightColumn fkCol3 = fkTableZeroMany .addColumn ("fk_col" );
87+ final LightColumn pkCol3 = pkTable .addColumn ("pk_col3" );
88+ final LightColumnReference colRef3 = new LightColumnReference (fkCol3 , pkCol3 );
89+ final TableReference optionalFkZeroMany = mock (TableReference .class );
90+ when (optionalFkZeroMany .getForeignKeyTable ()).thenReturn (fkTableZeroMany );
91+ when (optionalFkZeroMany .isOptional ()).thenReturn (true );
92+ when (optionalFkZeroMany .getColumnReferences ()).thenReturn (List .of (colRef3 ));
93+ when (optionalFkZeroMany .key ()).thenReturn (new NamedObjectKey ("schema" , "FK_ZERO_MANY" ));
94+ assertThat (support .cardinality (optionalFkZeroMany ), is (RelationshipCardinality .zero_many ));
95+
96+ // Unique (FK col matches FK-table's PK) + optional → zero_one
97+ final LightTable fkTableZeroOne = new LightTable ("fk_table_zero_one" );
98+ final LightColumn fkCol4 = fkTableZeroOne .addColumn ("fk_col" );
99+ final LightColumn pkCol4 = pkTable .addColumn ("pk_col4" );
100+ fkTableZeroOne .setPrimaryKey (new LightPrimaryKey (fkCol4 ));
101+ final LightColumnReference colRef4 = new LightColumnReference (fkCol4 , pkCol4 );
102+ final TableReference optionalFkZeroOne = mock (TableReference .class );
103+ when (optionalFkZeroOne .getForeignKeyTable ()).thenReturn (fkTableZeroOne );
104+ when (optionalFkZeroOne .isOptional ()).thenReturn (true );
105+ when (optionalFkZeroOne .getColumnReferences ()).thenReturn (List .of (colRef4 ));
106+ when (optionalFkZeroOne .key ()).thenReturn (new NamedObjectKey ("schema" , "FK_ZERO_ONE" ));
107+ assertThat (support .cardinality (optionalFkZeroOne ), is (RelationshipCardinality .zero_one ));
108+ }
109+
110+ @ Test
111+ public void cardinalitySymbolForRelationship () {
112+ // Null relationship falls back to unknown → default Mermaid symbol
113+ assertThat (support .cardinalitySymbol ((Relationship ) null ), is ("}o--||" ));
114+
115+ final Relationship rel = mock (Relationship .class );
116+
117+ when (rel .getType ()).thenReturn (RelationshipCardinality .unknown );
118+ assertThat (support .cardinalitySymbol (rel ), is ("}o--||" ));
119+
120+ when (rel .getType ()).thenReturn (RelationshipCardinality .zero_one );
121+ assertThat (support .cardinalitySymbol (rel ), is ("|o--||" ));
122+
123+ when (rel .getType ()).thenReturn (RelationshipCardinality .zero_many );
124+ assertThat (support .cardinalitySymbol (rel ), is ("}o--||" ));
125+
126+ when (rel .getType ()).thenReturn (RelationshipCardinality .one_one );
127+ assertThat (support .cardinalitySymbol (rel ), is ("||--||" ));
128+
129+ when (rel .getType ()).thenReturn (RelationshipCardinality .one_many );
130+ assertThat (support .cardinalitySymbol (rel ), is ("}|--||" ));
131+
132+ when (rel .getType ()).thenReturn (RelationshipCardinality .many_many );
133+ assertThat (support .cardinalitySymbol (rel ), is ("}o--o{" ));
134+ }
135+
136+ @ Test
137+ public void cardinalitySymbolForTableReference () {
138+ // Null FK → unknown cardinality → default Mermaid symbol
139+ assertThat (support .cardinalitySymbol ((TableReference ) null ), is ("}o--||" ));
140+
141+ // Non-unique, non-optional FK → one_many
142+ final LightTable pkTableSym = new LightTable ("pk_table_sym" );
143+ final LightTable fkTableOneMay = new LightTable ("fk_table_sym_one_many" );
144+ final LightColumn fkCol1 = fkTableOneMay .addColumn ("fk_col" );
145+ final LightColumn pkCol1 = pkTableSym .addColumn ("pk_col1" );
146+ final LightForeignKey fkOneMay = new LightForeignKey ("FK_SYM_ONE_MANY" , fkCol1 , pkCol1 );
147+ assertThat (support .cardinalitySymbol (fkOneMay ), is ("}|--||" ));
148+
149+ // Unique (FK col = PK), non-optional FK → one_one
150+ final LightTable fkTableOneOne = new LightTable ("fk_table_sym_one_one" );
151+ final LightColumn fkCol2 = fkTableOneOne .addColumn ("fk_col" );
152+ final LightColumn pkCol2 = pkTableSym .addColumn ("pk_col2" );
153+ fkTableOneOne .setPrimaryKey (new LightPrimaryKey (fkCol2 ));
154+ final LightForeignKey fkOneOne = new LightForeignKey ("FK_SYM_ONE_ONE" , fkCol2 , pkCol2 );
155+ assertThat (support .cardinalitySymbol (fkOneOne ), is ("||--||" ));
156+ }
157+
37158 @ Test
38159 public void cleanFullName () {
39160 assertThat (support .cleanFullName (null ), is ("" ));
@@ -113,6 +234,36 @@ public void columnType() {
113234 assertThat (support .columnType (varcharColumn ), is ("VARCHAR" ));
114235 }
115236
237+ @ Test
238+ public void entities () {
239+ // No ER model set → empty
240+ assertThat (support .entities ().isEmpty (), is (true ));
241+
242+ // Strong entity table (table with PK) → entity included in result
243+ final LightTable entityTable = new LightTable ("ENTITY_TABLE" );
244+ final LightColumn pkCol = entityTable .addColumn ("ID" );
245+ entityTable .setPrimaryKey (new LightPrimaryKey (pkCol ));
246+ final Catalog catalogWithEntity = lightCatalog (entityTable );
247+ final ERModel erModelWithEntity = ERModelBuilder .builder (catalogWithEntity ).build ();
248+ final ScriptSupport supportWithEntity = new ScriptSupport ();
249+ supportWithEntity .setERModel (erModelWithEntity );
250+ final Collection <Entity > entities = supportWithEntity .entities ();
251+ assertThat (entities .size (), is (1 ));
252+ assertThat (entities .iterator ().next ().getTable (), is (entityTable ));
253+
254+ // View table → excluded from result
255+ final View mockView = mock (View .class );
256+ when (mockView .key ()).thenReturn (new NamedObjectKey ("schema" , "MOCK_VIEW" ));
257+ when (mockView .getImportedForeignKeys ()).thenReturn (List .of ());
258+ when (mockView .getColumns ()).thenReturn (List .of ());
259+ when (mockView .getTableType ()).thenReturn (new TableType ("VIEW" ));
260+ final Catalog catalogWithView = lightCatalog (mockView );
261+ final ERModel erModelWithView = ERModelBuilder .builder (catalogWithView ).build ();
262+ final ScriptSupport supportWithView = new ScriptSupport ();
263+ supportWithView .setERModel (erModelWithView );
264+ assertThat (supportWithView .entities ().isEmpty (), is (true ));
265+ }
266+
116267 @ Test
117268 public void foreignKeyColumns () {
118269 assertThat (support .fkColumns (null ), is ("" ));
@@ -154,6 +305,54 @@ public void indent() {
154305 assertThat (support .indent ("x" , 2 ), is (" x\n " ));
155306 }
156307
308+ @ Test
309+ public void isToMany () {
310+ // Null FK → unknown cardinality → not to-many
311+ assertThat (support .isToMany (null ), is (false ));
312+
313+ final LightTable pkTableToMany = new LightTable ("pk_table_to_many" );
314+
315+ // Non-unique, non-optional → one_many → to-many
316+ final LightTable fkTableOneMay = new LightTable ("fk_table_to_many_one_many" );
317+ final LightColumn fkCol1 = fkTableOneMay .addColumn ("fk_col" );
318+ final LightColumn pkCol1 = pkTableToMany .addColumn ("pk_col1" );
319+ final LightForeignKey fkOneMay = new LightForeignKey ("FK_TO_MANY_ONE_MANY" , fkCol1 , pkCol1 );
320+ assertThat (support .isToMany (fkOneMay ), is (true ));
321+
322+ // Non-unique, optional → zero_many → to-many
323+ final LightTable fkTableZeroMany = new LightTable ("fk_table_to_many_zero_many" );
324+ final LightColumn fkCol2 = fkTableZeroMany .addColumn ("fk_col" );
325+ final LightColumn pkCol2 = pkTableToMany .addColumn ("pk_col2" );
326+ final LightColumnReference colRef2 = new LightColumnReference (fkCol2 , pkCol2 );
327+ final TableReference optionalFkZeroMany = mock (TableReference .class );
328+ when (optionalFkZeroMany .getForeignKeyTable ()).thenReturn (fkTableZeroMany );
329+ when (optionalFkZeroMany .isOptional ()).thenReturn (true );
330+ when (optionalFkZeroMany .getColumnReferences ()).thenReturn (List .of (colRef2 ));
331+ when (optionalFkZeroMany .key ()).thenReturn (new NamedObjectKey ("schema" , "FK_TO_MANY_ZERO_MANY" ));
332+ assertThat (support .isToMany (optionalFkZeroMany ), is (true ));
333+
334+ // Unique (FK col = PK), non-optional → one_one → not to-many
335+ final LightTable fkTableOneOne = new LightTable ("fk_table_to_many_one_one" );
336+ final LightColumn fkCol3 = fkTableOneOne .addColumn ("fk_col" );
337+ final LightColumn pkCol3 = pkTableToMany .addColumn ("pk_col3" );
338+ fkTableOneOne .setPrimaryKey (new LightPrimaryKey (fkCol3 ));
339+ final LightForeignKey fkOneOne = new LightForeignKey ("FK_TO_MANY_ONE_ONE" , fkCol3 , pkCol3 );
340+ assertThat (support .isToMany (fkOneOne ), is (false ));
341+
342+ // Unique (FK col = PK), optional → zero_one → not to-many
343+ final LightTable fkTableZeroOne = new LightTable ("fk_table_to_many_zero_one" );
344+ final LightColumn fkCol4 = fkTableZeroOne .addColumn ("fk_col" );
345+ final LightColumn pkCol4 = pkTableToMany .addColumn ("pk_col4" );
346+ fkTableZeroOne .setPrimaryKey (new LightPrimaryKey (fkCol4 ));
347+ final LightColumnReference colRef4 = new LightColumnReference (fkCol4 , pkCol4 );
348+ final TableReference optionalFkZeroOne = mock (TableReference .class );
349+ when (optionalFkZeroOne .getForeignKeyTable ()).thenReturn (fkTableZeroOne );
350+ when (optionalFkZeroOne .isOptional ()).thenReturn (true );
351+ when (optionalFkZeroOne .getColumnReferences ()).thenReturn (List .of (colRef4 ));
352+ when (optionalFkZeroOne .key ()).thenReturn (new NamedObjectKey ("schema" , "FK_TO_MANY_ZERO_ONE" ));
353+ assertThat (support .isToMany (optionalFkZeroOne ), is (false ));
354+ }
355+
157356 @ Test
158357 public void nonPrimaryIndexes () {
159358 assertThat (support .nonPrimaryIndexes (null ).isEmpty (), is (true ));
@@ -229,6 +428,36 @@ public void stripName() {
229428 assertThat (support .stripName (namedObject ), is ("abcxyz" ));
230429 }
231430
431+ @ Test
432+ public void tableReference () {
433+ // Null column → null (isPartial(null) short-circuits to true)
434+ assertThat (support .tableReference (null ), is (nullValue ()));
435+
436+ // Partial column → null
437+ final Column partialColumn =
438+ mock (Column .class , withSettings ().extraInterfaces (PartialDatabaseObject .class ));
439+ assertThat (support .tableReference (partialColumn ), is (nullValue ()));
440+
441+ // LightColumn (isPartOfForeignKey() = false) → null
442+ final LightTable table = new LightTable ("t" );
443+ final LightColumn notFkCol = table .addColumn ("col" );
444+ assertThat (support .tableReference (notFkCol ), is (nullValue ()));
445+
446+ // Column is part of an FK, and the matching FK column reference is found →
447+ // returns the FK
448+ final LightTable pkTable = new LightTable ("pk_table" );
449+ final LightColumn pkCol = pkTable .addColumn ("pk_col" );
450+ final LightTable fkTable = spy (new LightTable ("fk_table" ));
451+ final Column fkCol = mock (Column .class );
452+ when (fkCol .isPartOfForeignKey ()).thenReturn (true );
453+ when (fkCol .getParent ()).thenReturn (fkTable );
454+ final LightColumnReference colRef = new LightColumnReference (fkCol , pkCol );
455+ final ForeignKey fk = mock (ForeignKey .class );
456+ when (fk .iterator ()).thenAnswer (inv -> List .of (colRef ).iterator ());
457+ when (fkTable .getImportedForeignKeys ()).thenReturn (List .of (fk ));
458+ assertThat (support .tableReference (fkCol ), is (fk ));
459+ }
460+
232461 @ Test
233462 public void type () {
234463 // getSimpleTypeName(null) returns "unknown", no NPE
0 commit comments