1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 /**
28 * Unit tests for view declarations in schema, this file is #included into a bigger test suite
29 */
30 
FIXTURE_TEST_CASE(Version_2_Empty_Source,AST_Fixture)31 FIXTURE_TEST_CASE(Version_2_Empty_Source, AST_Fixture)
32 {
33     AST * ast = MakeAst ( "version 2; table t#1 {};" );
34     REQUIRE_NOT_NULL ( ast );
35     REQUIRE_EQ ( ( int ) PT_SCHEMA_2_0, ast -> GetTokenType () );
36     REQUIRE_EQ ( 2u, ast -> ChildrenCount () );
37     REQUIRE_EQ ( ( int ) PT_EMPTY,      ast -> GetChild ( 0 ) -> GetTokenType () ); // declarations in a list
38     REQUIRE_EQ ( ( int ) PT_VERSION_2,  ast -> GetChild ( 1 ) -> GetTokenType () );
39 }
40 
41 class ViewAccess // encapsulates access to an STable in a VSchema
42 {
43 public:
ViewAccess(const SView * p_fn)44     ViewAccess ( const SView* p_fn ) : m_self ( p_fn ) {}
45 
Version() const46     uint32_t Version () const { return m_self -> version; }
Id() const47     uint32_t Id () const { return m_self -> id; }
48 
GetOverloads() const49     const SNameOverload * GetOverloads () const
50     {
51         return static_cast < const SNameOverload * > ( m_self -> name -> u . obj );
52     }
53 
Overloads() const54     VdbVector < SView > Overloads () const { return VdbVector < SView > ( GetOverloads () -> items ); }
55 
Parameters() const56     VdbVector < const KSymbol > Parameters () const { return VdbVector < const KSymbol > ( m_self -> params ); }
57 
Parents() const58     VdbVector < SViewInstance > Parents () const { return VdbVector < SViewInstance > ( m_self -> parents ); }
59 
60     /* overrides ( inherited virtual productions )
61        contents are grouped by introducing parent */
Overrides() const62     VdbVector < SViewOverrides > Overrides () const { return VdbVector < SViewOverrides > ( m_self -> overrides ); }
63 
Columns() const64     VdbVector < SColumn > Columns () const { return VdbVector < SColumn > ( m_self -> col ); }
ColumnNames() const65     VdbVector < SNameOverload > ColumnNames () const { return VdbVector < SNameOverload > ( m_self -> cname ); }
Productions() const66     VdbVector < SProduction > Productions () const { return VdbVector < SProduction > ( m_self -> prod ); }
VirtualProductions() const67     VdbVector < KSymbol > VirtualProductions () const { return VdbVector < KSymbol > ( m_self -> vprods ); }
68 
69     const SView * m_self;
70 };
71 
72 class AST_View_Fixture : public AST_Fixture
73 {
74 public:
AST_View_Fixture()75     AST_View_Fixture ()
76     {
77     }
~AST_View_Fixture()78     ~AST_View_Fixture ()
79     {
80     }
81 
ParseView(const char * p_source,const char * p_name,uint32_t p_idx=0)82     ViewAccess ParseView ( const char * p_source, const char * p_name, uint32_t p_idx = 0 )
83     {
84         MakeAst ( p_source );
85         const SView * ret = static_cast < const SView* > ( VectorGet ( & GetSchema () -> view, p_idx ) );
86         if ( ret == 0 || ret -> name == 0 || string ( p_name ) != ToCppString ( ret -> name -> name ) )
87         {
88             throw std :: logic_error ( "AST_View_Fixture::ParseTable : wrong name" );
89         }
90         return ViewAccess ( ret );
91     }
GetView(uint32_t p_idx)92     ViewAccess GetView ( uint32_t p_idx )
93     {
94         return ViewAccess ( static_cast < const SView* > ( VectorGet ( & GetSchema () -> view, p_idx ) ) );
95     }
96 
97     #define THROW_ON_TRUE(cond) if ( cond ) throw logic_error ( string ( __func__ ) + " : " #cond );
98 
VerifySymExpr(const SExpression * p_expr,uint32_t p_exprType,const string & p_ident,uint32_t p_objType)99         void VerifySymExpr( const SExpression * p_expr,
100                             uint32_t            p_exprType,
101                             const string &      p_ident,
102                             uint32_t            p_objType )
103         {
104             THROW_ON_TRUE ( p_expr == 0 );
105             THROW_ON_TRUE ( p_exprType != p_expr -> var );
106             const SSymExpr * sym = reinterpret_cast < const SSymExpr * > ( p_expr );
107             THROW_ON_TRUE ( sym == 0 );
108             THROW_ON_TRUE ( sym -> _sym == 0 );
109             THROW_ON_TRUE ( p_ident != ToCppString( sym -> _sym -> name ) );
110             THROW_ON_TRUE ( p_objType != sym -> _sym -> type );
111         }
112     #undef THROW_ON_TRUE
113 
114 };
115 
FIXTURE_TEST_CASE(View_OneTable_NoParents,AST_View_Fixture)116 FIXTURE_TEST_CASE(View_OneTable_NoParents, AST_View_Fixture)
117 {
118     ViewAccess v = ParseView ( "version 2; table T#1 {}; view v#1 <T t> {}", "v" );
119 
120     REQUIRE_NULL ( v . m_self -> name -> dad );
121     REQUIRE_EQ ( ( uint32_t ) eView, v . m_self -> name -> type );
122     // verify entry in the container of (overloaded on version) view names
123     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> vname ) );
124     REQUIRE_EQ ( 1u, v . Overloads () . Count () );
125     REQUIRE_EQ ( v . GetOverloads (), ( const SNameOverload * ) VectorGet ( & GetSchema () -> vname, 0 ) );
126 }
127 
FIXTURE_TEST_CASE(View_Id,AST_View_Fixture)128 FIXTURE_TEST_CASE(View_Id, AST_View_Fixture)
129 {   // both version are registered
130     ViewAccess v1 = ParseView ( "version 2; table T#1 {}; view v#1 <T t> {}; view v#2 <T t> {}", "v" );
131     ViewAccess v2 = GetView ( 1 );
132 
133     REQUIRE_EQ ( 2u, VectorLength ( & GetSchema () -> view ) );
134     REQUIRE_EQ ( 0u, v1 . Id () );
135     REQUIRE_EQ ( 1u, v2 . Id () );
136 }
137 
138 // Version
139 
FIXTURE_TEST_CASE(View_Version,AST_View_Fixture)140 FIXTURE_TEST_CASE(View_Version, AST_View_Fixture)
141 {
142     ViewAccess v = ParseView ( "version 2; table T#1 {}; view v#1.2.3 <T t> {}", "v" );
143     REQUIRE_EQ ( Version ( 1, 2, 3 ), v . Version () );
144 }
145 
FIXTURE_TEST_CASE(View_Version_Redeclared,AST_Fixture)146 FIXTURE_TEST_CASE(View_Version_Redeclared, AST_Fixture)
147 {
148     VerifyErrorMessage ( "version 2; table T#1 {}; view v#1.2.3 <T t> {}; view v#1.2.3 <T t> {}",
149                               "This version is already declared: 'v'" );
150 }
151 
FIXTURE_TEST_CASE(View_NewerMajorVersion,AST_View_Fixture)152 FIXTURE_TEST_CASE(View_NewerMajorVersion, AST_View_Fixture)
153 {   // both version are registered
154     ViewAccess v1 = ParseView ( "version 2; table T#1 {}; view v#1 <T t> {}; view v#2 <T t> {}", "v" );
155     ViewAccess v2 = GetView ( 1 );
156 
157     REQUIRE_EQ ( 2u, VectorLength ( & GetSchema () -> view ) );
158     REQUIRE_EQ ( Version ( 1 ), v1 . Version () );
159     REQUIRE_EQ ( Version ( 2 ), v2 . Version () );
160 
161     // 1 entry in the table of view overloads, the entry points to the 2 versions of the view, the views point back
162     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> vname ) );
163     REQUIRE_EQ ( 2u, v1 . Overloads () . Count () );
164     REQUIRE_EQ ( v1 . GetOverloads (), v2 . GetOverloads () );
165     REQUIRE_EQ ( v1 . GetOverloads (), ( const SNameOverload * ) VectorGet ( & GetSchema () -> vname, 0 ) );
166 }
167 
FIXTURE_TEST_CASE(View_OlderMajorVersion,AST_View_Fixture)168 FIXTURE_TEST_CASE(View_OlderMajorVersion, AST_View_Fixture)
169 {   // both version are registered
170     ViewAccess v1 = ParseView ( "version 2; table T#1 {}; view v#2 <T t> {}; view v#1 <T t> {}", "v" );
171     ViewAccess v2 = GetView ( 1 );
172 
173     REQUIRE_EQ ( 2u, VectorLength ( & GetSchema () -> view ) );
174     REQUIRE_EQ ( Version ( 2 ), v1 . Version () );
175     REQUIRE_EQ ( Version ( 1 ), v2 . Version () );
176 
177     // 1 entry in the table of view overloads, the entry points to the 2 versions of the view, the views point back
178     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> vname ) );
179     REQUIRE_EQ ( 2u, v1 . Overloads () . Count () );
180 }
181 
FIXTURE_TEST_CASE(View_OlderMinorVersion,AST_View_Fixture)182 FIXTURE_TEST_CASE(View_OlderMinorVersion, AST_View_Fixture)
183 {   // older minor version is ignored
184     ViewAccess v = ParseView ( "version 2; table T#1 {}; view v#1.2 <T t> {}; view v#1.1 <T t> {}", "v" );
185 
186     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> view ) );
187     REQUIRE_EQ ( Version ( 1, 2 ), v . Version () );
188 
189     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> vname ) );
190     REQUIRE_EQ ( 1u, v . Overloads () . Count () );
191 }
192 
FIXTURE_TEST_CASE(View_NewerMinorVersion,AST_View_Fixture)193 FIXTURE_TEST_CASE(View_NewerMinorVersion, AST_View_Fixture)
194 {   // older minor version is replaced
195     ViewAccess v = ParseView ( "version 2; table T#1 {}; view v#1.1 <T t> {}; view v#1.2 <T t> {}", "v" );
196 
197     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> view ) );
198     REQUIRE_EQ ( Version ( 1, 2 ), v . Version () );
199 
200     REQUIRE_EQ ( 1u, VectorLength ( & GetSchema () -> vname ) );
201     REQUIRE_EQ ( 1u, v . Overloads () . Count () );
202 }
203 
204 // Parameters
FIXTURE_TEST_CASE(View_Parameter_Table,AST_View_Fixture)205 FIXTURE_TEST_CASE(View_Parameter_Table, AST_View_Fixture)
206 {
207     ViewAccess v = ParseView ( "version 2; table T#1 {}; view v#1 <T t> {}", "v" );
208     REQUIRE_EQ ( 1u, v . Parameters () . Count () );
209     REQUIRE_EQ ( (uint32_t)eTable, v . Parameters () . Get ( 0 ) -> type );
210     REQUIRE_EQ ( (const void *) GetTable ( 0 ), v . Parameters () . Get ( 0 ) -> u . obj );
211 }
212 
FIXTURE_TEST_CASE(View_Parameter_View,AST_View_Fixture)213 FIXTURE_TEST_CASE(View_Parameter_View, AST_View_Fixture)
214 {
215     ViewAccess v = ParseView ( "version 2; table T#1 {}; view X#1 <T t> {}; view v#1 <X v> {}", "v", 1 );
216     REQUIRE_EQ ( 1u, v . Parameters () . Count () );
217     REQUIRE_EQ ( (uint32_t)eView, v . Parameters () . Get ( 0 ) -> type );
218     REQUIRE_EQ ( (const void *) GetView ( 0 ) . m_self, v . Parameters () . Get ( 0 ) -> u . obj );
219 }
220 
FIXTURE_TEST_CASE(View_Parameter_TableAndView,AST_View_Fixture)221 FIXTURE_TEST_CASE(View_Parameter_TableAndView, AST_View_Fixture)
222 {
223     ViewAccess v = ParseView ( "version 2; table T#1 {}; view X#1 <T t> {}; view v#1 <T t, X v> {}", "v", 1 );
224     REQUIRE_EQ ( 2u, v . Parameters () . Count () );
225     REQUIRE_EQ ( (uint32_t)eTable, v . Parameters () . Get ( 0 ) -> type );
226     REQUIRE_EQ ( (const void *) GetTable ( 0 ), v . Parameters () . Get ( 0 ) -> u . obj );
227     REQUIRE_EQ ( (uint32_t)eView, v . Parameters () . Get ( 1 ) -> type );
228     REQUIRE_EQ ( (const void *) GetView ( 0 ) . m_self, v . Parameters () . Get ( 1 ) -> u . obj );
229 }
230 
FIXTURE_TEST_CASE(View_Parameter_NotTableOrView,AST_View_Fixture)231 FIXTURE_TEST_CASE(View_Parameter_NotTableOrView, AST_View_Fixture)
232 {
233     VerifyErrorMessage ( "version 2; view v#1 <U8 t> {}", "Cannot be used as a view parameter: 'U8'" );
234 }
235 
FIXTURE_TEST_CASE(View_Parameter_UnknownParameter,AST_View_Fixture)236 FIXTURE_TEST_CASE(View_Parameter_UnknownParameter, AST_View_Fixture)
237 {
238     VerifyErrorMessage ( "version 2; view v#1 <zz t> {}", "Undeclared identifier: 'zz'" );
239 }
240 
FIXTURE_TEST_CASE(View_Parameter_VersionedTable,AST_View_Fixture)241 FIXTURE_TEST_CASE(View_Parameter_VersionedTable, AST_View_Fixture)
242 {
243     ViewAccess v = ParseView ( "version 2; table T#1 {}; table T#2 {}; view v#1 <T#1 t> {}", "v" );
244     REQUIRE_EQ ( (const void*)GetTable ( 0 ), v . Parameters () . Get ( 0 ) -> u . obj );
245 }
246 
FIXTURE_TEST_CASE(View_Parameter_VersionedView,AST_View_Fixture)247 FIXTURE_TEST_CASE(View_Parameter_VersionedView, AST_View_Fixture)
248 {
249     ViewAccess v = ParseView (
250         "version 2; table T#1 {}; "
251         "view a:V#1 <T t> {}; "
252         "view a:V#2 <T t> {}; "
253         "view v#1 <a:V#2 v> {}", "v", 2 );
254     REQUIRE_EQ ( (const void*)GetView ( 1 ) . m_self, v . Parameters () . Get ( 0 ) -> u . obj );
255 }
256 
FIXTURE_TEST_CASE(View_Parameter_BadTableVersion,AST_View_Fixture)257 FIXTURE_TEST_CASE(View_Parameter_BadTableVersion, AST_View_Fixture)
258 {
259     VerifyErrorMessage ( "version 2; table T#1 {}; view v#1 <T#2 t> {}", "Requested version does not exist: 'T#2'" );
260 }
FIXTURE_TEST_CASE(View_Parameter_BadViewVersion,AST_View_Fixture)261 FIXTURE_TEST_CASE(View_Parameter_BadViewVersion, AST_View_Fixture)
262 {
263     VerifyErrorMessage ( "version 2; table T#1 {}; view X#1 <T t> {}; view v#1 <X#1.1 v> {}",
264                          "Requested version does not exist: 'X#1.1'" );
265 }
266 
FIXTURE_TEST_CASE(View_Parameter_DuplicateName,AST_View_Fixture)267 FIXTURE_TEST_CASE(View_Parameter_DuplicateName, AST_View_Fixture)
268 {
269     VerifyErrorMessage ( "version 2; table T#1 {}; view X#1 <T t> {}; view v#1 <X t, T t> {}",
270                          "Name already in use: 't'" );
271 }
272 
273 // View parents
FIXTURE_TEST_CASE(View_Parents_NoParents,AST_View_Fixture)274 FIXTURE_TEST_CASE(View_Parents_NoParents, AST_View_Fixture)
275 {
276     ViewAccess v = ParseView ( "version 2; table T#1 {}; view W#1 <T v> {}", "W" );
277     REQUIRE_EQ ( 0u, v . Parents () . Count () );
278 }
279 
FIXTURE_TEST_CASE(View_Parents_Multiple,AST_View_Fixture)280 FIXTURE_TEST_CASE(View_Parents_Multiple, AST_View_Fixture)
281 {
282     ViewAccess v = ParseView (
283         "version 2; table T#1 {}; "
284         "view V1#1 <T t> {}; "
285         "view V2#1 <T t, V1 v> {}; "
286         "view W#1 <T t, V1 v> = V1<t>, V2<t, v> {}",
287         "W", 2 );
288     REQUIRE_EQ ( 2u, v . Parents () . Count () );
289     REQUIRE_EQ ( GetView ( 0 ) . m_self, v . Parents () . Get ( 0 ) -> dad );
290     REQUIRE_EQ ( GetView ( 1 ) . m_self, v . Parents () . Get ( 1 ) -> dad );
291     // verify W's parents and their argiments
292     VdbVector < const KSymbol > v1 ( v . Parents () . Get ( 0 ) -> params );
293     REQUIRE_EQ ( 1u, v1 . Count () );
294     REQUIRE_EQ ( (uint32_t)eTable, v1 . Get ( 0 ) -> type );
295     REQUIRE_EQ ( string("t"), ToCppString ( v1 . Get ( 0 ) -> name ) );
296     VdbVector < const KSymbol > v2 ( v . Parents () . Get ( 1 ) -> params );
297     REQUIRE_EQ ( 2u, v2 . Count () );
298     REQUIRE_EQ ( (uint32_t)eTable, v2 . Get ( 0 ) -> type );
299     REQUIRE_EQ ( string("t"), ToCppString ( v2 . Get ( 0 ) -> name ) );
300     REQUIRE_EQ ( (uint32_t)eView,  v2 . Get ( 1 ) -> type );
301     REQUIRE_EQ ( string("v"), ToCppString ( v2 . Get ( 1 ) -> name ) );
302 }
303 
FIXTURE_TEST_CASE(View_Parents_Unknown,AST_View_Fixture)304 FIXTURE_TEST_CASE(View_Parents_Unknown, AST_View_Fixture)
305 {
306     VerifyErrorMessage (
307         "version 2; table T#1 {}; "
308         "view V#1 <T t> = Z<t> {}; ",
309         "Undeclared identifier: 'Z'" );
310 }
311 
FIXTURE_TEST_CASE(View_Parents_Duplicate,AST_View_Fixture)312 FIXTURE_TEST_CASE(View_Parents_Duplicate, AST_View_Fixture)
313 {
314     VerifyErrorMessage (
315         "version 2; table T#1 {}; "
316         "view V#1 <T t> {}; "
317         "view W#1 <T v> = V<v>, V<v> {}",
318         "Same view inherited from more than once: 'V'" );
319 }
320 
FIXTURE_TEST_CASE(View_Parents_NotAView,AST_View_Fixture)321 FIXTURE_TEST_CASE(View_Parents_NotAView, AST_View_Fixture)
322 {
323     VerifyErrorMessage (
324         "version 2; table T#1 {}; "
325         "view V#1 <T t> {}; "
326         "view W#1 <T v> = V<v>, T<v> {}",
327         "A view's parent has to be a view: 'T'" );
328 }
329 
FIXTURE_TEST_CASE(View_Parents_BadParameter,AST_View_Fixture)330 FIXTURE_TEST_CASE(View_Parents_BadParameter, AST_View_Fixture)
331 {
332     VerifyErrorMessage (
333         "version 2; table T#1 {}; "
334         "view V#1 <T t> {}; "
335         "const U8 c = 1;"
336         "view W#1 <T v> = V<c> {}",
337         "A view's parameter has to be a table or a view: 'c'" );
338 }
339 
FIXTURE_TEST_CASE(View_Parents_Diamond,AST_View_Fixture)340 FIXTURE_TEST_CASE(View_Parents_Diamond, AST_View_Fixture)
341 {   // a parent in an ancestry more than once
342     VerifyErrorMessage (
343         "version 2; table T#1 {}; "
344         "view V1#1 <T t> {}"
345         "view V2#1 <T t> = V1<t> {}"
346         "view V3#1 <T t> = V2<t>, V1<t> {}",
347         "Same view inherited from more than once: 'V1'");
348 }
349 
FIXTURE_TEST_CASE(View_Parents_BadVersion,AST_View_Fixture)350 FIXTURE_TEST_CASE(View_Parents_BadVersion, AST_View_Fixture)
351 {
352     VerifyErrorMessage (
353         "version 2; table T#1 {}; "
354         "view V#1 <T t> {}; "
355         "view W#1 <T v> = V#2<v> {}",
356         "Requested version does not exist: 'V#2'" );
357 }
358 
359 // View body: columns
360 
FIXTURE_TEST_CASE(View_Column,AST_View_Fixture)361 FIXTURE_TEST_CASE(View_Column, AST_View_Fixture)
362 {
363     ViewAccess v = ParseView ( "version 2; table T#1 {}; view W#1 <T v> { column U8 c = 1; }", "W" );
364     REQUIRE_EQ ( 1u, v . Columns () . Count () );
365     const SColumn & c = * v . Columns () . Get ( 0 );
366     REQUIRE_NOT_NULL ( c . name );
367     REQUIRE_EQ ( ( uint32_t ) eColumn, c . name -> type );
368 
369     REQUIRE_NOT_NULL ( c . read );
370     REQUIRE_EQ ( ( uint32_t ) eConstExpr, c . read -> var );
371 
372     REQUIRE_EQ ( string ("c"), ToCppString ( c . name -> name ) );
373     REQUIRE_NULL ( c . validate );
374     REQUIRE_NULL ( c . limit );
375     REQUIRE_NULL ( c . ptype );
376     REQUIRE_EQ ( U8_id, c . td . type_id );
377     REQUIRE_EQ ( 1u, c . td . dim);
378     REQUIRE_EQ ( 1u, c . cid . ctx ); // T;s contextId is 0, W's is 1
379     REQUIRE_EQ ( 0u, c . cid . id );
380     REQUIRE ( ! c . dflt );
381     REQUIRE ( c . read_only );
382     REQUIRE ( ! c . simple );
383 
384     REQUIRE_EQ ( ( const void * ) v . ColumnNames () . Get ( 0 ), c . name -> u . obj );
385 }
386 
FIXTURE_TEST_CASE(View_Column_ColumnExists,AST_View_Fixture)387 FIXTURE_TEST_CASE(View_Column_ColumnExists, AST_View_Fixture)
388 {
389     VerifyErrorMessage (
390         "version 2; table T#1 {};"
391         "view W#1 <T v> { column U8 c = 1; column U8 c = 2; }",
392         "Column already defined: 'c'" );
393 }
394 
FIXTURE_TEST_CASE(View_Column_Overloaded,AST_View_Fixture)395 FIXTURE_TEST_CASE(View_Column_Overloaded, AST_View_Fixture)
396 {   // with a different type, not an error but an overload
397     ViewAccess v = ParseView (
398         "version 2; table T#1 {}; "
399         "view W#1 <T v> { column U8 c = 1; column U16 c = 2; }",
400         "W" );
401     REQUIRE_EQ ( 1u, v . ColumnNames () . Count () );
402     const SNameOverload * ovl = v . ColumnNames () . Get ( 0 );
403     REQUIRE_NOT_NULL ( ovl );
404     REQUIRE_EQ ( string ("c"), ToCppString ( ovl -> name -> name ) );
405     REQUIRE_EQ ( 1u, ovl -> cid . ctx );
406     REQUIRE_EQ ( 0u, ovl -> cid . id );
407     const SColumn * col = v . Columns () . Get ( 0 );
408     REQUIRE_NOT_NULL ( col );
409     REQUIRE_EQ ( ovl -> cid . ctx, col -> cid . ctx );
410     REQUIRE_EQ ( ovl -> cid . id, col -> cid . id );
411 
412     VdbVector < SColumn > names ( ovl -> items );
413     REQUIRE_EQ ( 2u, names . Count () );
414     REQUIRE_EQ ( v . Columns () . Get ( 0 ), names . Get ( 0 ) );
415     REQUIRE_EQ ( v . Columns () . Get ( 1 ), names . Get ( 1 ) );
416 
417     col = v . Columns () . Get ( 1 );
418     REQUIRE_NOT_NULL ( col );
419     REQUIRE_EQ ( ovl -> cid . ctx, col -> cid . ctx );
420     REQUIRE_EQ ( ovl -> cid . id, col -> cid . id );
421 }
422 
FIXTURE_TEST_CASE(View_Column_Reference,AST_View_Fixture)423 FIXTURE_TEST_CASE(View_Column_Reference, AST_View_Fixture)
424 {
425     ViewAccess v = ParseView ( "version 2; table T#1 {}; view W#1 <T v> { column U8 c1 = 1; column U8 c2 = c1; }", "W" );
426     REQUIRE_EQ ( 2u, v . Columns () . Count () );
427     const SColumn & c = * v . Columns () . Get ( 1 );
428     REQUIRE_NOT_NULL ( c . name );
429     REQUIRE_EQ ( string ("c2"), ToCppString ( c . name -> name ) );
430     REQUIRE_NOT_NULL ( c . read );
431     REQUIRE_EQ ( ( uint32_t ) eColExpr, c . read -> var );
432 }
433 
FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn,AST_View_Fixture)434 FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn, AST_View_Fixture)
435 {   // introducing member expressions!
436     ViewAccess v = ParseView ( "version 2; table T#1 { column U8 c1 = 1; }; view W#1 <T t0, T t1> { column U8 c2 = t1 . c1; }", "W" );
437     REQUIRE_EQ ( 1u, v . Columns () . Count () );
438     const SColumn & c = * v . Columns () . Get ( 0 );
439     REQUIRE_NOT_NULL ( c . name );
440     REQUIRE_EQ ( string ("c2"), ToCppString ( c . name -> name ) );
441     REQUIRE_NOT_NULL ( c . read );
442     REQUIRE_EQ ( ( uint32_t ) eMembExpr, c . read -> var );
443     const SMembExpr * expr = reinterpret_cast < const SMembExpr * > ( c . read );
444     REQUIRE_EQ ( v .m_self, expr -> view );
445     REQUIRE_EQ ( 1u, expr -> paramId );
446     REQUIRE_EQ ( string("c1"), ToCppString ( expr -> member -> name ) );
447 }
FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn_PseudoPhysicalToken,AST_View_Fixture)448 FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn_PseudoPhysicalToken, AST_View_Fixture)
449 {   // .b looks like a physical identifier
450     ViewAccess v = ParseView ( "version 2; table T#1 { column U8 c1 = 1; }; view W#1 <T t> { column U8 c2 = t .c1; }", "W" );
451     REQUIRE_EQ ( ( uint32_t ) eMembExpr, v . Columns () . Get ( 0 ) -> read -> var );
452 }
FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesProduction,AST_View_Fixture)453 FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesProduction, AST_View_Fixture)
454 {
455     ViewAccess v = ParseView ( "version 2; table T#1 { U8 c1 = 1; }; view W#1 <T t> { column U8 c2 = t . c1; }", "W" );
456     REQUIRE_EQ ( ( uint32_t ) eMembExpr, v . Columns () . Get ( 0 ) -> read -> var );
457 }
458 
FIXTURE_TEST_CASE(View_Join_Shorthand,AST_View_Fixture)459 FIXTURE_TEST_CASE(View_Join_Shorthand, AST_View_Fixture)
460 {
461     ViewAccess v = ParseView (
462         "version 2;"
463         "table T1#1 { column I64 c1; };"
464         "table T2#1 { column U8 c2; };"
465         "view X#1 <T1 t1, T2 t2> { column U8 c3 = t2 [ t1 . c1 ] . c2; }; ",
466         "X" );
467 
468     REQUIRE_EQ ( 1u, v . Columns () . Count () );
469     const SColumn & c = * v . Columns () . Get ( 0 );
470     REQUIRE_NOT_NULL ( c . name );
471     REQUIRE_EQ ( string ("c3"), ToCppString ( c . name -> name ) );
472     REQUIRE_NOT_NULL ( c . read );
473     REQUIRE_EQ ( ( uint32_t ) eMembExpr, c . read -> var );
474     const SMembExpr * expr = reinterpret_cast < const SMembExpr * > ( c . read );
475     REQUIRE_EQ ( v . m_self, expr -> view );
476     REQUIRE_EQ ( 1u, expr -> paramId ); // t2
477     REQUIRE_EQ ( string("c2"), ToCppString ( expr -> member -> name ) );
478 
479     REQUIRE_NOT_NULL ( expr -> rowId );
480     const SMembExpr * rowId = reinterpret_cast < const SMembExpr * > ( expr ->  rowId );
481     REQUIRE_EQ ( v . m_self, rowId -> view );
482     REQUIRE_EQ ( 0u, rowId -> paramId ); // t1
483     REQUIRE_EQ ( string("c1"), ToCppString ( rowId -> member -> name ) );
484     REQUIRE_NULL ( rowId -> rowId );
485 }
486 
FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn_Undefined,AST_View_Fixture)487 FIXTURE_TEST_CASE(View_Column_ReferenceToParamTablesColumn_Undefined, AST_View_Fixture)
488 {
489     VerifyErrorMessage (
490         "version 2; table T#1 { column U8 c1 = 1; }; view W#1 <T t> { column U8 c2 = t . c11111; }",
491         "Column/production not found: 'c11111'" );
492 }
493 
FIXTURE_TEST_CASE(View_Column_ReferenceToParamViewsColumn,AST_View_Fixture)494 FIXTURE_TEST_CASE(View_Column_ReferenceToParamViewsColumn, AST_View_Fixture)
495 {
496     ViewAccess v = ParseView (
497         "version 2; table T#1 { U8 c1 = 1; };"
498         " view V#1 <T t> { column U8 c2 = t . c1; }"
499         " view W#1 <V v> { column U8 c3 = v . c2; }",
500     "W", 1 );
501     const SColumn & c = * v . Columns () . Get ( 0 );
502     REQUIRE_NOT_NULL ( c . read );
503     REQUIRE_EQ ( ( uint32_t ) eMembExpr, c . read -> var );
504 }
505 
FIXTURE_TEST_CASE(View_Column_ReferenceToParamViewsColumn_Undefined,AST_View_Fixture)506 FIXTURE_TEST_CASE(View_Column_ReferenceToParamViewsColumn_Undefined, AST_View_Fixture)
507 {
508     VerifyErrorMessage (
509         "version 2; table T#1 { U8 c1 = 1; };"
510         " view V#1 <T t> { column U8 c2 = t . c1; }"
511         " view W#1 <V v> { column U8 c3 = v . c22222222; }",
512         "Column/production not found: 'c22222222'" );
513 }
514 
FIXTURE_TEST_CASE(View_Column_Context,AST_View_Fixture)515 FIXTURE_TEST_CASE(View_Column_Context, AST_View_Fixture)
516 {
517     ViewAccess v = ParseView (
518         "version 2; table T#1 {};"
519         " view V#1 <T t> {}"
520         " view W#1 <T t> { column U8 c1 = 1; column U8 c2 = 2; }",
521     "W", 1 );
522     const SNameOverload * ovl = v . ColumnNames () . Get ( 0 );
523     REQUIRE_NOT_NULL ( ovl );
524     REQUIRE_EQ ( 2u, ovl -> cid . ctx ); // W'1 contextId is 2
525     REQUIRE_EQ ( 0u, ovl -> cid . id );
526     const SColumn * col = v . Columns () . Get ( 0 );
527     REQUIRE_NOT_NULL ( col );
528     REQUIRE_EQ ( ovl -> cid . ctx, col -> cid . ctx );
529     REQUIRE_EQ ( ovl -> cid . id, col -> cid . id );
530 
531     ovl = v . ColumnNames () . Get ( 1 );
532     REQUIRE_NOT_NULL ( ovl );
533     REQUIRE_EQ ( 2u, ovl -> cid . ctx );
534     REQUIRE_EQ ( 1u, ovl -> cid . id );
535     col = v . Columns () . Get ( 1 );
536     REQUIRE_NOT_NULL ( col );
537     REQUIRE_EQ ( ovl -> cid . ctx, col -> cid . ctx );
538     REQUIRE_EQ ( ovl -> cid . id, col -> cid . id );
539 }
540 
FIXTURE_TEST_CASE(View_ForwardReference,AST_View_Fixture)541 FIXTURE_TEST_CASE(View_ForwardReference, AST_View_Fixture)
542 {
543     ViewAccess v = ParseView (
544         "version 2; table T#1 {}; view V#1 <T v> { column U16 a = p; column U8 p = 1; }", "V" );
545     REQUIRE_EQ ( 2u, v . Columns () . Count () );
546     const SColumn * a = v . Columns () . Get ( 0 );
547     VerifySymExpr ( a -> read, eColExpr, "p", eColumn );
548 }
549 
FIXTURE_TEST_CASE(View_ColumnDecl_OutsideIdent,AST_View_Fixture)550 FIXTURE_TEST_CASE(View_ColumnDecl_OutsideIdent, AST_View_Fixture)
551 {
552     ParseView ("version 2; table T#1 {}; const U8 c = 1; view V#1 <T v> { column U8 c = 1; }", "V" );
553 }
554 
555 // View body: productions
556 
FIXTURE_TEST_CASE(View_Production,AST_View_Fixture)557 FIXTURE_TEST_CASE(View_Production, AST_View_Fixture)
558 {
559     ViewAccess v = ParseView ( "version 2; table T#1 {}; view V#1 <T v> { U8 p = 1; }", "V" );
560     REQUIRE_EQ ( 1u, v . Productions () . Count () );
561     const SProduction & p = * v . Productions () . Get ( 0 );
562     REQUIRE_NOT_NULL ( p . name );
563     REQUIRE_EQ ( string ("p"), ToCppString ( p . name -> name ) );
564     REQUIRE_EQ ( ( uint32_t ) eProduction, p . name -> type );
565 
566     REQUIRE_NOT_NULL ( p . expr );
567     REQUIRE_EQ ( ( uint32_t ) eConstExpr, p . expr -> var );
568 
569     REQUIRE_NOT_NULL ( p . fd );
570     REQUIRE_EQ ( ( uint32_t ) eTypeExpr, p . fd -> var );
571     const STypeExpr * type = reinterpret_cast < const STypeExpr * > ( p . fd );
572     REQUIRE_EQ ( U8_id, type -> dt -> id );
573     REQUIRE ( ! p . trigger );
574     REQUIRE ( ! p . control );
575 }
576 
FIXTURE_TEST_CASE(View_Production_ClashWithColumn,AST_View_Fixture)577 FIXTURE_TEST_CASE(View_Production_ClashWithColumn, AST_View_Fixture)
578 {
579     VerifyErrorMessage (
580         "version 2; table T#1 {}; view V#1 <T v> { column U8 c = 1; U8 c = 1; }",
581         "Production name is already in use: 'c'" );
582 }
583 
FIXTURE_TEST_CASE(View_Production_IntroducingVirtual,AST_View_Fixture)584 FIXTURE_TEST_CASE(View_Production_IntroducingVirtual, AST_View_Fixture)
585 {
586     ViewAccess v = ParseView ( "version 2; table T#1 {}; view V#1 <T v> { column U8 p = vp; }", "V" );
587     REQUIRE_EQ ( 1u, v . VirtualProductions () . Count () );
588     REQUIRE_EQ ( string ("vp"), ToCppString ( v . VirtualProductions () . Get ( 0 ) -> name ) );
589 }
590 
FIXTURE_TEST_CASE(View_Production_ForwardReference_DefinedAsProduction,AST_View_Fixture)591 FIXTURE_TEST_CASE(View_Production_ForwardReference_DefinedAsProduction, AST_View_Fixture)
592 {
593     ViewAccess v = ParseView ( "version 2; table T#1 {}; view V#1 <T v> { U16 a = p; U8 p = 1; }", "V" );
594     REQUIRE_EQ ( 2u, v . Productions () . Count () );
595     const SProduction * a = v . Productions () . Get ( 0 );
596     VerifySymExpr ( a -> expr, eProdExpr, "p", eProduction );
597     // once defined, p is not virtual anymore
598     REQUIRE_EQ ( 0u, v . VirtualProductions () . Count  () );
599 }
600 
601 // Inheritance
602 
FIXTURE_TEST_CASE(View_Parents_WrongNumberOfParams,AST_View_Fixture)603 FIXTURE_TEST_CASE(View_Parents_WrongNumberOfParams, AST_View_Fixture)
604 {
605     VerifyErrorMessage (
606         "version 2; table T#1 {}; "
607         "view V#1 <T t> { column U8  v = 1; }; "
608         "view W#1 <T t> { column U16 w = 1; }; "
609         "view X#1 <T t> = V<t>, W<t, V> {}",
610         "Wrong number of parameters for a view instantiation");
611 }
612 
FIXTURE_TEST_CASE(View_Parents_WrongParamType,AST_View_Fixture)613 FIXTURE_TEST_CASE(View_Parents_WrongParamType, AST_View_Fixture)
614 {
615     VerifyErrorMessage (
616         "version 2; table T#1 {}; "
617         "view V#1 <T t> { column U8  v = 1; }; "
618         "view W#1 <T t> { column U16 w = 1; }; "
619         "view X#1 <T t, W w> = V < w > {}",
620         "Wrong type of a view's parameter: 'w'");
621 }
622 
FIXTURE_TEST_CASE(View_Parents_ColumnsInherited,AST_View_Fixture)623 FIXTURE_TEST_CASE(View_Parents_ColumnsInherited, AST_View_Fixture)
624 {
625     ViewAccess v = ParseView (
626         "version 2; table T#1 {}; "
627         "view V#1 <T t> { column U8  v = 1; }; "
628         "view W#1 <T t> { column U16 w = 1; }; "
629         "view X#1 <T t> = V<t>, W<t> {}",
630         "X", 2 );
631     REQUIRE_EQ ( 2u, v . ColumnNames () . Count () );
632     // v and w are seen as X's columns
633     REQUIRE_EQ ( string ("v"), ToCppString ( v . ColumnNames () . Get ( 0 ) -> name -> name ) );
634     REQUIRE_EQ ( string ("w"), ToCppString ( v . ColumnNames () . Get ( 1 ) -> name -> name ) );
635 }
636 
FIXTURE_TEST_CASE(View_Parents_ProductionsInherited,AST_View_Fixture)637 FIXTURE_TEST_CASE(View_Parents_ProductionsInherited, AST_View_Fixture)
638 {
639     ViewAccess v = ParseView (
640         "version 2; table T#1 {}; "
641         "view V#1 <T t> { U8  v = 1; }; "
642         "view X#1 <T t> = V<t> { U8 _v = v; }",
643         "X", 1 );
644     // v does not count as X's production but is accessible
645     REQUIRE_EQ ( 1u, v . Productions () . Count () );
646     REQUIRE_EQ ( string ("_v"), ToCppString ( v . Productions () . Get ( 0 ) -> name -> name ) );
647 }
648 
FIXTURE_TEST_CASE(View_Parents_ColumnCollision,AST_View_Fixture)649 FIXTURE_TEST_CASE(View_Parents_ColumnCollision, AST_View_Fixture)
650 {
651     VerifyErrorMessage (
652         "version 2; table T#1 {}; "
653         "view V#1 <T t> { column U8 p = 1; }; "
654         "view W#1 <T t> { column U8 p = 2; }; "
655         "view X#1 <T t> = V<t>, W<t> {}",
656         "Duplicate symbol in parent view hierarchy: 'p'" );
657 }
658 
FIXTURE_TEST_CASE(View_Parents_ProductionCollision,AST_View_Fixture)659 FIXTURE_TEST_CASE(View_Parents_ProductionCollision, AST_View_Fixture)
660 {
661     VerifyErrorMessage (
662         "version 2; table T#1 {}; "
663         "view V#1 <T t> { U8 p = 1; }; "
664         "view W#1 <T t> { U8 p = 2; }; "
665         "view X#1 <T t> = V<t>, W<t> {}",
666         "Duplicate symbol in parent view hierarchy: 'p'" );
667 }
668 
FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefined,AST_View_Fixture)669 FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefined, AST_View_Fixture)
670 {
671     ViewAccess v = ParseView (
672         "version 2; table T#1 {}; "
673         "view V#1 <T t> { U8 p = v; }; "
674         "view X#1 <T t> = V<t> { U8 v = 1; }",
675         "X", 1 );
676     REQUIRE_EQ ( 1u, v . Productions () . Count () );
677     REQUIRE_EQ ( string ("v"), ToCppString ( v . Productions () . Get ( 0 ) -> name -> name ) );
678 
679     // verify p and its reference to v
680     const SProduction * p = GetView ( 0 ) . Productions () . Get ( 0 );
681     REQUIRE_NOT_NULL ( p );
682     VerifySymExpr ( p -> expr, eFwdExpr, "v", eVirtual );
683 }
684 
FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefinedAcrossParents,AST_View_Fixture)685 FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefinedAcrossParents, AST_View_Fixture)
686 {
687     ViewAccess v = ParseView (
688         "version 2; table T#1 {}; "
689         "view V#1 <T t> { column U8 c = v; }; "
690         "view W#1 <T t> { U8 v = 1; }; "
691         "view X#1 <T t> = V<t>, W<t> {}",
692         "X", 2 );
693     REQUIRE_EQ ( 0u, v . Productions () . Count () );
694     // verify c and its reference to W.v
695     const SColumn * p = GetView ( 0 ) . Columns () . Get ( 0 );
696     REQUIRE_NOT_NULL ( p );
697     VerifySymExpr ( p -> read, eFwdExpr, "v", eVirtual );
698 }
699 
FIXTURE_TEST_CASE(View_Parents_InheritedVirtualProduction,AST_View_Fixture)700 FIXTURE_TEST_CASE(View_Parents_InheritedVirtualProduction, AST_View_Fixture)
701 {
702     ViewAccess t = ParseView (
703         "version 2; table T#1 {}; "
704         "view granddad #1 <T t> { U8 a = v; }; "
705         "view dad #1 <T t> = granddad<t> { U8 b = v; }; "
706         "view t #1 <T t> = dad<t> { }",
707         "t", 2 );
708 
709     // verify overrides
710     // dad
711     ViewAccess dad = GetView ( 1 );
712     REQUIRE_EQ ( 1u, dad . Overrides () . Count () ); // inherits from granddad
713     VdbVector < const KSymbol > dadOvr ( dad . Overrides () . Get ( 0 ) -> by_parent );
714     REQUIRE_EQ ( 1u, dadOvr . Count () ); // 1 override copied from granddad
715 
716     // t
717     REQUIRE_EQ ( 2u, t . Overrides () . Count () ); // v inherits from dad and granddad
718 
719     VdbVector < const KSymbol > tDadOvr ( t . Overrides () . Get ( 0 ) -> by_parent );
720     REQUIRE_EQ ( 1u, tDadOvr . Count () ); // 1 override copied from granddad
721     REQUIRE_EQ ( string ( "v" ), ToCppString ( tDadOvr . Get ( 0 ) -> name ) );
722 
723     VdbVector < const KSymbol > tGdadOvr ( t . Overrides () . Get ( 1 ) -> by_parent );
724     REQUIRE_EQ ( 0u, tGdadOvr . Count () ); // no overrides copied from granddad
725 
726 
727     // v is not resolved in t
728     REQUIRE_EQ ( 0u, t . VirtualProductions () . Count  () );
729 }
730 
FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefinedAcrossParentsAsColumn,AST_View_Fixture)731 FIXTURE_TEST_CASE(View_Parents_VirtualProductionDefinedAcrossParentsAsColumn, AST_View_Fixture)
732 {
733     VerifyErrorMessage (
734         "version 2; table T#1 {}; "
735         "view V#1 <T t> { U8 a = v; }; "
736         "view W#1 <T t> { column U8 v = 1; }; "
737         "view X#1 <T t> = V<t>, W<t> {}",
738         "a virtual production from one parent defined as non-production in another: 'v'" );
739 }
740 
FIXTURE_TEST_CASE(View_Parents_RedeclaringParentsColumn,AST_View_Fixture)741 FIXTURE_TEST_CASE(View_Parents_RedeclaringParentsColumn, AST_View_Fixture)
742 {
743     VerifyErrorMessage (
744         "version 2; table T#1 {}; "
745         "view W#1 <T t>         { column U8 c = 1; }; "
746         "view X#1 <T t> = W<t>  { column U8 c = 2; }",
747         "Column already defined: 'c'" );
748 }
749 
FIXTURE_TEST_CASE(View_Parents_OverloadingParentsColumn,AST_View_Fixture)750 FIXTURE_TEST_CASE(View_Parents_OverloadingParentsColumn, AST_View_Fixture)
751 {
752     ViewAccess v = ParseView (
753         "version 2; table T#1 {}; "
754         "view W#1 <T t>         { column U8 c = 1; }; "
755         "view X#1 <T t> = W<t>  { column U16 c = 2; }",
756         "X", 1 );
757     ViewAccess dad = GetView ( 0 );
758 
759     REQUIRE_EQ ( 1u, v . Columns () . Count () );
760     REQUIRE_EQ ( 1u, v . ColumnNames () . Count () );
761     const SNameOverload * ovl = v . ColumnNames () . Get ( 0 );
762     REQUIRE_NOT_NULL ( ovl );
763     REQUIRE_NOT_NULL ( ovl -> name );
764     REQUIRE_EQ ( string ("c"), ToCppString ( ovl -> name -> name ) );
765     REQUIRE_EQ ( 1u, ovl -> cid . ctx ); // inherited from W whose contexId is 1
766     REQUIRE_EQ ( 0u, ovl -> cid . id );
767 
768     VdbVector < SColumn > names ( ovl -> items );
769     REQUIRE_EQ ( 2u, names . Count () );
770     REQUIRE_EQ ( dad . Columns () . Get ( 0 ), names . Get ( 0 ) );
771     REQUIRE_EQ ( v . Columns () . Get ( 0 ), names . Get ( 1 ) );
772 }
773 
774