1+ import logging
2+
3+ import pytest
4+
5+ from linkml_runtime .linkml_model .meta import (
6+ ClassDefinition ,
7+ SlotDefinition ,
8+ )
9+ from linkml_runtime .processing import inlining
10+ from linkml_runtime .utils .schema_builder import SchemaBuilder
11+
12+
13+ def prepare_schema (with_identifier , inlined , inlined_as_list ):
14+ builder = SchemaBuilder ()
15+
16+ id = SlotDefinition (name = "id" , identifier = True )
17+ builder .add_slot (id )
18+
19+ range_class = ClassDefinition (name = "RangeClass" )
20+ if with_identifier :
21+ range_class .slots = ["id" ]
22+ builder .add_class (range_class )
23+
24+ slot = SlotDefinition (name = "slot_under_test" , range = range_class .name )
25+ if isinstance (inlined , bool ):
26+ slot .inlined = inlined
27+ if isinstance (inlined_as_list , bool ):
28+ slot .inlined_as_list = inlined_as_list
29+ builder .add_slot (slot )
30+
31+ slot_type = SlotDefinition (name = "slot_with_type" , range = "int" )
32+ if isinstance (inlined , bool ):
33+ slot_type .inlined = inlined
34+ if isinstance (inlined_as_list , bool ):
35+ slot_type .inlined_as_list = inlined_as_list
36+ builder .add_slot (slot_type )
37+
38+ return (slot , slot_type , {"schema" : builder .schema })
39+
40+
41+ @pytest .mark .parametrize (
42+ ("with_identifier" , "inlined" , "inlined_as_list" , "expected_inlined" , "expected_inlined_as_list" ),
43+ [
44+ (True , True , True , True , True ),
45+ (True , True , False , True , False ),
46+ (True , False , None , False , None ),
47+ (False , True , True , True , True ),
48+ ],
49+ )
50+ def test_report_ok (with_identifier , inlined , inlined_as_list , expected_inlined , expected_inlined_as_list , caplog ):
51+ """Test that combinations that are clear an unproblematic only generate debug output."""
52+ logger = logging .getLogger ("Test" )
53+ caplog .set_level (logging .DEBUG )
54+
55+ slot , _ , schema_map = prepare_schema (with_identifier , inlined , inlined_as_list )
56+ fixed_inlined , fixed_inlined_as_list = inlining .process (slot , schema_map , logger )
57+ assert fixed_inlined == expected_inlined
58+ assert fixed_inlined_as_list == expected_inlined_as_list
59+ for logrecord in caplog .records :
60+ assert logrecord .levelname == "DEBUG"
61+ assert " complete inlining specification" in logrecord .message
62+
63+
64+ @pytest .mark .parametrize (
65+ ("with_identifier" , "inlined" , "inlined_as_list" , "expected_inlined_as_list" ),
66+ [
67+ # overriding specified `inlined: false` with `inlined: true`!!
68+ (True , False , True , True ),
69+ ],
70+ )
71+ def test_force_inlined (with_identifier , inlined , inlined_as_list , expected_inlined_as_list , caplog ):
72+ """Test that combinations that end up forcing `inlined: true` does so and generate a warning."""
73+ logger = logging .getLogger ("Test" )
74+ caplog .set_level (logging .WARNING )
75+
76+ slot , _ , schema_map = prepare_schema (with_identifier , inlined , inlined_as_list )
77+ fixed_inlined , fixed_inlined_as_list = inlining .process (slot , schema_map , logger )
78+ assert fixed_inlined
79+ assert fixed_inlined_as_list == expected_inlined_as_list
80+ for logrecord in caplog .records :
81+ assert logrecord .levelname == "WARNING"
82+ assert "Forcing `inlined: true`!!" in logrecord .message
83+
84+
85+ @pytest .mark .parametrize (
86+ ("with_identifier" , "inlined" , "inlined_as_list" , "expected_inlined_as_list" ),
87+ [
88+ # applying implicit default!!
89+ (True , None , True , True ),
90+ # applying implicit default!!
91+ (False , None , True , True ),
92+ ],
93+ )
94+ def test_default_inlined (with_identifier , inlined , inlined_as_list , expected_inlined_as_list , caplog ):
95+ """Test that combinations that end up forcing `inlined: true` does so and generate a warning."""
96+ logger = logging .getLogger ("Test" )
97+ caplog .set_level (logging .INFO )
98+
99+ slot , _ , schema_map = prepare_schema (with_identifier , inlined , inlined_as_list )
100+ fixed_inlined , fixed_inlined_as_list = inlining .process (slot , schema_map , logger )
101+ assert fixed_inlined
102+ assert fixed_inlined_as_list == expected_inlined_as_list
103+ for logrecord in caplog .records :
104+ assert logrecord .levelname == "INFO"
105+ assert "Forcing `inlined: true`!!" in logrecord .message
106+
107+
108+ @pytest .mark .parametrize (
109+ ("with_identifier" , "inlined" , "inlined_as_list" , "expected_inlined" , "expected_inlined_as_list" ),
110+ [
111+ # what type of inlining to use?
112+ (True , True , None , True , None ),
113+ # why specifying inlining type if no inlining?
114+ (True , False , False , False , False ),
115+ # why specifying inlining type if inlining not requested?
116+ (True , None , False , None , False ),
117+ # no defaults, in-code implicit defaults will apply
118+ (True , None , None , None , None ),
119+ # how to select a key for an object without an identifier?
120+ (False , True , False , True , False ),
121+ # no defaults, in-code implicit defaults will apply
122+ (False , True , None , True , None ),
123+ # how to add a reference to an object without an identifier?
124+ (False , False , True , False , True ),
125+ # how to add a reference to an object without an identifier?
126+ (False , False , False , False , False ),
127+ # how to add a reference to an object without an identifier?
128+ (False , False , None , False , None ),
129+ # why specifying inlining type if inlining not requested?
130+ (False , None , False , None , False ),
131+ # no defaults, in-code implicit defaults will apply
132+ (False , None , None , None , None ),
133+ ],
134+ )
135+ def test_info_inconsistencies (with_identifier , inlined , inlined_as_list , expected_inlined , expected_inlined_as_list , caplog ):
136+ """Test that combinations that are somehow illogical or incomplete are reported."""
137+ logger = logging .getLogger ("Test" )
138+ caplog .set_level (logging .INFO )
139+
140+ slot , _ , schema_map = prepare_schema (with_identifier , inlined , inlined_as_list )
141+ fixed_inlined , fixed_inlined_as_list = inlining .process (slot , schema_map , logger )
142+ assert fixed_inlined == expected_inlined
143+ assert fixed_inlined_as_list == expected_inlined_as_list
144+ for logrecord in caplog .records :
145+ assert logrecord .levelname == "INFO"
146+ assert "illogic or incomplete inlining specification" in logrecord .message
147+
148+
149+ @pytest .mark .parametrize (
150+ ("with_identifier" , "inlined" , "inlined_as_list" ),
151+ [
152+ (True , True , True ),
153+ (True , True , False ),
154+ (True , True , None ),
155+ (True , False , True ),
156+ (True , False , False ),
157+ (True , False , None ),
158+ (True , None , True ),
159+ (True , None , False ),
160+ (True , None , None ),
161+ (False , True , True ),
162+ (False , True , False ),
163+ (False , True , None ),
164+ (False , False , True ),
165+ (False , False , False ),
166+ (False , False , None ),
167+ (False , None , True ),
168+ (False , None , False ),
169+ (False , None , None ),
170+ ]
171+ )
172+ def test_slot_type (with_identifier , inlined , inlined_as_list ):
173+ """Test that slots with a type as range returns (None, None)."""
174+ logger = logging .getLogger ("Test" )
175+ _ , slot , schema_map = prepare_schema (with_identifier , inlined , inlined_as_list )
176+ fixed_inlined , fixed_inlined_as_list = inlining .process (slot , schema_map , logger )
177+ assert fixed_inlined is None
178+ assert fixed_inlined_as_list is None
0 commit comments