1. Project Clover database Wed Nov 12 2025 05:07:35 UTC
  2. Package guru.mikelue.foxglove.jdbc

File JdbcTableFacetTest.java

 

Code metrics

6
92
18
4
601
448
23
0.25
5.11
4.5
1.28

Classes

Class Line # Actions
JdbcTableFacetTest 29 17 0% 3 0
1.0100%
JdbcTableFacetTest.TestCase 123 0 - 0 0
-1.0 -
JdbcTableFacetTest.BuilderTest 173 75 0% 20 0
1.0100%
JdbcTableFacetTest.BuilderTest.TestCase 384 0 - 0 0
-1.0 -
 

Contributing tests

This file is covered by 36 tests. .

Source view

1    package guru.mikelue.foxglove.jdbc;
2   
3    import java.sql.JDBCType;
4    import java.util.ArrayList;
5    import java.util.HashMap;
6    import java.util.List;
7    import java.util.Map;
8    import java.util.function.Consumer;
9    import java.util.stream.IntStream;
10    import java.util.stream.Stream;
11   
12    import org.junit.jupiter.api.Nested;
13    import org.junit.jupiter.api.Test;
14    import org.junit.jupiter.params.ParameterizedTest;
15    import org.junit.jupiter.params.provider.Arguments;
16    import org.junit.jupiter.params.provider.CsvSource;
17    import org.junit.jupiter.params.provider.MethodSource;
18   
19    import guru.mikelue.foxglove.TupleAccessor;
20    import guru.mikelue.foxglove.functional.SupplierDecider;
21    import guru.mikelue.foxglove.setting.DataSetting;
22    import guru.mikelue.misc.testlib.AbstractTestBase;
23   
24    import static guru.mikelue.foxglove.ColumnMetaTestUtils.newColumnMeta;
25    import static org.assertj.core.api.Assertions.assertThat;
26    import static org.assertj.core.api.Assertions.assertThatThrownBy;
27    import static org.junit.jupiter.params.provider.Arguments.arguments;
28   
 
29    public class JdbcTableFacetTest extends AbstractTestBase {
30    /**
31    * Tests the column for referencing another table.
32    */
 
33  1 toggle @Test
34    void referencing()
35    {
36  1 final int numberOfParents = gen().ints().range(3, 6).get();
37  1 final int numberOfChildrenPerParent = gen().ints().range(2, 4).get();
38   
39  1 var parentTable = JdbcTableFacet.builder("parent_table")
40    .keyOfInt("pt_id").limit(10, numberOfParents)
41    .build();
42   
43  1 var childTable = JdbcTableFacet.builder("child_table")
44    .referencing("ch_pt_id")
45    .parent(parentTable, "pt_id")
46    .cardinality(numberOfChildrenPerParent)
47    .build();
48   
49    /*
50    * Simulates the id values in parent table
51    currentMeta.properties(),
52    */
53  1 var columnMetaOfParentId = newColumnMeta(
54    "pt_id", JDBCType.INTEGER
55    );
56  1 var tupleSchema = new TupleAccessorImpl.TupleSchema(
57    List.of(columnMetaOfParentId)
58    );
59   
60  1 IntStream.range(0, numberOfParents)
61    .<TupleAccessor>mapToObj(i -> tupleSchema.createTupleAccessor(
62    Map.of(columnMetaOfParentId, 10 + i), i
63    ))
64    .forEach(parentTable.getValueTomb()::preserveProtoData);
65    // :~)
66   
67    /*
68    * Asserts the expected number of rows in child table
69    */
70  1 assertThat(childTable.getNumberOfRows())
71    .isEqualTo(numberOfParents * numberOfChildrenPerParent);
72    // :~)
73   
74  1 var testedSupplier = childTable.resolveSupplier(
75    newColumnMeta("ch_pt_id", JDBCType.INTEGER)
76    )
77    .get();
78   
79    /*
80    * Asserts teh values of referencing column
81    */
82  1 assertThat(
83    Stream.generate(testedSupplier)
84    .limit(childTable.getNumberOfRows())
85    )
86    .containsExactly(
87    IntStream.range(0, numberOfParents)
88    .map(i -> 10 + i)
89    .flatMap(i ->
90    IntStream.range(0, numberOfChildrenPerParent)
91    .map(j -> i)
92    )
93    .boxed()
94    .toArray()
95    );
96    // :~)
97    }
98   
99    /**
100    * Tests the building for number of rows.
101    */
 
102  5 toggle @ParameterizedTest
103    @MethodSource
104    void getNumberOfRows(
105    Consumer<JdbcTableFacet.Builder> builderSetup,
106    int expectedNumberOfRows
107    ) {
108  5 var builder = JdbcTableFacet.builder("TEST_TABLE");
109  5 builderSetup.accept(builder);
110   
111  5 var tableFacet = builder.build();
112   
113  5 assertThat(tableFacet.tableName())
114    .isEqualTo("TEST_TABLE");
115   
116  5 assertThat(tableFacet.getNumberOfRows())
117    .isEqualTo(expectedNumberOfRows);
118   
119    }
120   
 
121  1 toggle static Stream<Arguments> getNumberOfRows()
122    {
 
123    record TestCase(
124    Consumer<JdbcTableFacet.Builder> builderSetup,
125    int expectedNumberOfRows
126  1 ) {};
127   
128  1 return Stream.of(
129    // Builder's numberOfRows take precedence
130    new TestCase(
131    builder -> builder.numberOfRows(15)
132    .withSetting(
133    new DataSetting().setDefaultNumberOfRows(20)
134    ),
135    15
136    ),
137    // Setting's defaultNumberOfRows is used
138    new TestCase(
139    builder -> builder
140    .withSetting(
141    new DataSetting().setDefaultNumberOfRows(20)
142    ),
143    20
144    ),
145    // Use global setting
146    new TestCase(
147    builder -> {},
148    DataSetting.defaults().getDefaultNumberOfRows()
149    ),
150    // By key column
151    new TestCase(
152    builder -> builder
153    .keyOfInt("tt_id").range(1, 100),
154    99
155    ),
156    // By cartesian product
157    new TestCase(
158    builder -> builder
159    .cartesianProduct("tt_weight")
160    .domain(10, 20)
161    .cartesianProduct("tt_color")
162    .domain("GREEN", "RED"),
163    4
164    )
165    )
166    .map(c -> arguments(
167    c.builderSetup(),
168    c.expectedNumberOfRows()
169    ));
170    }
171   
172    @Nested
 
173    class BuilderTest {
174    /**
175    * Tests the conflicting for number of rows.
176    */
 
177  5 toggle @ParameterizedTest
178    @MethodSource
179    void conflictNumberOfRows(
180    Consumer<JdbcTableFacet.Builder> builderSetup
181    ) {
182  5 assertThatThrownBy(() -> {
183  5 var builder = JdbcTableFacet.builder("TEST_TABLE");
184   
185  5 try {
186  5 builderSetup.accept(builder);
187    } catch (Throwable e) {
188  5 getLogger().debug("Column conflict: {}", e.getMessage());
189  5 throw e;
190    }
191    })
192    .isInstanceOf(IllegalArgumentException.class);
193    }
 
194  1 toggle static Stream<Consumer<JdbcTableFacet.Builder>> conflictNumberOfRows()
195    {
196  1 return Stream.<Consumer<JdbcTableFacet.Builder>>of(
197    // Has defined by numberOfRows()
198    builder -> builder
199    .numberOfRows(10)
200    .keyOfInt("key_1").range(1, 20),
201    // Has defined by numberOfRows()
202    builder -> builder
203    .numberOfRows(10)
204    .cartesianProduct("cp_1").domain(1, 2, 3),
205    // Has defined by key column
206    builder -> builder
207    .keyOfInt("key_1").range(1, 20)
208    .numberOfRows(10),
209    // Has defined by Cartesian product
210    builder -> builder
211    .cartesianProduct("cp_1").domain(1, 2, 3)
212    .numberOfRows(10),
213    // Has defined by Cartesian product
214    builder -> builder
215    .cartesianProduct("cp_1").domain(1, 2, 3)
216    .keyOfInt("cp_1").range(1, 10)
217    );
218    }
219   
220    /**
221    * Tests the conflicting settings for columns.
222    */
 
223  10 toggle @ParameterizedTest
224    @MethodSource
225    void conflictColumns(
226    Consumer<JdbcTableFacet.Builder> builderSetup
227    ) {
228  10 assertThatThrownBy(() -> {
229  10 var builder = JdbcTableFacet.builder("TEST_TABLE");
230   
231  10 try {
232  10 builderSetup.accept(builder);
233    } catch (Throwable e) {
234  10 getLogger().debug("Column conflict: {}", e.getMessage());
235  10 throw e;
236    }
237    })
238    .isInstanceOf(IllegalArgumentException.class);
239    }
 
240  1 toggle static Stream<Consumer<JdbcTableFacet.Builder>> conflictColumns()
241    {
242  1 return Stream.<Consumer<JdbcTableFacet.Builder>>of(
243    // Defines same columns
244    builder -> builder
245    .column("same_1").fixed("A")
246    .column("same_1").fixed("B"),
247    // Includes same columns
248    builder -> builder
249    .includeColumns("in_1").includeColumns("in_1"),
250    // Excludes same columns
251    builder -> builder
252    .excludeColumns("ex_1").excludeColumns("ex_1"),
253    // Include/Exclude at same time
254    builder -> builder
255    .includeColumns("in_ex_1").excludeColumns("in_ex_2"),
256    // Includes a column with SupplierDecider
257    builder -> builder
258    .column("su_1").fixed(10)
259    .includeColumns("su_1"),
260    // Defines a column with included
261    builder -> builder
262    .includeColumns("in_1")
263    .column("in_1"),
264    // Excludes a column with SupplierDecider
265    builder -> builder
266    .column("su_1").fixed(10)
267    .excludeColumns("su_1"),
268    // Defines a column with excluded
269    builder -> builder
270    .excludeColumns("ex_1")
271    .column("ex_1").fixed(100),
272    // Conflicts with key
273    builder -> builder
274    .keyOfInt("key_1").range(1, 10)
275    .column("key_1").fixed(10),
276    // Conflicts with Cartesian product
277    builder -> builder
278    .cartesianProduct("cp_1").domain(10, 20)
279    .column("cp_1").fixed(100)
280    );
281    }
282   
283    /**
284    * Tests the checking for columns with viable {@link SupplierDecider}.
285    */
 
286  2 toggle @ParameterizedTest
287    @CsvSource({
288    "in_1,Include",
289    "in_2,NotSet",
290    })
291    void supplierDecider(
292    String columnName, ColumnInclusionMode expectedMode
293    ) {
294  2 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
295    .column("in_1")
296    .roundRobin(10, 20, 30)
297    .build();
298   
299  2 var columnMeta = newColumnMeta(columnName);
300   
301  2 assertThat(tableFacet.getColumnInclusion(columnMeta))
302    .isEqualTo(expectedMode);
303    }
304   
305    /**
306    * Tests the key column generator.
307    */
 
308  2 toggle @ParameterizedTest
309    @MethodSource
310    void keyOfInt(
311    Consumer<JdbcTableFacet.Builder> builderSetup,
312    long[] expectedValues
313    ) {
314  2 var builder = JdbcTableFacet.builder("TEST_TABLE");
315  2 builderSetup.accept(builder);
316   
317  2 var tableFacet = builder.build();
318   
319    /*
320    * Generates the values to be tested
321    */
322  2 assertThat(tableFacet.getNumberOfRows())
323    .isEqualTo(expectedValues.length);
324   
325  2 var testedSupplier = tableFacet.<Long>resolveSupplier(
326    newColumnMeta("key_col", JDBCType.INTEGER)
327    ).get();
328   
329  2 var testedValues = new long[expectedValues.length];
330  12 for (int i = 0; i < expectedValues.length; i++) {
331  10 testedValues[i] = testedSupplier.get();
332    }
333    // :~)
334   
335  2 assertThat(testedValues)
336    .isEqualTo(expectedValues);
337    }
 
338  1 toggle static Stream<Arguments> keyOfInt()
339    {
340    record TestCase(
341    Consumer<JdbcTableFacet.Builder> builderSetup,
342    long[] expectedValues
343  1 ) {};
344   
345  1 return Stream.<TestCase>of(
346    new TestCase(
347    builder -> builder
348    .keyOfInt("key_col").range(1, 6),
349    new long[] {1, 2, 3, 4, 5}
350    ),
351    new TestCase(
352    builder -> builder
353    .keyOfInt("key_col").limit(10, 5),
354    new long[] {10, 11, 12, 13, 14}
355    )
356    )
357    .map(c -> arguments(
358    c.builderSetup(),
359    c.expectedValues()
360    ));
361    }
362   
363    /**
364    * Tests the supplier for Cartesian product.
365    */
 
366  2 toggle @ParameterizedTest
367    @MethodSource
368    void cartesianProduct(
369    Consumer<JdbcTableFacet.Builder> builderSetup,
370    Map<String, List<?>> expectedValues
371    ) {
372  2 var builder = JdbcTableFacet.builder("TEST_TABLE");
373  2 builderSetup.accept(builder);
374   
375  2 var tableFacet = builder.build();
376  2 tableFacet.getNumberOfRows(); // Triggers the generation
377   
378  2 assertCartesianProduct(
379    tableFacet, expectedValues
380    );
381    }
 
382  1 toggle static Stream<Arguments> cartesianProduct()
383    {
 
384    record TestCase(
385    Consumer<JdbcTableFacet.Builder> builderSetup,
386    Map<String, List<?>> expectedValues
387  1 ) {};
388   
389  1 return Stream.<TestCase>of(
390    // Single column
391    new TestCase(
392    builder -> builder
393    .cartesianProduct("cp_1").domain(11, 12, 13),
394    Map.of("cp_1", List.of(11, 12, 13))
395    ),
396    // Complex case
397    new TestCase(
398    builder -> builder
399    .cartesianProduct("cp_1")
400    .domain(1, 2)
401    .cartesianProduct("cp_2")
402    .domain("A", "B"),
403    Map.of(
404    "cp_1", List.of(1, 1, 2, 2),
405    "cp_2", List.of("A", "B", "A", "B")
406    )
407    )
408    )
409    .map(c -> arguments(
410    c.builderSetup(),
411    c.expectedValues()
412    ));
413    }
414   
415    /**
416    * Tests the Cartesian product by referencing other tables.
417    */
 
418  1 toggle @Test
419    void cartesianProductByReferencing()
420    {
421  1 var referentTableA = JdbcTableFacet.builder("rt_a")
422    .keyOfInt("ra_id").limit(100, 3)
423    .build();
424  1 var referentTableB = JdbcTableFacet.builder("rt_b")
425    .keyOfInt("rb_id").limit(70, 3)
426    .build();
427   
428  1 var expectedValues = Map.<String, List<?>>of(
429    "tt_ra_id", List.of(100, 100, 100, 101, 101, 101, 102, 102, 102),
430    "tt_rb_id", List.of(70, 71, 72, 70, 71, 72, 70, 71, 72)
431    );
432   
433    /*
434    * Prepares data of ids in referent tables
435    */
436  1 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
437    .cartesianProduct("tt_ra_id")
438    .referencing(referentTableA, "ra_id")
439    .cartesianProduct("tt_rb_id")
440    .referencing(referentTableB, "rb_id")
441    .build();
442   
443  1 TombTestUtils.setupTomb(
444    referentTableA.getValueTomb(), "ra_id",
445    100, 101, 102
446    );
447  1 TombTestUtils.setupTomb(
448    referentTableB.getValueTomb(), "rb_id",
449    70, 71, 72
450    );
451   
452  1 tableFacet.getNumberOfRows(); // Triggers the generation
453    // :~)
454   
455  1 assertCartesianProduct(
456    tableFacet, expectedValues
457    );
458    }
459   
 
460  3 toggle private static void assertCartesianProduct(
461    JdbcTableFacet testedTable,
462    Map<String, List<?>> expectedValues
463    ) {
464    /*
465    * Asserts values of every columns expanded by Cartesian product
466    */
467  3 for (var entry: expectedValues.entrySet()) {
468  5 var columnName = entry.getKey();
469  5 var expectedColumnValues = entry.getValue();
470   
471    /*
472    * Generates the values to be tested
473    */
474  5 var columnMeta = newColumnMeta(columnName);
475  5 var testedSupplier = testedTable.<Object>resolveSupplier(columnMeta).get();
476   
477  5 var testedColumnValues = new ArrayList<Object>(expectedColumnValues.size());
478  34 for (int i = 0; i < expectedColumnValues.size(); i++) {
479  29 testedColumnValues.add(testedSupplier.get());
480    }
481    // :~)
482   
483    /*
484    * Asserts the values for a column
485    */
486  5 assertThat(testedColumnValues)
487    .as("For column: %s", columnName)
488    .isEqualTo(expectedColumnValues);
489    // :~)
490    }
491    // :~)
492    }
493    /**
494    * Tests the checking for inclusion of columns.
495    */
 
496  3 toggle @ParameterizedTest
497    @CsvSource({
498    "in_1,Include",
499    "in_2,Include",
500    "out_1,Exclude",
501    })
502    void includeColumns(
503    String columnName, ColumnInclusionMode expectedMode
504    ) {
505  3 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
506    .includeColumns("in_1", "in_2")
507    .build();
508   
509  3 var columnMeta = newColumnMeta(columnName);
510   
511  3 assertThat(tableFacet.getColumnInclusion(columnMeta))
512    .isEqualTo(expectedMode);
513    }
514   
515    /**
516    * Tests the checking for exclusion of columns.
517    */
 
518  3 toggle @ParameterizedTest
519    @CsvSource({
520    "in_1,NotSet", // included by default
521    "out_2,Exclude",
522    "out_1,Exclude",
523    })
524    void excludeColumns(
525    String columnName, ColumnInclusionMode expectedMode
526    ) {
527  3 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
528    .excludeColumns("out_1", "out_2")
529    .build();
530   
531  3 var columnMeta = newColumnMeta(columnName);
532   
533  3 assertThat(tableFacet.getColumnInclusion(columnMeta))
534    .isEqualTo(expectedMode);
535    }
536   
537    /**
538    * Tests the supplier converting row index to value.
539    */
 
540  1 toggle @Test
541    void forRow()
542    {
543  1 final int TIMES = 5;
544   
545  1 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
546    .column("int_value")
547    .forRow(i -> i * 2)
548    .build();
549   
550  1 var columnMeta = newColumnMeta("int_value");
551   
552  1 var testedValue = new ArrayList<Integer>(TIMES);
553  1 var testedSupplier = tableFacet.<Integer>resolveSupplier(columnMeta).get();
554   
555  6 for (int i = 0; i < TIMES; i++) {
556  5 testedValue.add(testedSupplier.get());
557    }
558   
559  1 assertThat(testedValue)
560    .isEqualTo(List.of(0, 2, 4, 6, 8));
561    }
562   
563    /**
564    * Tests the modification after row generating.
565    */
 
566  1 toggle @Test
567    void onTupleGenerated()
568    {
569  1 var tableFacet = JdbcTableFacet.builder("TEST_TABLE")
570    .column("tb_value")
571    .fixed(1)
572    .includeColumns("tb_value2")
573    .onTupleGenerated(tuple -> {
574  1 var baseValue = tuple.<Integer>getValue("tb_value");
575  1 tuple.setValue("tb_value2", baseValue + 10);
576    })
577    .build();
578   
579  1 var testedValues = List.of(1, -1);
580  1 var sampleMetaOfColumns = List.of(
581    newColumnMeta("tb_value"),
582    newColumnMeta("tb_value2")
583    );
584  1 var tupleSchema = new TupleAccessorImpl.TupleSchema(
585    sampleMetaOfColumns
586    );
587  1 var sampleTuple = tupleSchema.createTupleAccessor(
588    Map.of(
589    sampleMetaOfColumns.get(0), testedValues.get(0),
590    sampleMetaOfColumns.get(1), testedValues.get(1)
591    ), 0
592    );
593   
594  1 tableFacet.getHandlerOfTuple()
595    .accept(sampleTuple);
596   
597  1 assertThat(sampleTuple.<Integer>getValue("tb_value2"))
598    .isEqualTo(11);
599    }
600    }
601    }