1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "googletest.h"
27 
28 #include "sqlitedatabasemock.h"
29 
30 #include <modelnode.h>
31 #include <projectstorage/projectstorage.h>
32 #include <projectstorage/sourcepathcache.h>
33 #include <sqlitedatabase.h>
34 #include <sqlitereadstatement.h>
35 #include <sqlitewritestatement.h>
36 
37 namespace {
38 
39 using QmlDesigner::ImportId;
40 using QmlDesigner::PropertyDeclarationId;
41 using QmlDesigner::SourceContextId;
42 using QmlDesigner::SourceId;
43 using QmlDesigner::TypeId;
44 using QmlDesigner::Cache::Source;
45 using QmlDesigner::Cache::SourceContext;
46 using QmlDesigner::Storage::TypeAccessSemantics;
47 
48 namespace Storage = QmlDesigner::Storage;
49 
50 MATCHER_P2(IsSourceContext,
51            id,
52            value,
53            std::string(negation ? "isn't " : "is ") + PrintToString(SourceContext{value, id}))
54 {
55     const SourceContext &sourceContext = arg;
56 
57     return sourceContext.id == id && sourceContext.value == value;
58 }
59 
60 MATCHER_P2(IsSourceNameAndSourceContextId,
61            name,
62            id,
63            std::string(negation ? "isn't " : "is ")
64                + PrintToString(QmlDesigner::Cache::SourceNameAndSourceContextId{name, id}))
65 {
66     const QmlDesigner::Cache::SourceNameAndSourceContextId &sourceNameAndSourceContextId = arg;
67 
68     return sourceNameAndSourceContextId.sourceName == name
69            && sourceNameAndSourceContextId.sourceContextId == id;
70 }
71 
72 MATCHER_P5(IsStorageType,
73            importId,
74            typeName,
75            prototype,
76            accessSemantics,
77            sourceId,
78            std::string(negation ? "isn't " : "is ")
79                + PrintToString(Storage::Type{importId, typeName, prototype, accessSemantics, sourceId}))
80 {
81     const Storage::Type &type = arg;
82 
83     return type.importId == importId && type.typeName == typeName
84            && type.accessSemantics == accessSemantics && type.sourceId == sourceId
__anon2a96ed8e0202(auto &&v) 85            && Utils::visit([&](auto &&v) -> bool { return v.name == prototype.name; }, type.prototype);
86 }
87 
88 MATCHER_P4(IsStorageTypeWithInvalidSourceId,
89            importId,
90            typeName,
91            prototype,
92            accessSemantics,
93            std::string(negation ? "isn't " : "is ")
94                + PrintToString(Storage::Type{importId, typeName, prototype, accessSemantics, SourceId{}}))
95 {
96     const Storage::Type &type = arg;
97 
98     return type.importId == importId && type.typeName == typeName && type.prototype == prototype
99            && type.accessSemantics == accessSemantics && !type.sourceId.isValid();
100 }
101 
102 MATCHER_P(IsExportedType,
103           name,
104           std::string(negation ? "isn't " : "is ") + PrintToString(Storage::ExportedType{name}))
105 {
106     const Storage::ExportedType &type = arg;
107 
108     return type.name == name;
109 }
110 
111 MATCHER_P3(IsPropertyDeclaration,
112            name,
113            typeName,
114            traits,
115            std::string(negation ? "isn't " : "is ")
116                + PrintToString(Storage::PropertyDeclaration{name, typeName, traits}))
117 {
118     const Storage::PropertyDeclaration &propertyDeclaration = arg;
119 
120     return propertyDeclaration.name == name
__anon2a96ed8e0302(auto &&v) 121            && Utils::visit([&](auto &&v) -> bool { return v.name == typeName.name; },
122                          propertyDeclaration.typeName)
123            && propertyDeclaration.traits == traits;
124 }
125 
126 MATCHER_P2(IsBasicImport,
127            name,
128            version,
129            std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Import{name, version}))
130 {
131     const Storage::BasicImport &import = arg;
132 
133     return import.name == name && import.version == version;
134 }
135 
136 MATCHER_P3(IsImport,
137            name,
138            version,
139            sourceId,
140            std::string(negation ? "isn't " : "is ")
141                + PrintToString(Storage::Import{name, version, sourceId}))
142 {
143     const Storage::Import &import = arg;
144 
145     return import.name == name && import.version == version && &import.sourceId == &sourceId;
146 }
147 
148 class ProjectStorage : public testing::Test
149 {
150 public:
ProjectStorage()151     ProjectStorage()
152     {
153         ON_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
154                 valueReturnsSourceContextId(A<Utils::SmallStringView>()))
155             .WillByDefault(Return(SourceContextId()));
156         ON_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
157                 valueReturnsSourceContextId(Utils::SmallStringView("")))
158             .WillByDefault(Return(SourceContextId(0)));
159         ON_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
160                 valueReturnsSourceContextId(Utils::SmallStringView("/path/to")))
161             .WillByDefault(Return(SourceContextId(5)));
162         ON_CALL(databaseMock, lastInsertedRowId()).WillByDefault(Return(12));
163         ON_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
164                 valueReturnInt32(_, _))
165             .WillByDefault(Return(Utils::optional<int>()));
166         ON_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
167                 valueReturnInt32(0, Utils::SmallStringView("")))
168             .WillByDefault(Return(Utils::optional<int>(0)));
169         ON_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
170                 valueReturnInt32(5, Utils::SmallStringView("file.h")))
171             .WillByDefault(Return(Utils::optional<int>(42)));
172         ON_CALL(selectAllSourcesStatement, valuesReturnCacheSources(_))
173             .WillByDefault(Return(std::vector<Source>{{"file.h", SourceContextId{1}, SourceId{1}},
174                                                       {"file.cpp", SourceContextId{2}, SourceId{4}}}));
175         ON_CALL(selectSourceContextPathFromSourceContextsBySourceContextIdStatement,
176                 valueReturnPathString(5))
177             .WillByDefault(Return(Utils::optional<Utils::PathString>("/path/to")));
178         ON_CALL(selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement,
179                 valueReturnCacheSourceNameAndSourceContextId(42))
180             .WillByDefault(Return(QmlDesigner::Cache::SourceNameAndSourceContextId{"file.cpp", 5}));
181         ON_CALL(selectSourceContextIdFromSourcesBySourceIdStatement,
182                 valueReturnInt32(TypedEq<int>(42)))
183             .WillByDefault(Return(Utils::optional<int>(5)));
184     }
185 
186 protected:
187     using ProjectStorageMock = QmlDesigner::ProjectStorage<SqliteDatabaseMock>;
188     template<int ResultCount>
189     using ReadStatement = ProjectStorageMock::ReadStatement<ResultCount>;
190     using WriteStatement = ProjectStorageMock::WriteStatement;
191     template<int ResultCount>
192     using ReadWriteStatement = ProjectStorageMock::ReadWriteStatement<ResultCount>;
193 
194     NiceMock<SqliteDatabaseMock> databaseMock;
195     ProjectStorageMock storage{databaseMock, true};
196     ReadWriteStatement<1> &upsertTypeStatement = storage.upsertTypeStatement;
197     ReadStatement<1> &selectTypeIdByExportedNameStatement = storage.selectTypeIdByExportedNameStatement;
198     WriteStatement &upsertExportedTypesStatement = storage.upsertExportedTypesStatement;
199     ReadStatement<1> &selectSourceContextIdFromSourceContextsBySourceContextPathStatement
200         = storage.selectSourceContextIdFromSourceContextsBySourceContextPathStatement;
201     ReadStatement<1> &selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment
202         = storage.selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement;
203     ReadStatement<1> &selectSourceContextPathFromSourceContextsBySourceContextIdStatement
204         = storage.selectSourceContextPathFromSourceContextsBySourceContextIdStatement;
205     ReadStatement<2> &selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
206         = storage.selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement;
207     ReadStatement<2> &selectAllSourceContextsStatement = storage.selectAllSourceContextsStatement;
208     WriteStatement &insertIntoSourceContexts = storage.insertIntoSourceContextsStatement;
209     WriteStatement &insertIntoSourcesStatement = storage.insertIntoSourcesStatement;
210     ReadStatement<3> &selectAllSourcesStatement = storage.selectAllSourcesStatement;
211     ReadStatement<1> &selectSourceContextIdFromSourcesBySourceIdStatement = storage.selectSourceContextIdFromSourcesBySourceIdStatement;
212     ReadStatement<5> &selectTypeByTypeIdStatement = storage.selectTypeByTypeIdStatement;
213     ReadStatement<1> &selectExportedTypesByTypeIdStatement = storage.selectExportedTypesByTypeIdStatement;
214     ReadStatement<6> &selectTypesStatement = storage.selectTypesStatement;
215 };
216 
TEST_F(ProjectStorage,SelectForFetchingSourceContextIdForKnownPathCalls)217 TEST_F(ProjectStorage, SelectForFetchingSourceContextIdForKnownPathCalls)
218 {
219     InSequence s;
220 
221     EXPECT_CALL(databaseMock, deferredBegin());
222     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
223                 valueReturnsSourceContextId(TypedEq<Utils::SmallStringView>("/path/to")));
224     EXPECT_CALL(databaseMock, commit());
225 
226     storage.fetchSourceContextId("/path/to");
227 }
228 
TEST_F(ProjectStorage,SelectForFetchingSourceIdForKnownPathCalls)229 TEST_F(ProjectStorage, SelectForFetchingSourceIdForKnownPathCalls)
230 {
231     InSequence s;
232 
233     EXPECT_CALL(databaseMock, deferredBegin());
234     EXPECT_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
235                 valueReturnsSourceId(5, Eq("file.h")));
236     EXPECT_CALL(databaseMock, commit());
237 
238     storage.fetchSourceId(SourceContextId{5}, "file.h");
239 }
240 
TEST_F(ProjectStorage,NotWriteForFetchingSourceContextIdForKnownPathCalls)241 TEST_F(ProjectStorage, NotWriteForFetchingSourceContextIdForKnownPathCalls)
242 {
243     EXPECT_CALL(insertIntoSourceContexts, write(An<Utils::SmallStringView>())).Times(0);
244 
245     storage.fetchSourceContextId("/path/to");
246 }
247 
TEST_F(ProjectStorage,NotWriteForFetchingSoureIdForKnownEntryCalls)248 TEST_F(ProjectStorage, NotWriteForFetchingSoureIdForKnownEntryCalls)
249 {
250     EXPECT_CALL(insertIntoSourcesStatement, write(An<uint>(), An<Utils::SmallStringView>())).Times(0);
251 
252     storage.fetchSourceId(SourceContextId{5}, "file.h");
253 }
254 
TEST_F(ProjectStorage,SelectAndWriteForFetchingSourceContextIdForUnknownPathCalls)255 TEST_F(ProjectStorage, SelectAndWriteForFetchingSourceContextIdForUnknownPathCalls)
256 {
257     InSequence s;
258 
259     EXPECT_CALL(databaseMock, deferredBegin());
260     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
261                 valueReturnsSourceContextId(
262                     TypedEq<Utils::SmallStringView>("/some/not/known/path")));
263     EXPECT_CALL(insertIntoSourceContexts,
264                 write(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
265     EXPECT_CALL(databaseMock, commit());
266 
267     storage.fetchSourceContextId("/some/not/known/path");
268 }
269 
TEST_F(ProjectStorage,SelectAndWriteForFetchingSourceIdForUnknownEntryCalls)270 TEST_F(ProjectStorage, SelectAndWriteForFetchingSourceIdForUnknownEntryCalls)
271 {
272     InSequence s;
273 
274     EXPECT_CALL(databaseMock, deferredBegin());
275     EXPECT_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
276                 valueReturnsSourceId(5, Eq("unknownfile.h")));
277     EXPECT_CALL(insertIntoSourcesStatement,
278                 write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("unknownfile.h")));
279     EXPECT_CALL(databaseMock, commit());
280 
281     storage.fetchSourceId(SourceContextId{5}, "unknownfile.h");
282 }
283 
TEST_F(ProjectStorage,ValueForFetchSourceContextForIdCalls)284 TEST_F(ProjectStorage, ValueForFetchSourceContextForIdCalls)
285 {
286     EXPECT_CALL(databaseMock, deferredBegin());
287     EXPECT_CALL(selectSourceContextPathFromSourceContextsBySourceContextIdStatement,
288                 valueReturnPathString(5));
289     EXPECT_CALL(databaseMock, commit());
290 
291     storage.fetchSourceContextPath(SourceContextId{5});
292 }
293 
TEST_F(ProjectStorage,FetchSourceContextForId)294 TEST_F(ProjectStorage, FetchSourceContextForId)
295 {
296     auto path = storage.fetchSourceContextPath(SourceContextId{5});
297 
298     ASSERT_THAT(path, Eq("/path/to"));
299 }
300 
TEST_F(ProjectStorage,ThrowAsFetchingSourceContextPathForNonExistingId)301 TEST_F(ProjectStorage, ThrowAsFetchingSourceContextPathForNonExistingId)
302 {
303     ASSERT_THROW(storage.fetchSourceContextPath(SourceContextId{12}),
304                  QmlDesigner::SourceContextIdDoesNotExists);
305 }
306 
TEST_F(ProjectStorage,FetchSourceContextIdForUnknownSourceId)307 TEST_F(ProjectStorage, FetchSourceContextIdForUnknownSourceId)
308 {
309     ASSERT_THROW(storage.fetchSourceContextId(SourceId{1111}), QmlDesigner::SourceIdDoesNotExists);
310 }
311 
TEST_F(ProjectStorage,FetchSourceContextIdThrows)312 TEST_F(ProjectStorage, FetchSourceContextIdThrows)
313 {
314     ASSERT_THROW(storage.fetchSourceContextId(SourceId{41}), QmlDesigner::SourceIdDoesNotExists);
315 }
316 
TEST_F(ProjectStorage,GetTheSourceContextIdBackAfterFetchingANewEntryFromSourceContextsUnguarded)317 TEST_F(ProjectStorage, GetTheSourceContextIdBackAfterFetchingANewEntryFromSourceContextsUnguarded)
318 {
319     auto sourceContextId = storage.fetchSourceContextIdUnguarded("/some/not/known/path");
320 
321     ASSERT_THAT(sourceContextId, SourceContextId{12});
322 }
323 
TEST_F(ProjectStorage,GetTheSourceIdBackAfterFetchingANewEntryFromSourcesUnguarded)324 TEST_F(ProjectStorage, GetTheSourceIdBackAfterFetchingANewEntryFromSourcesUnguarded)
325 {
326     auto sourceId = storage.fetchSourceIdUnguarded(SourceContextId{5}, "unknownfile.h");
327 
328     ASSERT_THAT(sourceId, SourceId{12});
329 }
330 
TEST_F(ProjectStorage,SelectForFetchingSourceContextIdForKnownPathUnguardedCalls)331 TEST_F(ProjectStorage, SelectForFetchingSourceContextIdForKnownPathUnguardedCalls)
332 {
333     InSequence s;
334 
335     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
336                 valueReturnsSourceContextId(TypedEq<Utils::SmallStringView>("/path/to")));
337 
338     storage.fetchSourceContextIdUnguarded("/path/to");
339 }
340 
TEST_F(ProjectStorage,SelectForFetchingSourceIdForKnownPathUnguardedCalls)341 TEST_F(ProjectStorage, SelectForFetchingSourceIdForKnownPathUnguardedCalls)
342 {
343     EXPECT_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
344                 valueReturnsSourceId(5, Eq("file.h")));
345 
346     storage.fetchSourceIdUnguarded(SourceContextId{5}, "file.h");
347 }
348 
TEST_F(ProjectStorage,NotWriteForFetchingSourceContextIdForKnownPathUnguardedCalls)349 TEST_F(ProjectStorage, NotWriteForFetchingSourceContextIdForKnownPathUnguardedCalls)
350 {
351     EXPECT_CALL(insertIntoSourceContexts, write(An<Utils::SmallStringView>())).Times(0);
352 
353     storage.fetchSourceContextIdUnguarded("/path/to");
354 }
355 
TEST_F(ProjectStorage,NotWriteForFetchingSoureIdForKnownEntryUnguardedCalls)356 TEST_F(ProjectStorage, NotWriteForFetchingSoureIdForKnownEntryUnguardedCalls)
357 {
358     EXPECT_CALL(insertIntoSourcesStatement, write(An<uint>(), An<Utils::SmallStringView>())).Times(0);
359 
360     storage.fetchSourceIdUnguarded(SourceContextId{5}, "file.h");
361 }
362 
TEST_F(ProjectStorage,SelectAndWriteForFetchingSourceContextIdForUnknownPathUnguardedCalls)363 TEST_F(ProjectStorage, SelectAndWriteForFetchingSourceContextIdForUnknownPathUnguardedCalls)
364 {
365     InSequence s;
366 
367     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
368                 valueReturnsSourceContextId(
369                     TypedEq<Utils::SmallStringView>("/some/not/known/path")));
370     EXPECT_CALL(insertIntoSourceContexts,
371                 write(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
372 
373     storage.fetchSourceContextIdUnguarded("/some/not/known/path");
374 }
375 
TEST_F(ProjectStorage,SelectAndWriteForFetchingSourceIdForUnknownEntryUnguardedCalls)376 TEST_F(ProjectStorage, SelectAndWriteForFetchingSourceIdForUnknownEntryUnguardedCalls)
377 {
378     InSequence s;
379 
380     EXPECT_CALL(selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatment,
381                 valueReturnsSourceId(5, Eq("unknownfile.h")));
382     EXPECT_CALL(insertIntoSourcesStatement,
383                 write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("unknownfile.h")));
384 
385     storage.fetchSourceIdUnguarded(SourceContextId{5}, "unknownfile.h");
386 }
387 
TEST_F(ProjectStorage,SelectAndWriteForFetchingSourceContextIdTwoTimesIfTheIndexIsConstraintBecauseTheEntryExistsAlreadyCalls)388 TEST_F(ProjectStorage,
389        SelectAndWriteForFetchingSourceContextIdTwoTimesIfTheIndexIsConstraintBecauseTheEntryExistsAlreadyCalls)
390 {
391     InSequence s;
392 
393     EXPECT_CALL(databaseMock, deferredBegin());
394     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
395                 valueReturnsSourceContextId(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
396     EXPECT_CALL(insertIntoSourceContexts, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")))
397         .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy")));
398     EXPECT_CALL(databaseMock, rollback());
399     EXPECT_CALL(databaseMock, deferredBegin());
400     EXPECT_CALL(selectSourceContextIdFromSourceContextsBySourceContextPathStatement,
401                 valueReturnsSourceContextId(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
402     EXPECT_CALL(insertIntoSourceContexts,
403                 write(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
404     EXPECT_CALL(databaseMock, commit());
405 
406     storage.fetchSourceContextId("/other/unknow/path");
407 }
408 
TEST_F(ProjectStorage,FetchTypeByTypeIdCalls)409 TEST_F(ProjectStorage, FetchTypeByTypeIdCalls)
410 {
411     InSequence s;
412 
413     EXPECT_CALL(databaseMock, deferredBegin());
414     EXPECT_CALL(selectTypeByTypeIdStatement, valueReturnsStorageType(Eq(21)));
415     EXPECT_CALL(selectExportedTypesByTypeIdStatement, valuesReturnsStorageExportedTypes(_, Eq(21)));
416     EXPECT_CALL(databaseMock, commit());
417 
418     storage.fetchTypeByTypeId(TypeId{21});
419 }
420 
TEST_F(ProjectStorage,FetchTypesCalls)421 TEST_F(ProjectStorage, FetchTypesCalls)
422 {
423     InSequence s;
424     Storage::Type type{ImportId{}, {}, {}, {}, SourceId{}, {}, {}, {}, {}, {}, {}, {}, TypeId{55}};
425     Storage::Types types{type};
426 
427     EXPECT_CALL(databaseMock, deferredBegin());
428     EXPECT_CALL(selectTypesStatement, valuesReturnsStorageTypes(_)).WillOnce(Return(types));
429     EXPECT_CALL(selectExportedTypesByTypeIdStatement, valuesReturnsStorageExportedTypes(_, Eq(55)));
430     EXPECT_CALL(databaseMock, commit());
431 
432     storage.fetchTypes();
433 }
434 
435 class ProjectStorageSlowTest : public testing::Test
436 {
437 protected:
438     template<typename Range>
toValues(Range && range)439     static auto toValues(Range &&range)
440     {
441         using Type = typename std::decay_t<Range>;
442 
443         return std::vector<typename Type::value_type>{range.begin(), range.end()};
444     }
445 
addSomeDummyData()446     void addSomeDummyData()
447     {
448         auto sourceContextId1 = storage.fetchSourceContextId("/path/dummy");
449         auto sourceContextId2 = storage.fetchSourceContextId("/path/dummy2");
450         auto sourceContextId3 = storage.fetchSourceContextId("/path/");
451 
452         storage.fetchSourceId(sourceContextId1, "foo");
453         storage.fetchSourceId(sourceContextId1, "dummy");
454         storage.fetchSourceId(sourceContextId2, "foo");
455         storage.fetchSourceId(sourceContextId2, "bar");
456         storage.fetchSourceId(sourceContextId3, "foo");
457         storage.fetchSourceId(sourceContextId3, "bar");
458         storage.fetchSourceId(sourceContextId1, "bar");
459         storage.fetchSourceId(sourceContextId3, "bar");
460     }
461 
createTypes()462     auto createTypes()
463     {
464         setUpImports();
465 
466         sourceId1 = sourcePathCache.sourceId(path1);
467         sourceId2 = sourcePathCache.sourceId(path2);
468         sourceId3 = sourcePathCache.sourceId(path3);
469         sourceId4 = sourcePathCache.sourceId(path4);
470 
471         return Storage::Types{
472             Storage::Type{
473                 importId2,
474                 "QQuickItem",
475                 Storage::NativeType{"QObject"},
476                 TypeAccessSemantics::Reference,
477                 sourceId1,
478                 importIds,
479                 {Storage::ExportedType{"Item"}},
480                 {Storage::PropertyDeclaration{"data",
481                                               Storage::NativeType{"QObject"},
482                                               Storage::PropertyDeclarationTraits::IsList},
483                  Storage::PropertyDeclaration{"children",
484                                               Storage::ExportedType{"Item"},
485                                               Storage::PropertyDeclarationTraits::IsList
486                                                   | Storage::PropertyDeclarationTraits::IsReadOnly}},
487                 {Storage::FunctionDeclaration{"execute", "", {Storage::ParameterDeclaration{"arg", ""}}},
488                  Storage::FunctionDeclaration{
489                      "values",
490                      "Vector3D",
491                      {Storage::ParameterDeclaration{"arg1", "int"},
492                       Storage::ParameterDeclaration{"arg2",
493                                                     "QObject",
494                                                     Storage::PropertyDeclarationTraits::IsPointer},
495                       Storage::ParameterDeclaration{"arg3", "string"}}}},
496                 {Storage::SignalDeclaration{"execute", {Storage::ParameterDeclaration{"arg", ""}}},
497                  Storage::SignalDeclaration{
498                      "values",
499                      {Storage::ParameterDeclaration{"arg1", "int"},
500                       Storage::ParameterDeclaration{"arg2",
501                                                     "QObject",
502                                                     Storage::PropertyDeclarationTraits::IsPointer},
503                       Storage::ParameterDeclaration{"arg3", "string"}}}},
504                 {Storage::EnumerationDeclaration{"Enum",
505                                                  {Storage::EnumeratorDeclaration{"Foo"},
506                                                   Storage::EnumeratorDeclaration{"Bar", 32}}},
507                  Storage::EnumerationDeclaration{"Type",
508                                                  {Storage::EnumeratorDeclaration{"Foo"},
509                                                   Storage::EnumeratorDeclaration{"Poo", 12}}}}},
510             Storage::Type{importId1,
511                           "QObject",
512                           Storage::NativeType{},
513                           TypeAccessSemantics::Reference,
514                           sourceId2,
515                           importIds,
516                           {Storage::ExportedType{"Object"}, Storage::ExportedType{"Obj"}}}};
517     }
518 
createTypesWithAliases()519     auto createTypesWithAliases()
520     {
521         auto types = createTypes();
522 
523         types[1].propertyDeclarations.push_back(
524             Storage::PropertyDeclaration{"objects",
525                                          Storage::NativeType{"QObject"},
526                                          Storage::PropertyDeclarationTraits::IsList});
527 
528         types.push_back(Storage::Type{importId2,
529                                       "QAliasItem",
530                                       Storage::NativeType{"QQuickItem"},
531                                       TypeAccessSemantics::Reference,
532                                       sourceId3,
533                                       importIds,
534                                       {Storage::ExportedType{"AliasItem"}}});
535         types.back().propertyDeclarations.push_back(
536             Storage::PropertyDeclaration{"data",
537                                          Storage::NativeType{"QObject"},
538                                          Storage::PropertyDeclarationTraits::IsList});
539         types.back().aliasDeclarations.push_back(
540             Storage::AliasPropertyDeclaration{"items", Storage::NativeType{"QQuickItem"}, "children"});
541         types.back().aliasDeclarations.push_back(
542             Storage::AliasPropertyDeclaration{"objects", Storage::NativeType{"QQuickItem"}, "objects"});
543 
544         types.push_back(
545             Storage::Type{importId3,
546                           "QObject2",
547                           Storage::NativeType{},
548                           TypeAccessSemantics::Reference,
549                           sourceId4,
550                           importIds,
551                           {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}});
552         types[3].propertyDeclarations.push_back(
553             Storage::PropertyDeclaration{"objects",
554                                          Storage::NativeType{"QObject"},
555                                          Storage::PropertyDeclarationTraits::IsList});
556 
557         return types;
558     }
559 
createImports()560     auto createImports()
561     {
562         importSourceId1 = sourcePathCache.sourceId(importPath1);
563         importSourceId2 = sourcePathCache.sourceId(importPath2);
564         importSourceId3 = sourcePathCache.sourceId(importPath3);
565 
566         return Storage::Imports{Storage::Import{"Qml", Storage::VersionNumber{2}, importSourceId1, {}},
567                                 Storage::Import{"QtQuick",
568                                                 Storage::VersionNumber{},
569                                                 importSourceId2,
570                                                 {Storage::Import{"Qml", Storage::VersionNumber{2}}}},
571                                 Storage::Import{"/path/to",
572                                                 Storage::VersionNumber{},
573                                                 SourceId{},
574                                                 {Storage::Import{"QtQuick"},
575                                                  Storage::Import{"Qml", Storage::VersionNumber{2}}}}};
576     }
577 
setUpImports()578     void setUpImports()
579     {
580         auto imports = createImports();
581         storage.synchronizeImports(imports);
582         importIds = storage.fetchImportIds(imports);
583         importId1 = importIds[0];
584         importId2 = importIds[1];
585         importId3 = importIds[2];
586     }
587 
588 protected:
589     using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
590     Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
591     ProjectStorage storage{database, database.isInitialized()};
592     QmlDesigner::SourcePathCache<ProjectStorage> sourcePathCache{storage};
593     QmlDesigner::SourcePathView path1{"/path1/to"};
594     QmlDesigner::SourcePathView path2{"/path2/to"};
595     QmlDesigner::SourcePathView path3{"/path3/to"};
596     QmlDesigner::SourcePathView path4{"/path4/to"};
597     SourceId sourceId1;
598     SourceId sourceId2;
599     SourceId sourceId3;
600     SourceId sourceId4;
601     QmlDesigner::SourcePathView importPath1{"/import/path1/to"};
602     QmlDesigner::SourcePathView importPath2{"/import/path2/to"};
603     QmlDesigner::SourcePathView importPath3{"/import/aaaa/to"};
604     SourceId importSourceId1;
605     SourceId importSourceId2;
606     SourceId importSourceId3;
607     ImportId importId1;
608     ImportId importId2;
609     ImportId importId3;
610     QmlDesigner::ImportIds importIds;
611 };
612 
TEST_F(ProjectStorageSlowTest,FetchSourceContextIdReturnsAlwaysTheSameIdForTheSamePath)613 TEST_F(ProjectStorageSlowTest, FetchSourceContextIdReturnsAlwaysTheSameIdForTheSamePath)
614 {
615     auto sourceContextId = storage.fetchSourceContextId("/path/to");
616 
617     auto newSourceContextId = storage.fetchSourceContextId("/path/to");
618 
619     ASSERT_THAT(newSourceContextId, Eq(sourceContextId));
620 }
621 
TEST_F(ProjectStorageSlowTest,FetchSourceContextIdReturnsNotTheSameIdForDifferentPath)622 TEST_F(ProjectStorageSlowTest, FetchSourceContextIdReturnsNotTheSameIdForDifferentPath)
623 {
624     auto sourceContextId = storage.fetchSourceContextId("/path/to");
625 
626     auto newSourceContextId = storage.fetchSourceContextId("/path/to2");
627 
628     ASSERT_THAT(newSourceContextId, Ne(sourceContextId));
629 }
630 
TEST_F(ProjectStorageSlowTest,FetchSourceContextPath)631 TEST_F(ProjectStorageSlowTest, FetchSourceContextPath)
632 {
633     auto sourceContextId = storage.fetchSourceContextId("/path/to");
634 
635     auto path = storage.fetchSourceContextPath(sourceContextId);
636 
637     ASSERT_THAT(path, Eq("/path/to"));
638 }
639 
TEST_F(ProjectStorageSlowTest,FetchUnknownSourceContextPathThrows)640 TEST_F(ProjectStorageSlowTest, FetchUnknownSourceContextPathThrows)
641 {
642     ASSERT_THROW(storage.fetchSourceContextPath(SourceContextId{323}),
643                  QmlDesigner::SourceContextIdDoesNotExists);
644 }
645 
TEST_F(ProjectStorageSlowTest,FetchAllSourceContextsAreEmptyIfNoSourceContextsExists)646 TEST_F(ProjectStorageSlowTest, FetchAllSourceContextsAreEmptyIfNoSourceContextsExists)
647 {
648     auto sourceContexts = storage.fetchAllSourceContexts();
649 
650     ASSERT_THAT(toValues(sourceContexts), IsEmpty());
651 }
652 
TEST_F(ProjectStorageSlowTest,FetchAllSourceContexts)653 TEST_F(ProjectStorageSlowTest, FetchAllSourceContexts)
654 {
655     auto sourceContextId = storage.fetchSourceContextId("/path/to");
656     auto sourceContextId2 = storage.fetchSourceContextId("/path/to2");
657 
658     auto sourceContexts = storage.fetchAllSourceContexts();
659 
660     ASSERT_THAT(toValues(sourceContexts),
661                 UnorderedElementsAre(IsSourceContext(sourceContextId, "/path/to"),
662                                      IsSourceContext(sourceContextId2, "/path/to2")));
663 }
664 
TEST_F(ProjectStorageSlowTest,FetchSourceIdFirstTime)665 TEST_F(ProjectStorageSlowTest, FetchSourceIdFirstTime)
666 {
667     addSomeDummyData();
668     auto sourceContextId = storage.fetchSourceContextId("/path/to");
669 
670     auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
671 
672     ASSERT_TRUE(sourceId.isValid());
673 }
674 
TEST_F(ProjectStorageSlowTest,FetchExistingSourceId)675 TEST_F(ProjectStorageSlowTest, FetchExistingSourceId)
676 {
677     addSomeDummyData();
678     auto sourceContextId = storage.fetchSourceContextId("/path/to");
679     auto createdSourceId = storage.fetchSourceId(sourceContextId, "foo");
680 
681     auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
682 
683     ASSERT_THAT(sourceId, createdSourceId);
684 }
685 
TEST_F(ProjectStorageSlowTest,FetchSourceIdWithDifferentContextIdAreNotEqual)686 TEST_F(ProjectStorageSlowTest, FetchSourceIdWithDifferentContextIdAreNotEqual)
687 {
688     addSomeDummyData();
689     auto sourceContextId = storage.fetchSourceContextId("/path/to");
690     auto sourceContextId2 = storage.fetchSourceContextId("/path/to2");
691     auto sourceId2 = storage.fetchSourceId(sourceContextId2, "foo");
692 
693     auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
694 
695     ASSERT_THAT(sourceId, Ne(sourceId2));
696 }
697 
TEST_F(ProjectStorageSlowTest,FetchSourceIdWithDifferentNameAreNotEqual)698 TEST_F(ProjectStorageSlowTest, FetchSourceIdWithDifferentNameAreNotEqual)
699 {
700     addSomeDummyData();
701     auto sourceContextId = storage.fetchSourceContextId("/path/to");
702     auto sourceId2 = storage.fetchSourceId(sourceContextId, "foo");
703 
704     auto sourceId = storage.fetchSourceId(sourceContextId, "foo2");
705 
706     ASSERT_THAT(sourceId, Ne(sourceId2));
707 }
708 
TEST_F(ProjectStorageSlowTest,FetchSourceIdWithNonExistingSourceContextIdThrows)709 TEST_F(ProjectStorageSlowTest, FetchSourceIdWithNonExistingSourceContextIdThrows)
710 {
711     ASSERT_THROW(storage.fetchSourceId(SourceContextId{42}, "foo"),
712                  Sqlite::ConstraintPreventsModification);
713 }
714 
TEST_F(ProjectStorageSlowTest,FetchSourceNameAndSourceContextIdForNonExistingSourceId)715 TEST_F(ProjectStorageSlowTest, FetchSourceNameAndSourceContextIdForNonExistingSourceId)
716 {
717     ASSERT_THROW(storage.fetchSourceNameAndSourceContextId(SourceId{212}),
718                  QmlDesigner::SourceIdDoesNotExists);
719 }
720 
TEST_F(ProjectStorageSlowTest,FetchSourceNameAndSourceContextIdForNonExistingEntry)721 TEST_F(ProjectStorageSlowTest, FetchSourceNameAndSourceContextIdForNonExistingEntry)
722 {
723     addSomeDummyData();
724     auto sourceContextId = storage.fetchSourceContextId("/path/to");
725     auto sourceId = storage.fetchSourceId(sourceContextId, "foo");
726 
727     auto sourceNameAndSourceContextId = storage.fetchSourceNameAndSourceContextId(sourceId);
728 
729     ASSERT_THAT(sourceNameAndSourceContextId, IsSourceNameAndSourceContextId("foo", sourceContextId));
730 }
731 
TEST_F(ProjectStorageSlowTest,FetchSourceContextIdForNonExistingSourceId)732 TEST_F(ProjectStorageSlowTest, FetchSourceContextIdForNonExistingSourceId)
733 {
734     ASSERT_THROW(storage.fetchSourceContextId(SourceId{212}), QmlDesigner::SourceIdDoesNotExists);
735 }
736 
TEST_F(ProjectStorageSlowTest,FetchSourceContextIdForExistingSourceId)737 TEST_F(ProjectStorageSlowTest, FetchSourceContextIdForExistingSourceId)
738 {
739     addSomeDummyData();
740     auto originalSourceContextId = storage.fetchSourceContextId("/path/to3");
741     auto sourceId = storage.fetchSourceId(originalSourceContextId, "foo");
742 
743     auto sourceContextId = storage.fetchSourceContextId(sourceId);
744 
745     ASSERT_THAT(sourceContextId, Eq(originalSourceContextId));
746 }
747 
TEST_F(ProjectStorageSlowTest,FetchAllSources)748 TEST_F(ProjectStorageSlowTest, FetchAllSources)
749 {
750     auto sources = storage.fetchAllSources();
751 
752     ASSERT_THAT(toValues(sources), IsEmpty());
753 }
754 
TEST_F(ProjectStorageSlowTest,FetchSourceIdUnguardedFirstTime)755 TEST_F(ProjectStorageSlowTest, FetchSourceIdUnguardedFirstTime)
756 {
757     addSomeDummyData();
758     auto sourceContextId = storage.fetchSourceContextId("/path/to");
759     std::lock_guard lock{database};
760 
761     auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
762 
763     ASSERT_TRUE(sourceId.isValid());
764 }
765 
TEST_F(ProjectStorageSlowTest,FetchExistingSourceIdUnguarded)766 TEST_F(ProjectStorageSlowTest, FetchExistingSourceIdUnguarded)
767 {
768     addSomeDummyData();
769     auto sourceContextId = storage.fetchSourceContextId("/path/to");
770     std::lock_guard lock{database};
771     auto createdSourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
772 
773     auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
774 
775     ASSERT_THAT(sourceId, createdSourceId);
776 }
777 
TEST_F(ProjectStorageSlowTest,FetchSourceIdUnguardedWithDifferentContextIdAreNotEqual)778 TEST_F(ProjectStorageSlowTest, FetchSourceIdUnguardedWithDifferentContextIdAreNotEqual)
779 {
780     addSomeDummyData();
781     auto sourceContextId = storage.fetchSourceContextId("/path/to");
782     auto sourceContextId2 = storage.fetchSourceContextId("/path/to2");
783     std::lock_guard lock{database};
784     auto sourceId2 = storage.fetchSourceIdUnguarded(sourceContextId2, "foo");
785 
786     auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
787 
788     ASSERT_THAT(sourceId, Ne(sourceId2));
789 }
790 
TEST_F(ProjectStorageSlowTest,FetchSourceIdUnguardedWithDifferentNameAreNotEqual)791 TEST_F(ProjectStorageSlowTest, FetchSourceIdUnguardedWithDifferentNameAreNotEqual)
792 {
793     addSomeDummyData();
794     auto sourceContextId = storage.fetchSourceContextId("/path/to");
795     std::lock_guard lock{database};
796     auto sourceId2 = storage.fetchSourceIdUnguarded(sourceContextId, "foo");
797 
798     auto sourceId = storage.fetchSourceIdUnguarded(sourceContextId, "foo2");
799 
800     ASSERT_THAT(sourceId, Ne(sourceId2));
801 }
802 
TEST_F(ProjectStorageSlowTest,FetchSourceIdUnguardedWithNonExistingSourceContextIdThrows)803 TEST_F(ProjectStorageSlowTest, FetchSourceIdUnguardedWithNonExistingSourceContextIdThrows)
804 {
805     std::lock_guard lock{database};
806 
807     ASSERT_THROW(storage.fetchSourceIdUnguarded(SourceContextId{42}, "foo"),
808                  Sqlite::ConstraintPreventsModification);
809 }
810 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypes)811 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypes)
812 {
813     Storage::Types types{createTypes()};
814 
815     storage.synchronizeTypes(types, {sourceId1, sourceId2});
816 
817     ASSERT_THAT(storage.fetchTypes(),
818                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
819                                                          "QObject",
820                                                          Storage::NativeType{},
821                                                          TypeAccessSemantics::Reference,
822                                                          sourceId2),
823                                            Field(&Storage::Type::exportedTypes,
824                                                  UnorderedElementsAre(IsExportedType("Object"),
825                                                                       IsExportedType("Obj")))),
826                                      AllOf(IsStorageType(importId2,
827                                                          "QQuickItem",
828                                                          Storage::NativeType{"QObject"},
829                                                          TypeAccessSemantics::Reference,
830                                                          sourceId1),
831                                            Field(&Storage::Type::exportedTypes,
832                                                  UnorderedElementsAre(IsExportedType("Item"))))));
833 }
834 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypesWithExportedPrototypeName)835 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypesWithExportedPrototypeName)
836 {
837     Storage::Types types{createTypes()};
838     types[0].prototype = Storage::ExportedType{"Object"};
839 
840     storage.synchronizeTypes(types, {sourceId1, sourceId2});
841 
842     ASSERT_THAT(storage.fetchTypes(),
843                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
844                                                          "QObject",
845                                                          Storage::NativeType{},
846                                                          TypeAccessSemantics::Reference,
847                                                          sourceId2),
848                                            Field(&Storage::Type::exportedTypes,
849                                                  UnorderedElementsAre(IsExportedType("Object"),
850                                                                       IsExportedType("Obj")))),
851                                      AllOf(IsStorageType(importId2,
852                                                          "QQuickItem",
853                                                          Storage::NativeType{"QObject"},
854                                                          TypeAccessSemantics::Reference,
855                                                          sourceId1),
856                                            Field(&Storage::Type::exportedTypes,
857                                                  UnorderedElementsAre(IsExportedType("Item"))))));
858 }
859 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypesThrowsWithWrongExportedPrototypeName)860 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypesThrowsWithWrongExportedPrototypeName)
861 {
862     Storage::Types types{createTypes()};
863     types[0].prototype = Storage::ExportedType{"Objec"};
864 
865     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
866                  QmlDesigner::TypeNameDoesNotExists);
867 }
868 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypesWithMissingImportAndExportedPrototypeName)869 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypesWithMissingImportAndExportedPrototypeName)
870 {
871     Storage::Types types{createTypes()};
872     types[0].importIds = {importId1};
873     types[1].prototype = Storage::ExportedType{"Object"};
874 
875     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
876                  QmlDesigner::TypeNameDoesNotExists);
877 }
878 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypesWithMissingImport)879 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypesWithMissingImport)
880 {
881     Storage::Types types{createTypes()};
882     types[0].importIds = {importId1};
883 
884     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
885                  QmlDesigner::TypeNameDoesNotExists);
886 }
887 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsNewTypesReverseOrder)888 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsNewTypesReverseOrder)
889 {
890     Storage::Types types{createTypes()};
891     std::reverse(types.begin(), types.end());
892 
893     storage.synchronizeTypes(types, {sourceId1, sourceId2});
894 
895     ASSERT_THAT(storage.fetchTypes(),
896                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
897                                                          "QObject",
898                                                          Storage::NativeType{},
899                                                          TypeAccessSemantics::Reference,
900                                                          sourceId2),
901                                            Field(&Storage::Type::exportedTypes,
902                                                  UnorderedElementsAre(IsExportedType("Object"),
903                                                                       IsExportedType("Obj")))),
904                                      AllOf(IsStorageType(importId2,
905                                                          "QQuickItem",
906                                                          Storage::NativeType{"QObject"},
907                                                          TypeAccessSemantics::Reference,
908                                                          sourceId1),
909                                            Field(&Storage::Type::exportedTypes,
910                                                  UnorderedElementsAre(IsExportedType("Item"))))));
911 }
912 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesOverwritesTypeAccessSemantics)913 TEST_F(ProjectStorageSlowTest, SynchronizeTypesOverwritesTypeAccessSemantics)
914 {
915     Storage::Types types{createTypes()};
916     storage.synchronizeTypes(types, {sourceId1, sourceId2});
917     types[0].accessSemantics = TypeAccessSemantics::Value;
918     types[1].accessSemantics = TypeAccessSemantics::Value;
919 
920     storage.synchronizeTypes(types, {sourceId1, sourceId2});
921 
922     ASSERT_THAT(storage.fetchTypes(),
923                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
924                                                          "QObject",
925                                                          Storage::NativeType{},
926                                                          TypeAccessSemantics::Value,
927                                                          sourceId2),
928                                            Field(&Storage::Type::exportedTypes,
929                                                  UnorderedElementsAre(IsExportedType("Object"),
930                                                                       IsExportedType("Obj")))),
931                                      AllOf(IsStorageType(importId2,
932                                                          "QQuickItem",
933                                                          Storage::NativeType{"QObject"},
934                                                          TypeAccessSemantics::Value,
935                                                          sourceId1),
936                                            Field(&Storage::Type::exportedTypes,
937                                                  UnorderedElementsAre(IsExportedType("Item"))))));
938 }
939 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesOverwritesSources)940 TEST_F(ProjectStorageSlowTest, SynchronizeTypesOverwritesSources)
941 {
942     Storage::Types types{createTypes()};
943     storage.synchronizeTypes(types, {sourceId1, sourceId2});
944     types[0].sourceId = sourceId3;
945     types[1].sourceId = sourceId4;
946 
947     storage.synchronizeTypes(types, {sourceId1, sourceId2});
948 
949     ASSERT_THAT(storage.fetchTypes(),
950                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
951                                                          "QObject",
952                                                          Storage::NativeType{},
953                                                          TypeAccessSemantics::Reference,
954                                                          sourceId4),
955                                            Field(&Storage::Type::exportedTypes,
956                                                  UnorderedElementsAre(IsExportedType("Object"),
957                                                                       IsExportedType("Obj")))),
958                                      AllOf(IsStorageType(importId2,
959                                                          "QQuickItem",
960                                                          Storage::NativeType{"QObject"},
961                                                          TypeAccessSemantics::Reference,
962                                                          sourceId3),
963                                            Field(&Storage::Type::exportedTypes,
964                                                  UnorderedElementsAre(IsExportedType("Item"))))));
965 }
966 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesInsertTypeIntoPrototypeChain)967 TEST_F(ProjectStorageSlowTest, SynchronizeTypesInsertTypeIntoPrototypeChain)
968 {
969     Storage::Types types{createTypes()};
970     storage.synchronizeTypes(types, {sourceId1, sourceId2});
971     types[0].prototype = Storage::NativeType{"QQuickObject"};
972     types.push_back(Storage::Type{importId2,
973                                   "QQuickObject",
974                                   Storage::NativeType{"QObject"},
975                                   TypeAccessSemantics::Reference,
976                                   sourceId1,
977                                   importIds,
978                                   {Storage::ExportedType{"Object"}}});
979 
980     storage.synchronizeTypes(types, {sourceId1, sourceId2});
981 
982     ASSERT_THAT(storage.fetchTypes(),
983                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
984                                                          "QObject",
985                                                          Storage::NativeType{},
986                                                          TypeAccessSemantics::Reference,
987                                                          sourceId2),
988                                            Field(&Storage::Type::exportedTypes,
989                                                  UnorderedElementsAre(IsExportedType("Object"),
990                                                                       IsExportedType("Obj")))),
991                                      AllOf(IsStorageType(importId2,
992                                                          "QQuickObject",
993                                                          Storage::NativeType{"QObject"},
994                                                          TypeAccessSemantics::Reference,
995                                                          sourceId1),
996                                            Field(&Storage::Type::exportedTypes,
997                                                  UnorderedElementsAre(IsExportedType("Object")))),
998                                      AllOf(IsStorageType(importId2,
999                                                          "QQuickItem",
1000                                                          Storage::NativeType{"QQuickObject"},
1001                                                          TypeAccessSemantics::Reference,
1002                                                          sourceId1),
1003                                            Field(&Storage::Type::exportedTypes,
1004                                                  UnorderedElementsAre(IsExportedType("Item"))))));
1005 }
1006 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddExplicitPrototype)1007 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddExplicitPrototype)
1008 {
1009     Storage::Types types{createTypes()};
1010     types[0].prototype = Storage::ExplicitExportedType{"Object", importId2};
1011     types.push_back(Storage::Type{importId2,
1012                                   "QQuickObject",
1013                                   Storage::NativeType{"QObject"},
1014                                   TypeAccessSemantics::Reference,
1015                                   sourceId1,
1016                                   importIds,
1017                                   {Storage::ExportedType{"Object"}}});
1018 
1019     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1020 
1021     ASSERT_THAT(storage.fetchTypes(),
1022                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
1023                                                          "QObject",
1024                                                          Storage::NativeType{},
1025                                                          TypeAccessSemantics::Reference,
1026                                                          sourceId2),
1027                                            Field(&Storage::Type::exportedTypes,
1028                                                  UnorderedElementsAre(IsExportedType("Object"),
1029                                                                       IsExportedType("Obj")))),
1030                                      AllOf(IsStorageType(importId2,
1031                                                          "QQuickObject",
1032                                                          Storage::NativeType{"QObject"},
1033                                                          TypeAccessSemantics::Reference,
1034                                                          sourceId1),
1035                                            Field(&Storage::Type::exportedTypes,
1036                                                  UnorderedElementsAre(IsExportedType("Object")))),
1037                                      AllOf(IsStorageType(importId2,
1038                                                          "QQuickItem",
1039                                                          Storage::NativeType{"QQuickObject"},
1040                                                          TypeAccessSemantics::Reference,
1041                                                          sourceId1),
1042                                            Field(&Storage::Type::exportedTypes,
1043                                                  UnorderedElementsAre(IsExportedType("Item"))))));
1044 }
1045 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesThrowsForMissingPrototype)1046 TEST_F(ProjectStorageSlowTest, SynchronizeTypesThrowsForMissingPrototype)
1047 {
1048     sourceId1 = sourcePathCache.sourceId(path1);
1049     Storage::Types types{Storage::Type{importId2,
1050                                        "QQuickItem",
1051                                        Storage::NativeType{"QObject"},
1052                                        TypeAccessSemantics::Reference,
1053                                        sourceId1,
1054                                        importIds,
1055                                        {Storage::ExportedType{"Item"}}}};
1056 
1057     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1}), QmlDesigner::TypeNameDoesNotExists);
1058 }
1059 
TEST_F(ProjectStorageSlowTest,TypeWithInvalidSourceIdThrows)1060 TEST_F(ProjectStorageSlowTest, TypeWithInvalidSourceIdThrows)
1061 {
1062     Storage::Types types{Storage::Type{importId2,
1063                                        "QQuickItem",
1064                                        Storage::NativeType{""},
1065                                        TypeAccessSemantics::Reference,
1066                                        SourceId{},
1067                                        importIds,
1068                                        {Storage::ExportedType{"Item"}}}};
1069 
1070     ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::TypeHasInvalidSourceId);
1071 }
1072 
TEST_F(ProjectStorageSlowTest,DeleteTypeIfSourceIdIsSynchronized)1073 TEST_F(ProjectStorageSlowTest, DeleteTypeIfSourceIdIsSynchronized)
1074 {
1075     Storage::Types types{createTypes()};
1076     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1077     types.erase(types.begin());
1078 
1079     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1080 
1081     ASSERT_THAT(storage.fetchTypes(),
1082                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
1083                                                          "QObject",
1084                                                          Storage::NativeType{},
1085                                                          TypeAccessSemantics::Reference,
1086                                                          sourceId2),
1087                                            Field(&Storage::Type::exportedTypes,
1088                                                  UnorderedElementsAre(IsExportedType("Object"),
1089                                                                       IsExportedType("Obj"))))));
1090 }
1091 
TEST_F(ProjectStorageSlowTest,DontDeleteTypeIfSourceIdIsNotSynchronized)1092 TEST_F(ProjectStorageSlowTest, DontDeleteTypeIfSourceIdIsNotSynchronized)
1093 {
1094     Storage::Types types{createTypes()};
1095     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1096     types.pop_back();
1097 
1098     storage.synchronizeTypes(types, {sourceId1});
1099 
1100     ASSERT_THAT(storage.fetchTypes(),
1101                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
1102                                                          "QObject",
1103                                                          Storage::NativeType{},
1104                                                          TypeAccessSemantics::Reference,
1105                                                          sourceId2),
1106                                            Field(&Storage::Type::exportedTypes,
1107                                                  UnorderedElementsAre(IsExportedType("Object"),
1108                                                                       IsExportedType("Obj")))),
1109                                      AllOf(IsStorageType(importId2,
1110                                                          "QQuickItem",
1111                                                          Storage::NativeType{"QObject"},
1112                                                          TypeAccessSemantics::Reference,
1113                                                          sourceId1),
1114                                            Field(&Storage::Type::exportedTypes,
1115                                                  UnorderedElementsAre(IsExportedType("Item"))))));
1116 }
1117 
TEST_F(ProjectStorageSlowTest,BreakingPrototypeChainByDeletingBaseComponentThrows)1118 TEST_F(ProjectStorageSlowTest, BreakingPrototypeChainByDeletingBaseComponentThrows)
1119 {
1120     Storage::Types types{createTypes()};
1121     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1122     types.pop_back();
1123 
1124     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1125                  Sqlite::ConstraintPreventsModification);
1126 }
1127 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddPropertyDeclarations)1128 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddPropertyDeclarations)
1129 {
1130     Storage::Types types{createTypes()};
1131 
1132     storage.synchronizeTypes(types, {});
1133 
1134     ASSERT_THAT(storage.fetchTypes(),
1135                 Contains(
1136                     AllOf(IsStorageType(importId2,
1137                                         "QQuickItem",
1138                                         Storage::NativeType{"QObject"},
1139                                         TypeAccessSemantics::Reference,
1140                                         sourceId1),
1141                           Field(&Storage::Type::propertyDeclarations,
1142                                 UnorderedElementsAre(
1143                                     IsPropertyDeclaration("data",
1144                                                           Storage::NativeType{"QObject"},
1145                                                           Storage::PropertyDeclarationTraits::IsList),
1146                                     IsPropertyDeclaration(
1147                                         "children",
1148                                         Storage::NativeType{"QQuickItem"},
1149                                         Storage::PropertyDeclarationTraits::IsList
1150                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1151 }
1152 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddPropertyDeclarationsWithMissingImportIdsForNativeTypes)1153 TEST_F(ProjectStorageSlowTest,
1154        SynchronizeTypesAddPropertyDeclarationsWithMissingImportIdsForNativeTypes)
1155 {
1156     Storage::Types types{createTypes()};
1157     types[0].importIds = {importId2};
1158     types[0].propertyDeclarations.pop_back();
1159 
1160     ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::TypeNameDoesNotExists);
1161 }
1162 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddPropertyDeclarationsWithMissingImportIdsForExportedTypes)1163 TEST_F(ProjectStorageSlowTest,
1164        SynchronizeTypesAddPropertyDeclarationsWithMissingImportIdsForExportedTypes)
1165 {
1166     Storage::Types types{createTypes()};
1167     types[0].importIds = {importId1};
1168     types[0].propertyDeclarations[0].typeName = Storage::ExportedType{"Obj"};
1169 
1170     ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::TypeNameDoesNotExists);
1171 }
1172 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddPropertyDeclarationExplicitType)1173 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddPropertyDeclarationExplicitType)
1174 {
1175     Storage::Types types{createTypes()};
1176     types[0].propertyDeclarations[0].typeName = Storage::ExplicitExportedType{"Object", importId2};
1177     types.push_back(Storage::Type{importId2,
1178                                   "QQuickObject",
1179                                   Storage::NativeType{"QObject"},
1180                                   TypeAccessSemantics::Reference,
1181                                   sourceId1,
1182                                   importIds,
1183                                   {Storage::ExportedType{"Object"}}});
1184 
1185     storage.synchronizeTypes(types, {});
1186 
1187     ASSERT_THAT(storage.fetchTypes(),
1188                 Contains(
1189                     AllOf(IsStorageType(importId2,
1190                                         "QQuickItem",
1191                                         Storage::NativeType{"QObject"},
1192                                         TypeAccessSemantics::Reference,
1193                                         sourceId1),
1194                           Field(&Storage::Type::propertyDeclarations,
1195                                 UnorderedElementsAre(
1196                                     IsPropertyDeclaration("data",
1197                                                           Storage::NativeType{"QQuickObject"},
1198                                                           Storage::PropertyDeclarationTraits::IsList),
1199                                     IsPropertyDeclaration(
1200                                         "children",
1201                                         Storage::NativeType{"QQuickItem"},
1202                                         Storage::PropertyDeclarationTraits::IsList
1203                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1204 }
1205 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesPropertyDeclarationType)1206 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesPropertyDeclarationType)
1207 {
1208     Storage::Types types{createTypes()};
1209     storage.synchronizeTypes(types, {});
1210     types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QQuickItem"};
1211 
1212     storage.synchronizeTypes(types, {});
1213 
1214     ASSERT_THAT(storage.fetchTypes(),
1215                 Contains(
1216                     AllOf(IsStorageType(importId2,
1217                                         "QQuickItem",
1218                                         Storage::NativeType{"QObject"},
1219                                         TypeAccessSemantics::Reference,
1220                                         sourceId1),
1221                           Field(&Storage::Type::propertyDeclarations,
1222                                 UnorderedElementsAre(
1223                                     IsPropertyDeclaration("data",
1224                                                           Storage::NativeType{"QQuickItem"},
1225                                                           Storage::PropertyDeclarationTraits::IsList),
1226                                     IsPropertyDeclaration(
1227                                         "children",
1228                                         Storage::NativeType{"QQuickItem"},
1229                                         Storage::PropertyDeclarationTraits::IsList
1230                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1231 }
1232 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesDeclarationTraits)1233 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesDeclarationTraits)
1234 {
1235     Storage::Types types{createTypes()};
1236     storage.synchronizeTypes(types, {});
1237     types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer;
1238 
1239     storage.synchronizeTypes(types, {});
1240 
1241     ASSERT_THAT(storage.fetchTypes(),
1242                 Contains(
1243                     AllOf(IsStorageType(importId2,
1244                                         "QQuickItem",
1245                                         Storage::NativeType{"QObject"},
1246                                         TypeAccessSemantics::Reference,
1247                                         sourceId1),
1248                           Field(&Storage::Type::propertyDeclarations,
1249                                 UnorderedElementsAre(
1250                                     IsPropertyDeclaration("data",
1251                                                           Storage::NativeType{"QObject"},
1252                                                           Storage::PropertyDeclarationTraits::IsPointer),
1253                                     IsPropertyDeclaration(
1254                                         "children",
1255                                         Storage::NativeType{"QQuickItem"},
1256                                         Storage::PropertyDeclarationTraits::IsList
1257                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1258 }
1259 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesDeclarationTraitsAndType)1260 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesDeclarationTraitsAndType)
1261 {
1262     Storage::Types types{createTypes()};
1263     storage.synchronizeTypes(types, {});
1264     types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer;
1265     types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QQuickItem"};
1266 
1267     storage.synchronizeTypes(types, {});
1268 
1269     ASSERT_THAT(storage.fetchTypes(),
1270                 Contains(
1271                     AllOf(IsStorageType(importId2,
1272                                         "QQuickItem",
1273                                         Storage::NativeType{"QObject"},
1274                                         TypeAccessSemantics::Reference,
1275                                         sourceId1),
1276                           Field(&Storage::Type::propertyDeclarations,
1277                                 UnorderedElementsAre(
1278                                     IsPropertyDeclaration("data",
1279                                                           Storage::NativeType{"QQuickItem"},
1280                                                           Storage::PropertyDeclarationTraits::IsPointer),
1281                                     IsPropertyDeclaration(
1282                                         "children",
1283                                         Storage::NativeType{"QQuickItem"},
1284                                         Storage::PropertyDeclarationTraits::IsList
1285                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1286 }
1287 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovesAPropertyDeclaration)1288 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesAPropertyDeclaration)
1289 {
1290     Storage::Types types{createTypes()};
1291     storage.synchronizeTypes(types, {});
1292     types[0].propertyDeclarations.pop_back();
1293 
1294     storage.synchronizeTypes(types, {});
1295 
1296     ASSERT_THAT(storage.fetchTypes(),
1297                 Contains(AllOf(IsStorageType(importId2,
1298                                              "QQuickItem",
1299                                              Storage::NativeType{"QObject"},
1300                                              TypeAccessSemantics::Reference,
1301                                              sourceId1),
1302                                Field(&Storage::Type::propertyDeclarations,
1303                                      UnorderedElementsAre(IsPropertyDeclaration(
1304                                          "data",
1305                                          Storage::NativeType{"QObject"},
1306                                          Storage::PropertyDeclarationTraits::IsList))))));
1307 }
1308 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddsAPropertyDeclaration)1309 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsAPropertyDeclaration)
1310 {
1311     Storage::Types types{createTypes()};
1312     storage.synchronizeTypes(types, {});
1313     types[0].propertyDeclarations.push_back(
1314         Storage::PropertyDeclaration{"object",
1315                                      Storage::NativeType{"QObject"},
1316                                      Storage::PropertyDeclarationTraits::IsPointer});
1317 
1318     storage.synchronizeTypes(types, {});
1319 
1320     ASSERT_THAT(
1321         storage.fetchTypes(),
1322         Contains(AllOf(
1323             IsStorageType(importId2,
1324                           "QQuickItem",
1325                           Storage::NativeType{"QObject"},
1326                           TypeAccessSemantics::Reference,
1327                           sourceId1),
1328             Field(&Storage::Type::propertyDeclarations,
1329                   UnorderedElementsAre(
1330                       IsPropertyDeclaration("object",
1331                                             Storage::NativeType{"QObject"},
1332                                             Storage::PropertyDeclarationTraits::IsPointer),
1333                       IsPropertyDeclaration("data",
1334                                             Storage::NativeType{"QObject"},
1335                                             Storage::PropertyDeclarationTraits::IsList),
1336                       IsPropertyDeclaration("children",
1337                                             Storage::NativeType{"QQuickItem"},
1338                                             Storage::PropertyDeclarationTraits::IsList
1339                                                 | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1340 }
1341 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRenameAPropertyDeclaration)1342 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRenameAPropertyDeclaration)
1343 {
1344     Storage::Types types{createTypes()};
1345     storage.synchronizeTypes(types, {});
1346     types[0].propertyDeclarations[1].name = "objects";
1347 
1348     storage.synchronizeTypes(types, {});
1349 
1350     ASSERT_THAT(storage.fetchTypes(),
1351                 Contains(
1352                     AllOf(IsStorageType(importId2,
1353                                         "QQuickItem",
1354                                         Storage::NativeType{"QObject"},
1355                                         TypeAccessSemantics::Reference,
1356                                         sourceId1),
1357                           Field(&Storage::Type::propertyDeclarations,
1358                                 UnorderedElementsAre(
1359                                     IsPropertyDeclaration("data",
1360                                                           Storage::NativeType{"QObject"},
1361                                                           Storage::PropertyDeclarationTraits::IsList),
1362                                     IsPropertyDeclaration(
1363                                         "objects",
1364                                         Storage::NativeType{"QQuickItem"},
1365                                         Storage::PropertyDeclarationTraits::IsList
1366                                             | Storage::PropertyDeclarationTraits::IsReadOnly))))));
1367 }
1368 
TEST_F(ProjectStorageSlowTest,UsingNonExistingNativePropertyTypeThrows)1369 TEST_F(ProjectStorageSlowTest, UsingNonExistingNativePropertyTypeThrows)
1370 {
1371     Storage::Types types{createTypes()};
1372     types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QObject2"};
1373     types.pop_back();
1374 
1375     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1376                  QmlDesigner::TypeNameDoesNotExists);
1377 }
1378 
TEST_F(ProjectStorageSlowTest,UsingNonExistingExportedPropertyTypeThrows)1379 TEST_F(ProjectStorageSlowTest, UsingNonExistingExportedPropertyTypeThrows)
1380 {
1381     Storage::Types types{createTypes()};
1382     types[0].propertyDeclarations[0].typeName = Storage::ExportedType{"QObject2"};
1383     types.pop_back();
1384 
1385     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1386                  QmlDesigner::TypeNameDoesNotExists);
1387 }
1388 
TEST_F(ProjectStorageSlowTest,UsingNonExistingExplicitExportedPropertyTypeWithWrongNAMEThrows)1389 TEST_F(ProjectStorageSlowTest, UsingNonExistingExplicitExportedPropertyTypeWithWrongNAMEThrows)
1390 {
1391     Storage::Types types{createTypes()};
1392     types[0].propertyDeclarations[0].typeName = Storage::ExplicitExportedType{"QObject2", importId1};
1393     types.pop_back();
1394 
1395     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1396                  QmlDesigner::TypeNameDoesNotExists);
1397 }
1398 
TEST_F(ProjectStorageSlowTest,UsingNonExistingExplicitExportedPropertyTypeWithWrongImportThrows)1399 TEST_F(ProjectStorageSlowTest, UsingNonExistingExplicitExportedPropertyTypeWithWrongImportThrows)
1400 {
1401     Storage::Types types{createTypes()};
1402     types[0].propertyDeclarations[0].typeName = Storage::ExplicitExportedType{"QObject", importId2};
1403     types.pop_back();
1404 
1405     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1406                  QmlDesigner::TypeNameDoesNotExists);
1407 }
1408 
TEST_F(ProjectStorageSlowTest,BreakingPropertyDeclarationTypeDependencyByDeletingTypeThrows)1409 TEST_F(ProjectStorageSlowTest, BreakingPropertyDeclarationTypeDependencyByDeletingTypeThrows)
1410 {
1411     Storage::Types types{createTypes()};
1412     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1413     types[0].prototype = Storage::NativeType{};
1414     types.pop_back();
1415 
1416     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId1, sourceId2}),
1417                  Sqlite::ConstraintPreventsModification);
1418 }
1419 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddFunctionDeclarations)1420 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddFunctionDeclarations)
1421 {
1422     Storage::Types types{createTypes()};
1423 
1424     storage.synchronizeTypes(types, {sourceId1, sourceId2});
1425 
1426     ASSERT_THAT(storage.fetchTypes(),
1427                 Contains(AllOf(IsStorageType(importId2,
1428                                              "QQuickItem",
1429                                              Storage::NativeType{"QObject"},
1430                                              TypeAccessSemantics::Reference,
1431                                              sourceId1),
1432                                Field(&Storage::Type::functionDeclarations,
1433                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1434                                                           Eq(types[0].functionDeclarations[1]))))));
1435 }
1436 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationReturnType)1437 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationReturnType)
1438 {
1439     Storage::Types types{createTypes()};
1440     storage.synchronizeTypes(types, {});
1441     types[0].functionDeclarations[1].returnTypeName = "item";
1442 
1443     storage.synchronizeTypes(types, {});
1444 
1445     ASSERT_THAT(storage.fetchTypes(),
1446                 Contains(AllOf(IsStorageType(importId2,
1447                                              "QQuickItem",
1448                                              Storage::NativeType{"QObject"},
1449                                              TypeAccessSemantics::Reference,
1450                                              sourceId1),
1451                                Field(&Storage::Type::functionDeclarations,
1452                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1453                                                           Eq(types[0].functionDeclarations[1]))))));
1454 }
1455 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationName)1456 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationName)
1457 {
1458     Storage::Types types{createTypes()};
1459     storage.synchronizeTypes(types, {});
1460     types[0].functionDeclarations[1].name = "name";
1461 
1462     storage.synchronizeTypes(types, {});
1463 
1464     ASSERT_THAT(storage.fetchTypes(),
1465                 Contains(AllOf(IsStorageType(importId2,
1466                                              "QQuickItem",
1467                                              Storage::NativeType{"QObject"},
1468                                              TypeAccessSemantics::Reference,
1469                                              sourceId1),
1470                                Field(&Storage::Type::functionDeclarations,
1471                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1472                                                           Eq(types[0].functionDeclarations[1]))))));
1473 }
1474 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationPopParameters)1475 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationPopParameters)
1476 {
1477     Storage::Types types{createTypes()};
1478     storage.synchronizeTypes(types, {});
1479     types[0].functionDeclarations[1].parameters.pop_back();
1480 
1481     storage.synchronizeTypes(types, {});
1482 
1483     ASSERT_THAT(storage.fetchTypes(),
1484                 Contains(AllOf(IsStorageType(importId2,
1485                                              "QQuickItem",
1486                                              Storage::NativeType{"QObject"},
1487                                              TypeAccessSemantics::Reference,
1488                                              sourceId1),
1489                                Field(&Storage::Type::functionDeclarations,
1490                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1491                                                           Eq(types[0].functionDeclarations[1]))))));
1492 }
1493 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationAppendParameters)1494 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationAppendParameters)
1495 {
1496     Storage::Types types{createTypes()};
1497     storage.synchronizeTypes(types, {});
1498     types[0].functionDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"});
1499 
1500     storage.synchronizeTypes(types, {});
1501 
1502     ASSERT_THAT(storage.fetchTypes(),
1503                 Contains(AllOf(IsStorageType(importId2,
1504                                              "QQuickItem",
1505                                              Storage::NativeType{"QObject"},
1506                                              TypeAccessSemantics::Reference,
1507                                              sourceId1),
1508                                Field(&Storage::Type::functionDeclarations,
1509                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1510                                                           Eq(types[0].functionDeclarations[1]))))));
1511 }
1512 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationChangeParameterName)1513 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationChangeParameterName)
1514 {
1515     Storage::Types types{createTypes()};
1516     storage.synchronizeTypes(types, {});
1517     types[0].functionDeclarations[1].parameters[0].name = "other";
1518 
1519     storage.synchronizeTypes(types, {});
1520 
1521     ASSERT_THAT(storage.fetchTypes(),
1522                 Contains(AllOf(IsStorageType(importId2,
1523                                              "QQuickItem",
1524                                              Storage::NativeType{"QObject"},
1525                                              TypeAccessSemantics::Reference,
1526                                              sourceId1),
1527                                Field(&Storage::Type::functionDeclarations,
1528                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1529                                                           Eq(types[0].functionDeclarations[1]))))));
1530 }
1531 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationChangeParameterTypeName)1532 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationChangeParameterTypeName)
1533 {
1534     Storage::Types types{createTypes()};
1535     storage.synchronizeTypes(types, {});
1536     types[0].functionDeclarations[1].parameters[0].name = "long long";
1537 
1538     storage.synchronizeTypes(types, {});
1539 
1540     ASSERT_THAT(storage.fetchTypes(),
1541                 Contains(AllOf(IsStorageType(importId2,
1542                                              "QQuickItem",
1543                                              Storage::NativeType{"QObject"},
1544                                              TypeAccessSemantics::Reference,
1545                                              sourceId1),
1546                                Field(&Storage::Type::functionDeclarations,
1547                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1548                                                           Eq(types[0].functionDeclarations[1]))))));
1549 }
1550 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesFunctionDeclarationChangeParameterTraits)1551 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationChangeParameterTraits)
1552 {
1553     Storage::Types types{createTypes()};
1554     storage.synchronizeTypes(types, {});
1555     types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList;
1556 
1557     storage.synchronizeTypes(types, {});
1558 
1559     ASSERT_THAT(storage.fetchTypes(),
1560                 Contains(AllOf(IsStorageType(importId2,
1561                                              "QQuickItem",
1562                                              Storage::NativeType{"QObject"},
1563                                              TypeAccessSemantics::Reference,
1564                                              sourceId1),
1565                                Field(&Storage::Type::functionDeclarations,
1566                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1567                                                           Eq(types[0].functionDeclarations[1]))))));
1568 }
1569 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovesFunctionDeclaration)1570 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesFunctionDeclaration)
1571 {
1572     Storage::Types types{createTypes()};
1573     storage.synchronizeTypes(types, {});
1574     types[0].functionDeclarations.pop_back();
1575 
1576     storage.synchronizeTypes(types, {});
1577 
1578     ASSERT_THAT(storage.fetchTypes(),
1579                 Contains(AllOf(IsStorageType(importId2,
1580                                              "QQuickItem",
1581                                              Storage::NativeType{"QObject"},
1582                                              TypeAccessSemantics::Reference,
1583                                              sourceId1),
1584                                Field(&Storage::Type::functionDeclarations,
1585                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]))))));
1586 }
1587 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddFunctionDeclaration)1588 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddFunctionDeclaration)
1589 {
1590     Storage::Types types{createTypes()};
1591     storage.synchronizeTypes(types, {});
1592     types[0].functionDeclarations.push_back(
1593         Storage::FunctionDeclaration{"name", "string", {Storage::ParameterDeclaration{"arg", "int"}}});
1594 
1595     storage.synchronizeTypes(types, {});
1596 
1597     ASSERT_THAT(storage.fetchTypes(),
1598                 Contains(AllOf(IsStorageType(importId2,
1599                                              "QQuickItem",
1600                                              Storage::NativeType{"QObject"},
1601                                              TypeAccessSemantics::Reference,
1602                                              sourceId1),
1603                                Field(&Storage::Type::functionDeclarations,
1604                                      UnorderedElementsAre(Eq(types[0].functionDeclarations[0]),
1605                                                           Eq(types[0].functionDeclarations[1]),
1606                                                           Eq(types[0].functionDeclarations[2]))))));
1607 }
1608 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddSignalDeclarations)1609 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddSignalDeclarations)
1610 {
1611     Storage::Types types{createTypes()};
1612 
1613     storage.synchronizeTypes(types, {});
1614 
1615     ASSERT_THAT(storage.fetchTypes(),
1616                 Contains(AllOf(IsStorageType(importId2,
1617                                              "QQuickItem",
1618                                              Storage::NativeType{"QObject"},
1619                                              TypeAccessSemantics::Reference,
1620                                              sourceId1),
1621                                Field(&Storage::Type::signalDeclarations,
1622                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1623                                                           Eq(types[0].signalDeclarations[1]))))));
1624 }
1625 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationName)1626 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationName)
1627 {
1628     Storage::Types types{createTypes()};
1629     storage.synchronizeTypes(types, {});
1630     types[0].signalDeclarations[1].name = "name";
1631 
1632     storage.synchronizeTypes(types, {});
1633 
1634     ASSERT_THAT(storage.fetchTypes(),
1635                 Contains(AllOf(IsStorageType(importId2,
1636                                              "QQuickItem",
1637                                              Storage::NativeType{"QObject"},
1638                                              TypeAccessSemantics::Reference,
1639                                              sourceId1),
1640                                Field(&Storage::Type::signalDeclarations,
1641                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1642                                                           Eq(types[0].signalDeclarations[1]))))));
1643 }
1644 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationPopParameters)1645 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationPopParameters)
1646 {
1647     Storage::Types types{createTypes()};
1648     storage.synchronizeTypes(types, {});
1649     types[0].signalDeclarations[1].parameters.pop_back();
1650 
1651     storage.synchronizeTypes(types, {});
1652 
1653     ASSERT_THAT(storage.fetchTypes(),
1654                 Contains(AllOf(IsStorageType(importId2,
1655                                              "QQuickItem",
1656                                              Storage::NativeType{"QObject"},
1657                                              TypeAccessSemantics::Reference,
1658                                              sourceId1),
1659                                Field(&Storage::Type::signalDeclarations,
1660                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1661                                                           Eq(types[0].signalDeclarations[1]))))));
1662 }
1663 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationAppendParameters)1664 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationAppendParameters)
1665 {
1666     Storage::Types types{createTypes()};
1667     storage.synchronizeTypes(types, {});
1668     types[0].signalDeclarations[1].parameters.push_back(Storage::ParameterDeclaration{"arg4", "int"});
1669 
1670     storage.synchronizeTypes(types, {});
1671 
1672     ASSERT_THAT(storage.fetchTypes(),
1673                 Contains(AllOf(IsStorageType(importId2,
1674                                              "QQuickItem",
1675                                              Storage::NativeType{"QObject"},
1676                                              TypeAccessSemantics::Reference,
1677                                              sourceId1),
1678                                Field(&Storage::Type::signalDeclarations,
1679                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1680                                                           Eq(types[0].signalDeclarations[1]))))));
1681 }
1682 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationChangeParameterName)1683 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationChangeParameterName)
1684 {
1685     Storage::Types types{createTypes()};
1686     storage.synchronizeTypes(types, {});
1687     types[0].signalDeclarations[1].parameters[0].name = "other";
1688 
1689     storage.synchronizeTypes(types, {});
1690 
1691     ASSERT_THAT(storage.fetchTypes(),
1692                 Contains(AllOf(IsStorageType(importId2,
1693                                              "QQuickItem",
1694                                              Storage::NativeType{"QObject"},
1695                                              TypeAccessSemantics::Reference,
1696                                              sourceId1),
1697                                Field(&Storage::Type::signalDeclarations,
1698                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1699                                                           Eq(types[0].signalDeclarations[1]))))));
1700 }
1701 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationChangeParameterTypeName)1702 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationChangeParameterTypeName)
1703 {
1704     Storage::Types types{createTypes()};
1705     storage.synchronizeTypes(types, {});
1706     types[0].signalDeclarations[1].parameters[0].typeName = "long long";
1707 
1708     storage.synchronizeTypes(types, {});
1709 
1710     ASSERT_THAT(storage.fetchTypes(),
1711                 Contains(AllOf(IsStorageType(importId2,
1712                                              "QQuickItem",
1713                                              Storage::NativeType{"QObject"},
1714                                              TypeAccessSemantics::Reference,
1715                                              sourceId1),
1716                                Field(&Storage::Type::signalDeclarations,
1717                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1718                                                           Eq(types[0].signalDeclarations[1]))))));
1719 }
1720 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesSignalDeclarationChangeParameterTraits)1721 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationChangeParameterTraits)
1722 {
1723     Storage::Types types{createTypes()};
1724     storage.synchronizeTypes(types, {});
1725     types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList;
1726 
1727     storage.synchronizeTypes(types, {});
1728 
1729     ASSERT_THAT(storage.fetchTypes(),
1730                 Contains(AllOf(IsStorageType(importId2,
1731                                              "QQuickItem",
1732                                              Storage::NativeType{"QObject"},
1733                                              TypeAccessSemantics::Reference,
1734                                              sourceId1),
1735                                Field(&Storage::Type::signalDeclarations,
1736                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1737                                                           Eq(types[0].signalDeclarations[1]))))));
1738 }
1739 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovesSignalDeclaration)1740 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesSignalDeclaration)
1741 {
1742     Storage::Types types{createTypes()};
1743     storage.synchronizeTypes(types, {});
1744     types[0].signalDeclarations.pop_back();
1745 
1746     storage.synchronizeTypes(types, {});
1747 
1748     ASSERT_THAT(storage.fetchTypes(),
1749                 Contains(AllOf(IsStorageType(importId2,
1750                                              "QQuickItem",
1751                                              Storage::NativeType{"QObject"},
1752                                              TypeAccessSemantics::Reference,
1753                                              sourceId1),
1754                                Field(&Storage::Type::signalDeclarations,
1755                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]))))));
1756 }
1757 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddSignalDeclaration)1758 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddSignalDeclaration)
1759 {
1760     Storage::Types types{createTypes()};
1761     storage.synchronizeTypes(types, {});
1762     types[0].signalDeclarations.push_back(
1763         Storage::SignalDeclaration{"name", {Storage::ParameterDeclaration{"arg", "int"}}});
1764 
1765     storage.synchronizeTypes(types, {});
1766 
1767     ASSERT_THAT(storage.fetchTypes(),
1768                 Contains(AllOf(IsStorageType(importId2,
1769                                              "QQuickItem",
1770                                              Storage::NativeType{"QObject"},
1771                                              TypeAccessSemantics::Reference,
1772                                              sourceId1),
1773                                Field(&Storage::Type::signalDeclarations,
1774                                      UnorderedElementsAre(Eq(types[0].signalDeclarations[0]),
1775                                                           Eq(types[0].signalDeclarations[1]),
1776                                                           Eq(types[0].signalDeclarations[2]))))));
1777 }
1778 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddEnumerationDeclarations)1779 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddEnumerationDeclarations)
1780 {
1781     Storage::Types types{createTypes()};
1782 
1783     storage.synchronizeTypes(types, {});
1784 
1785     ASSERT_THAT(storage.fetchTypes(),
1786                 Contains(AllOf(IsStorageType(importId2,
1787                                              "QQuickItem",
1788                                              Storage::NativeType{"QObject"},
1789                                              TypeAccessSemantics::Reference,
1790                                              sourceId1),
1791                                Field(&Storage::Type::enumerationDeclarations,
1792                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1793                                                           Eq(types[0].enumerationDeclarations[1]))))));
1794 }
1795 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationName)1796 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesEnumerationDeclarationName)
1797 {
1798     Storage::Types types{createTypes()};
1799     storage.synchronizeTypes(types, {});
1800     types[0].enumerationDeclarations[1].name = "Name";
1801 
1802     storage.synchronizeTypes(types, {});
1803 
1804     ASSERT_THAT(storage.fetchTypes(),
1805                 Contains(AllOf(IsStorageType(importId2,
1806                                              "QQuickItem",
1807                                              Storage::NativeType{"QObject"},
1808                                              TypeAccessSemantics::Reference,
1809                                              sourceId1),
1810                                Field(&Storage::Type::enumerationDeclarations,
1811                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1812                                                           Eq(types[0].enumerationDeclarations[1]))))));
1813 }
1814 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationPopEnumeratorDeclaration)1815 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesEnumerationDeclarationPopEnumeratorDeclaration)
1816 {
1817     Storage::Types types{createTypes()};
1818     storage.synchronizeTypes(types, {});
1819     types[0].enumerationDeclarations[1].enumeratorDeclarations.pop_back();
1820 
1821     storage.synchronizeTypes(types, {});
1822 
1823     ASSERT_THAT(storage.fetchTypes(),
1824                 Contains(AllOf(IsStorageType(importId2,
1825                                              "QQuickItem",
1826                                              Storage::NativeType{"QObject"},
1827                                              TypeAccessSemantics::Reference,
1828                                              sourceId1),
1829                                Field(&Storage::Type::enumerationDeclarations,
1830                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1831                                                           Eq(types[0].enumerationDeclarations[1]))))));
1832 }
1833 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationAppendEnumeratorDeclaration)1834 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesEnumerationDeclarationAppendEnumeratorDeclaration)
1835 {
1836     Storage::Types types{createTypes()};
1837     storage.synchronizeTypes(types, {});
1838     types[0].enumerationDeclarations[1].enumeratorDeclarations.push_back(
1839         Storage::EnumeratorDeclaration{"Haa", 54});
1840 
1841     storage.synchronizeTypes(types, {});
1842 
1843     ASSERT_THAT(storage.fetchTypes(),
1844                 Contains(AllOf(IsStorageType(importId2,
1845                                              "QQuickItem",
1846                                              Storage::NativeType{"QObject"},
1847                                              TypeAccessSemantics::Reference,
1848                                              sourceId1),
1849                                Field(&Storage::Type::enumerationDeclarations,
1850                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1851                                                           Eq(types[0].enumerationDeclarations[1]))))));
1852 }
1853 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationName)1854 TEST_F(ProjectStorageSlowTest,
1855        SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationName)
1856 {
1857     Storage::Types types{createTypes()};
1858     storage.synchronizeTypes(types, {});
1859     types[0].enumerationDeclarations[1].enumeratorDeclarations[0].name = "Hoo";
1860 
1861     storage.synchronizeTypes(types, {});
1862 
1863     ASSERT_THAT(storage.fetchTypes(),
1864                 Contains(AllOf(IsStorageType(importId2,
1865                                              "QQuickItem",
1866                                              Storage::NativeType{"QObject"},
1867                                              TypeAccessSemantics::Reference,
1868                                              sourceId1),
1869                                Field(&Storage::Type::enumerationDeclarations,
1870                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1871                                                           Eq(types[0].enumerationDeclarations[1]))))));
1872 }
1873 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationValue)1874 TEST_F(ProjectStorageSlowTest,
1875        SynchronizeTypesChangesEnumerationDeclarationChangeEnumeratorDeclarationValue)
1876 {
1877     Storage::Types types{createTypes()};
1878     storage.synchronizeTypes(types, {});
1879     types[0].enumerationDeclarations[1].enumeratorDeclarations[1].value = 11;
1880 
1881     storage.synchronizeTypes(types, {});
1882 
1883     ASSERT_THAT(storage.fetchTypes(),
1884                 Contains(AllOf(IsStorageType(importId2,
1885                                              "QQuickItem",
1886                                              Storage::NativeType{"QObject"},
1887                                              TypeAccessSemantics::Reference,
1888                                              sourceId1),
1889                                Field(&Storage::Type::enumerationDeclarations,
1890                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1891                                                           Eq(types[0].enumerationDeclarations[1]))))));
1892 }
1893 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationAddThatEnumeratorDeclarationHasValue)1894 TEST_F(ProjectStorageSlowTest,
1895        SynchronizeTypesChangesEnumerationDeclarationAddThatEnumeratorDeclarationHasValue)
1896 {
1897     Storage::Types types{createTypes()};
1898     storage.synchronizeTypes(types, {});
1899     types[0].enumerationDeclarations[1].enumeratorDeclarations[0].value = 11;
1900     types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = true;
1901 
1902     storage.synchronizeTypes(types, {});
1903 
1904     ASSERT_THAT(storage.fetchTypes(),
1905                 Contains(AllOf(IsStorageType(importId2,
1906                                              "QQuickItem",
1907                                              Storage::NativeType{"QObject"},
1908                                              TypeAccessSemantics::Reference,
1909                                              sourceId1),
1910                                Field(&Storage::Type::enumerationDeclarations,
1911                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1912                                                           Eq(types[0].enumerationDeclarations[1]))))));
1913 }
1914 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangesEnumerationDeclarationRemoveThatEnumeratorDeclarationHasValue)1915 TEST_F(ProjectStorageSlowTest,
1916        SynchronizeTypesChangesEnumerationDeclarationRemoveThatEnumeratorDeclarationHasValue)
1917 {
1918     Storage::Types types{createTypes()};
1919     storage.synchronizeTypes(types, {});
1920     types[0].enumerationDeclarations[1].enumeratorDeclarations[0].hasValue = false;
1921 
1922     storage.synchronizeTypes(types, {});
1923 
1924     ASSERT_THAT(storage.fetchTypes(),
1925                 Contains(AllOf(IsStorageType(importId2,
1926                                              "QQuickItem",
1927                                              Storage::NativeType{"QObject"},
1928                                              TypeAccessSemantics::Reference,
1929                                              sourceId1),
1930                                Field(&Storage::Type::enumerationDeclarations,
1931                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1932                                                           Eq(types[0].enumerationDeclarations[1]))))));
1933 }
1934 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovesEnumerationDeclaration)1935 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesEnumerationDeclaration)
1936 {
1937     Storage::Types types{createTypes()};
1938     storage.synchronizeTypes(types, {});
1939     types[0].enumerationDeclarations.pop_back();
1940 
1941     storage.synchronizeTypes(types, {});
1942 
1943     ASSERT_THAT(storage.fetchTypes(),
1944                 Contains(AllOf(IsStorageType(importId2,
1945                                              "QQuickItem",
1946                                              Storage::NativeType{"QObject"},
1947                                              TypeAccessSemantics::Reference,
1948                                              sourceId1),
1949                                Field(&Storage::Type::enumerationDeclarations,
1950                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]))))));
1951 }
1952 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddEnumerationDeclaration)1953 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddEnumerationDeclaration)
1954 {
1955     Storage::Types types{createTypes()};
1956     storage.synchronizeTypes(types, {});
1957     types[0].enumerationDeclarations.push_back(
1958         Storage::EnumerationDeclaration{"name", {Storage::EnumeratorDeclaration{"Foo", 98, true}}});
1959 
1960     storage.synchronizeTypes(types, {});
1961 
1962     ASSERT_THAT(storage.fetchTypes(),
1963                 Contains(AllOf(IsStorageType(importId2,
1964                                              "QQuickItem",
1965                                              Storage::NativeType{"QObject"},
1966                                              TypeAccessSemantics::Reference,
1967                                              sourceId1),
1968                                Field(&Storage::Type::enumerationDeclarations,
1969                                      UnorderedElementsAre(Eq(types[0].enumerationDeclarations[0]),
1970                                                           Eq(types[0].enumerationDeclarations[1]),
1971                                                           Eq(types[0].enumerationDeclarations[2]))))));
1972 }
1973 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddImports)1974 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImports)
1975 {
1976     Storage::Imports imports{createImports()};
1977 
1978     storage.synchronizeImports(imports);
1979 
1980     ASSERT_THAT(storage.fetchAllImports(),
1981                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
1982                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
1983                                      IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
1984 }
1985 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddImportsAgain)1986 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportsAgain)
1987 {
1988     Storage::Imports imports{createImports()};
1989     storage.synchronizeImports(imports);
1990 
1991     storage.synchronizeImports(imports);
1992 
1993     ASSERT_THAT(storage.fetchAllImports(),
1994                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
1995                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
1996                                      IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
1997 }
1998 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddMoreImports)1999 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImports)
2000 {
2001     Storage::Imports imports{createImports()};
2002     storage.synchronizeImports(imports);
2003     imports.push_back(Storage::Import{"QtQuick.Foo", Storage::VersionNumber{1}, importSourceId3});
2004 
2005     storage.synchronizeImports(imports);
2006 
2007     ASSERT_THAT(storage.fetchAllImports(),
2008                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2009                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2010                                      IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2011                                      IsImport("QtQuick.Foo", Storage::VersionNumber{1}, importSourceId3)));
2012 }
2013 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddSameImportNameButDifferentVersion)2014 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddSameImportNameButDifferentVersion)
2015 {
2016     Storage::Imports imports{createImports()};
2017     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{4}, importSourceId3});
2018     storage.synchronizeImports(imports);
2019     imports.pop_back();
2020     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId3});
2021 
2022     storage.synchronizeImports(imports);
2023 
2024     ASSERT_THAT(storage.fetchAllImports(),
2025                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2026                                      IsImport("Qml", Storage::VersionNumber{3}, importSourceId3),
2027                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2028                                      IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
2029 }
2030 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsRemoveImport)2031 TEST_F(ProjectStorageSlowTest, SynchronizeImportsRemoveImport)
2032 {
2033     Storage::Imports imports{createImports()};
2034     storage.synchronizeImports(imports);
2035     imports.pop_back();
2036 
2037     storage.synchronizeImports(imports);
2038 
2039     ASSERT_THAT(storage.fetchAllImports(),
2040                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2041                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2)));
2042 }
2043 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsUpdateImport)2044 TEST_F(ProjectStorageSlowTest, SynchronizeImportsUpdateImport)
2045 {
2046     Storage::Imports imports{createImports()};
2047     storage.synchronizeImports(imports);
2048     imports[1].sourceId = importSourceId3;
2049 
2050     storage.synchronizeImports(imports);
2051 
2052     ASSERT_THAT(storage.fetchAllImports(),
2053                 UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2054                                      IsImport("QtQuick", Storage::VersionNumber{}, importSourceId3),
2055                                      IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
2056 }
2057 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddImportDependecies)2058 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportDependecies)
2059 {
2060     Storage::Imports imports{createImports()};
2061 
2062     storage.synchronizeImports(imports);
2063 
2064     ASSERT_THAT(storage.fetchAllImports(),
2065                 UnorderedElementsAre(
2066                     AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2067                           Field(&Storage::Import::importDependencies, IsEmpty())),
2068                     AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2069                           Field(&Storage::Import::importDependencies,
2070                                 ElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
2071                     AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2072                           Field(&Storage::Import::importDependencies,
2073                                 UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2074                                                      IsBasicImport("QtQuick",
2075                                                                    Storage::VersionNumber{}))))));
2076 }
2077 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddImportDependeciesWhichDoesNotExitsThrows)2078 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportDependeciesWhichDoesNotExitsThrows)
2079 {
2080     Storage::Imports imports{createImports()};
2081     imports[1].importDependencies.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}});
2082 
2083     ASSERT_THROW(storage.synchronizeImports(imports), QmlDesigner::ImportDoesNotExists);
2084 }
2085 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsRemovesDependeciesForRemovedImports)2086 TEST_F(ProjectStorageSlowTest, SynchronizeImportsRemovesDependeciesForRemovedImports)
2087 {
2088     Storage::Imports imports{createImports()};
2089     storage.synchronizeImports(imports);
2090     auto last = imports.back();
2091     imports.pop_back();
2092 
2093     storage.synchronizeImports(imports);
2094 
2095     last.importDependencies.pop_back();
2096     imports.push_back(last);
2097     storage.synchronizeImports(imports);
2098     ASSERT_THAT(storage.fetchAllImports(),
2099                 UnorderedElementsAre(
2100                     AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2101                           Field(&Storage::Import::importDependencies, IsEmpty())),
2102                     AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2103                           Field(&Storage::Import::importDependencies,
2104                                 ElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
2105                     AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2106                           Field(&Storage::Import::importDependencies,
2107                                 UnorderedElementsAre(
2108                                     IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2109 }
2110 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddMoreImportDependecies)2111 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImportDependecies)
2112 {
2113     Storage::Imports imports{createImports()};
2114     storage.synchronizeImports(imports);
2115     imports.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}, importSourceId1, {}});
2116     imports[1].importDependencies.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}});
2117 
2118     storage.synchronizeImports(imports);
2119 
2120     ASSERT_THAT(
2121         storage.fetchAllImports(),
2122         UnorderedElementsAre(
2123             AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2124                   Field(&Storage::Import::importDependencies, IsEmpty())),
2125             AllOf(IsImport("QmlBase", Storage::VersionNumber{2}, importSourceId1),
2126                   Field(&Storage::Import::importDependencies, IsEmpty())),
2127             AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2128                   Field(&Storage::Import::importDependencies,
2129                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2130                                              IsBasicImport("QmlBase", Storage::VersionNumber{2})))),
2131             AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2132                   Field(&Storage::Import::importDependencies,
2133                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2134                                              IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2135 }
2136 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsAddMoreImportDependeciesWithDifferentVersionNumber)2137 TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImportDependeciesWithDifferentVersionNumber)
2138 {
2139     Storage::Imports imports{createImports()};
2140     storage.synchronizeImports(imports);
2141     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
2142     imports[1].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
2143 
2144     storage.synchronizeImports(imports);
2145 
2146     ASSERT_THAT(
2147         storage.fetchAllImports(),
2148         UnorderedElementsAre(
2149             AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2150                   Field(&Storage::Import::importDependencies, IsEmpty())),
2151             AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
2152                   Field(&Storage::Import::importDependencies, IsEmpty())),
2153             AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2154                   Field(&Storage::Import::importDependencies,
2155                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2156                                              IsBasicImport("Qml", Storage::VersionNumber{3})))),
2157             AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2158                   Field(&Storage::Import::importDependencies,
2159                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2160                                              IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2161 }
2162 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsDependencyGetsHighestVersionIfNoVersionIsSupplied)2163 TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyGetsHighestVersionIfNoVersionIsSupplied)
2164 {
2165     Storage::Imports imports{createImports()};
2166     storage.synchronizeImports(imports);
2167     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
2168     imports[1].importDependencies.push_back(Storage::Import{"Qml"});
2169 
2170     storage.synchronizeImports(imports);
2171 
2172     ASSERT_THAT(
2173         storage.fetchAllImports(),
2174         UnorderedElementsAre(
2175             AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2176                   Field(&Storage::Import::importDependencies, IsEmpty())),
2177             AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
2178                   Field(&Storage::Import::importDependencies, IsEmpty())),
2179             AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2180                   Field(&Storage::Import::importDependencies,
2181                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2182                                              IsBasicImport("Qml", Storage::VersionNumber{3})))),
2183             AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2184                   Field(&Storage::Import::importDependencies,
2185                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2186                                              IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2187 }
2188 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsDependencyGetsOnlyTheHighestDependency)2189 TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyGetsOnlyTheHighestDependency)
2190 {
2191     Storage::Imports imports{createImports()};
2192     storage.synchronizeImports(imports);
2193     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{1}, importSourceId1, {}});
2194     imports[1].importDependencies.push_back(Storage::Import{"Qml"});
2195 
2196     storage.synchronizeImports(imports);
2197 
2198     ASSERT_THAT(
2199         storage.fetchAllImports(),
2200         UnorderedElementsAre(
2201             AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2202                   Field(&Storage::Import::importDependencies, IsEmpty())),
2203             AllOf(IsImport("Qml", Storage::VersionNumber{1}, importSourceId1),
2204                   Field(&Storage::Import::importDependencies, IsEmpty())),
2205             AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2206                   Field(&Storage::Import::importDependencies,
2207                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
2208             AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2209                   Field(&Storage::Import::importDependencies,
2210                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2211                                              IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2212 }
2213 
TEST_F(ProjectStorageSlowTest,SynchronizeImportsDependencyRemoveDuplicateDependencies)2214 TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyRemoveDuplicateDependencies)
2215 {
2216     Storage::Imports imports{createImports()};
2217     storage.synchronizeImports(imports);
2218     imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
2219     imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
2220     imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{2}});
2221     imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
2222     imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{2}});
2223 
2224     storage.synchronizeImports(imports);
2225 
2226     ASSERT_THAT(
2227         storage.fetchAllImports(),
2228         UnorderedElementsAre(
2229             AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
2230                   Field(&Storage::Import::importDependencies, IsEmpty())),
2231             AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
2232                   Field(&Storage::Import::importDependencies, IsEmpty())),
2233             AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
2234                   Field(&Storage::Import::importDependencies,
2235                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
2236             AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
2237                   Field(&Storage::Import::importDependencies,
2238                         UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
2239                                              IsBasicImport("Qml", Storage::VersionNumber{3}),
2240                                              IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
2241 }
2242 
TEST_F(ProjectStorageSlowTest,RemovingImportRemovesDependentTypesToo)2243 TEST_F(ProjectStorageSlowTest, RemovingImportRemovesDependentTypesToo)
2244 {
2245     Storage::Types types{createTypes()};
2246     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2247     Storage::Imports imports{createImports()};
2248     imports.pop_back();
2249     imports.pop_back();
2250     storage.synchronizeImports(imports);
2251 
2252     ASSERT_THAT(storage.fetchTypes(),
2253                 UnorderedElementsAre(AllOf(IsStorageType(importId1,
2254                                                          "QObject",
2255                                                          Storage::NativeType{},
2256                                                          TypeAccessSemantics::Reference,
2257                                                          sourceId2),
2258                                            Field(&Storage::Type::exportedTypes,
2259                                                  UnorderedElementsAre(IsExportedType("Object"),
2260                                                                       IsExportedType("Obj"))))));
2261 }
2262 
TEST_F(ProjectStorageSlowTest,FetchTypeIdByImportIdAndName)2263 TEST_F(ProjectStorageSlowTest, FetchTypeIdByImportIdAndName)
2264 {
2265     Storage::Types types{createTypes()};
2266     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2267 
2268     auto typeId = storage.fetchTypeIdByName(importId1, "QObject");
2269 
2270     ASSERT_THAT(storage.fetchTypeIdByExportedName("Object"), Eq(typeId));
2271 }
2272 
TEST_F(ProjectStorageSlowTest,FetchTypeIdByExportedName)2273 TEST_F(ProjectStorageSlowTest, FetchTypeIdByExportedName)
2274 {
2275     Storage::Types types{createTypes()};
2276     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2277 
2278     auto typeId = storage.fetchTypeIdByExportedName("Object");
2279 
2280     ASSERT_THAT(storage.fetchTypeIdByName(importId1, "QObject"), Eq(typeId));
2281 }
2282 
TEST_F(ProjectStorageSlowTest,FetchTypeIdByImporIdsAndExportedName)2283 TEST_F(ProjectStorageSlowTest, FetchTypeIdByImporIdsAndExportedName)
2284 {
2285     Storage::Types types{createTypes()};
2286     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2287 
2288     auto typeId = storage.fetchTypeIdByImportIdsAndExportedName({importId1, importId2}, "Object");
2289 
2290     ASSERT_THAT(storage.fetchTypeIdByName(importId1, "QObject"), Eq(typeId));
2291 }
2292 
TEST_F(ProjectStorageSlowTest,FetchInvalidTypeIdByImporIdsAndExportedNameIfImportIdsAreEmpty)2293 TEST_F(ProjectStorageSlowTest, FetchInvalidTypeIdByImporIdsAndExportedNameIfImportIdsAreEmpty)
2294 {
2295     Storage::Types types{createTypes()};
2296     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2297 
2298     auto typeId = storage.fetchTypeIdByImportIdsAndExportedName({}, "Object");
2299 
2300     ASSERT_FALSE(typeId.isValid());
2301 }
2302 
TEST_F(ProjectStorageSlowTest,FetchInvalidTypeIdByImporIdsAndExportedNameIfImportIdsAreInvalid)2303 TEST_F(ProjectStorageSlowTest, FetchInvalidTypeIdByImporIdsAndExportedNameIfImportIdsAreInvalid)
2304 {
2305     Storage::Types types{createTypes()};
2306     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2307 
2308     auto typeId = storage.fetchTypeIdByImportIdsAndExportedName({ImportId{}}, "Object");
2309 
2310     ASSERT_FALSE(typeId.isValid());
2311 }
2312 
TEST_F(ProjectStorageSlowTest,FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInImport)2313 TEST_F(ProjectStorageSlowTest, FetchInvalidTypeIdByImporIdsAndExportedNameIfNotInImport)
2314 {
2315     Storage::Types types{createTypes()};
2316     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2317 
2318     auto typeId = storage.fetchTypeIdByImportIdsAndExportedName({importId2, importId3}, "Object");
2319 
2320     ASSERT_FALSE(typeId.isValid());
2321 }
2322 
TEST_F(ProjectStorageSlowTest,FetchImportDepencencyIds)2323 TEST_F(ProjectStorageSlowTest, FetchImportDepencencyIds)
2324 {
2325     Storage::Types types{createTypes()};
2326     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2327 
2328     auto importIds = storage.fetchImportDependencyIds({importId3});
2329 
2330     ASSERT_THAT(importIds, UnorderedElementsAre(importId1, importId2, importId3));
2331 }
2332 
TEST_F(ProjectStorageSlowTest,FetchImportDepencencyIdsForRootDepencency)2333 TEST_F(ProjectStorageSlowTest, FetchImportDepencencyIdsForRootDepencency)
2334 {
2335     Storage::Types types{createTypes()};
2336     storage.synchronizeTypes(types, {sourceId1, sourceId2});
2337 
2338     auto importIds = storage.fetchImportDependencyIds({importId1});
2339 
2340     ASSERT_THAT(importIds, ElementsAre(importId1));
2341 }
2342 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddAliasDeclarations)2343 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarations)
2344 {
2345     Storage::Types types{createTypesWithAliases()};
2346 
2347     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2348 
2349     ASSERT_THAT(storage.fetchTypes(),
2350                 Contains(AllOf(
2351                     IsStorageType(importId2,
2352                                   "QAliasItem",
2353                                   Storage::NativeType{"QQuickItem"},
2354                                   TypeAccessSemantics::Reference,
2355                                   sourceId3),
2356                     Field(&Storage::Type::propertyDeclarations,
2357                           UnorderedElementsAre(
2358                               IsPropertyDeclaration("items",
2359                                                     Storage::NativeType{"QQuickItem"},
2360                                                     Storage::PropertyDeclarationTraits::IsList
2361                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2362                               IsPropertyDeclaration("objects",
2363                                                     Storage::NativeType{"QObject"},
2364                                                     Storage::PropertyDeclarationTraits::IsList),
2365                               IsPropertyDeclaration("data",
2366                                                     Storage::NativeType{"QObject"},
2367                                                     Storage::PropertyDeclarationTraits::IsList))))));
2368 }
2369 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddAliasDeclarationsAgain)2370 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsAgain)
2371 {
2372     Storage::Types types{createTypesWithAliases()};
2373     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2374 
2375     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2376 
2377     ASSERT_THAT(storage.fetchTypes(),
2378                 Contains(AllOf(
2379                     IsStorageType(importId2,
2380                                   "QAliasItem",
2381                                   Storage::NativeType{"QQuickItem"},
2382                                   TypeAccessSemantics::Reference,
2383                                   sourceId3),
2384                     Field(&Storage::Type::propertyDeclarations,
2385                           UnorderedElementsAre(
2386                               IsPropertyDeclaration("items",
2387                                                     Storage::NativeType{"QQuickItem"},
2388                                                     Storage::PropertyDeclarationTraits::IsList
2389                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2390                               IsPropertyDeclaration("objects",
2391                                                     Storage::NativeType{"QObject"},
2392                                                     Storage::PropertyDeclarationTraits::IsList),
2393                               IsPropertyDeclaration("data",
2394                                                     Storage::NativeType{"QObject"},
2395                                                     Storage::PropertyDeclarationTraits::IsList))))));
2396 }
2397 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemoveAliasDeclarations)2398 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveAliasDeclarations)
2399 {
2400     Storage::Types types{createTypesWithAliases()};
2401     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2402     types[2].aliasDeclarations.pop_back();
2403 
2404     storage.synchronizeTypes({types[2]}, {sourceId3});
2405 
2406     ASSERT_THAT(storage.fetchTypes(),
2407                 Contains(AllOf(
2408                     IsStorageType(importId2,
2409                                   "QAliasItem",
2410                                   Storage::NativeType{"QQuickItem"},
2411                                   TypeAccessSemantics::Reference,
2412                                   sourceId3),
2413                     Field(&Storage::Type::propertyDeclarations,
2414                           UnorderedElementsAre(
2415                               IsPropertyDeclaration("items",
2416                                                     Storage::NativeType{"QQuickItem"},
2417                                                     Storage::PropertyDeclarationTraits::IsList
2418                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2419                               IsPropertyDeclaration("data",
2420                                                     Storage::NativeType{"QObject"},
2421                                                     Storage::PropertyDeclarationTraits::IsList))))));
2422 }
2423 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddAliasDeclarationsThrowsForWrongTypeName)2424 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWrongTypeName)
2425 {
2426     Storage::Types types{createTypesWithAliases()};
2427     types[2].aliasDeclarations[0].aliasTypeName = Storage::NativeType{"QQuickItemWrong"};
2428 
2429     ASSERT_THROW(storage.synchronizeTypes({types[2]}, {sourceId4}),
2430                  QmlDesigner::TypeNameDoesNotExists);
2431 }
TEST_F(ProjectStorageSlowTest,SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName)2432 TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName)
2433 {
2434     Storage::Types types{createTypesWithAliases()};
2435     types[2].aliasDeclarations[0].aliasPropertyName = "childrenWrong";
2436 
2437     ASSERT_THROW(storage.synchronizeTypes(types, {sourceId4}), QmlDesigner::PropertyNameDoesNotExists);
2438 }
2439 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangeAliasDeclarationsTypeName)2440 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName)
2441 {
2442     Storage::Types types{createTypesWithAliases()};
2443     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2444     types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Obj2"};
2445 
2446     storage.synchronizeTypes({types[2]}, {sourceId3});
2447 
2448     ASSERT_THAT(storage.fetchTypes(),
2449                 Contains(AllOf(
2450                     IsStorageType(importId2,
2451                                   "QAliasItem",
2452                                   Storage::NativeType{"QQuickItem"},
2453                                   TypeAccessSemantics::Reference,
2454                                   sourceId3),
2455                     Field(&Storage::Type::propertyDeclarations,
2456                           UnorderedElementsAre(
2457                               IsPropertyDeclaration("items",
2458                                                     Storage::NativeType{"QQuickItem"},
2459                                                     Storage::PropertyDeclarationTraits::IsList
2460                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2461                               IsPropertyDeclaration("objects",
2462                                                     Storage::NativeType{"QObject"},
2463                                                     Storage::PropertyDeclarationTraits::IsList),
2464                               IsPropertyDeclaration("data",
2465                                                     Storage::NativeType{"QObject"},
2466                                                     Storage::PropertyDeclarationTraits::IsList))))));
2467 }
2468 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangeAliasDeclarationsPropertyName)2469 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsPropertyName)
2470 {
2471     Storage::Types types{createTypesWithAliases()};
2472     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2473     types[2].aliasDeclarations[1].aliasPropertyName = "children";
2474 
2475     storage.synchronizeTypes({types[2]}, {sourceId3});
2476 
2477     ASSERT_THAT(
2478         storage.fetchTypes(),
2479         Contains(
2480             AllOf(IsStorageType(importId2,
2481                                 "QAliasItem",
2482                                 Storage::NativeType{"QQuickItem"},
2483                                 TypeAccessSemantics::Reference,
2484                                 sourceId3),
2485                   Field(&Storage::Type::propertyDeclarations,
2486                         UnorderedElementsAre(
2487                             IsPropertyDeclaration("items",
2488                                                   Storage::NativeType{"QQuickItem"},
2489                                                   Storage::PropertyDeclarationTraits::IsList
2490                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2491                             IsPropertyDeclaration("objects",
2492                                                   Storage::NativeType{"QQuickItem"},
2493                                                   Storage::PropertyDeclarationTraits::IsList
2494                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2495                             IsPropertyDeclaration("data",
2496                                                   Storage::NativeType{"QObject"},
2497                                                   Storage::PropertyDeclarationTraits::IsList))))));
2498 }
2499 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration)2500 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration)
2501 {
2502     Storage::Types types{createTypesWithAliases()};
2503     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2504     types[2].aliasDeclarations.pop_back();
2505     types[2].propertyDeclarations.push_back(
2506         Storage::PropertyDeclaration{"objects",
2507                                      Storage::NativeType{"QQuickItem"},
2508                                      Storage::PropertyDeclarationTraits::IsList
2509                                          | Storage::PropertyDeclarationTraits::IsReadOnly});
2510 
2511     storage.synchronizeTypes({types[2]}, {sourceId3});
2512 
2513     ASSERT_THAT(
2514         storage.fetchTypes(),
2515         Contains(
2516             AllOf(IsStorageType(importId2,
2517                                 "QAliasItem",
2518                                 Storage::NativeType{"QQuickItem"},
2519                                 TypeAccessSemantics::Reference,
2520                                 sourceId3),
2521                   Field(&Storage::Type::propertyDeclarations,
2522                         UnorderedElementsAre(
2523                             IsPropertyDeclaration("items",
2524                                                   Storage::NativeType{"QQuickItem"},
2525                                                   Storage::PropertyDeclarationTraits::IsList
2526                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2527                             IsPropertyDeclaration("objects",
2528                                                   Storage::NativeType{"QQuickItem"},
2529                                                   Storage::PropertyDeclarationTraits::IsList
2530                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2531                             IsPropertyDeclaration("data",
2532                                                   Storage::NativeType{"QObject"},
2533                                                   Storage::PropertyDeclarationTraits::IsList))))));
2534 }
2535 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangePropertyDeclarationsToAliasDeclaration)2536 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangePropertyDeclarationsToAliasDeclaration)
2537 {
2538     Storage::Types types{createTypesWithAliases()};
2539     auto typesChanged = types;
2540     typesChanged[2].aliasDeclarations.pop_back();
2541     typesChanged[2].propertyDeclarations.push_back(
2542         Storage::PropertyDeclaration{"objects",
2543                                      Storage::NativeType{"QQuickItem"},
2544                                      Storage::PropertyDeclarationTraits::IsList
2545                                          | Storage::PropertyDeclarationTraits::IsReadOnly});
2546     storage.synchronizeTypes(typesChanged, {sourceId1, sourceId2, sourceId3, sourceId4});
2547 
2548     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2549 
2550     ASSERT_THAT(storage.fetchTypes(),
2551                 Contains(AllOf(
2552                     IsStorageType(importId2,
2553                                   "QAliasItem",
2554                                   Storage::NativeType{"QQuickItem"},
2555                                   TypeAccessSemantics::Reference,
2556                                   sourceId3),
2557                     Field(&Storage::Type::propertyDeclarations,
2558                           UnorderedElementsAre(
2559                               IsPropertyDeclaration("items",
2560                                                     Storage::NativeType{"QQuickItem"},
2561                                                     Storage::PropertyDeclarationTraits::IsList
2562                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2563                               IsPropertyDeclaration("objects",
2564                                                     Storage::NativeType{"QObject"},
2565                                                     Storage::PropertyDeclarationTraits::IsList),
2566                               IsPropertyDeclaration("data",
2567                                                     Storage::NativeType{"QObject"},
2568                                                     Storage::PropertyDeclarationTraits::IsList))))));
2569 }
2570 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangeAliasTargetPropertyDeclarationTraits)2571 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasTargetPropertyDeclarationTraits)
2572 {
2573     Storage::Types types{createTypesWithAliases()};
2574     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2575     types[1].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList
2576                                               | Storage::PropertyDeclarationTraits::IsReadOnly;
2577 
2578     storage.synchronizeTypes({types[1]}, {sourceId2});
2579 
2580     ASSERT_THAT(
2581         storage.fetchTypes(),
2582         Contains(
2583             AllOf(IsStorageType(importId2,
2584                                 "QAliasItem",
2585                                 Storage::NativeType{"QQuickItem"},
2586                                 TypeAccessSemantics::Reference,
2587                                 sourceId3),
2588                   Field(&Storage::Type::propertyDeclarations,
2589                         UnorderedElementsAre(
2590                             IsPropertyDeclaration("items",
2591                                                   Storage::NativeType{"QQuickItem"},
2592                                                   Storage::PropertyDeclarationTraits::IsList
2593                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2594                             IsPropertyDeclaration("objects",
2595                                                   Storage::NativeType{"QObject"},
2596                                                   Storage::PropertyDeclarationTraits::IsList
2597                                                       | Storage::PropertyDeclarationTraits::IsReadOnly),
2598                             IsPropertyDeclaration("data",
2599                                                   Storage::NativeType{"QObject"},
2600                                                   Storage::PropertyDeclarationTraits::IsList))))));
2601 }
2602 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeName)2603 TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeName)
2604 {
2605     Storage::Types types{createTypesWithAliases()};
2606     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2607     types[1].propertyDeclarations[0].typeName = Storage::ExportedType{"Item"};
2608 
2609     storage.synchronizeTypes({types[1]}, {sourceId2});
2610 
2611     ASSERT_THAT(storage.fetchTypes(),
2612                 Contains(AllOf(
2613                     IsStorageType(importId2,
2614                                   "QAliasItem",
2615                                   Storage::NativeType{"QQuickItem"},
2616                                   TypeAccessSemantics::Reference,
2617                                   sourceId3),
2618                     Field(&Storage::Type::propertyDeclarations,
2619                           UnorderedElementsAre(
2620                               IsPropertyDeclaration("items",
2621                                                     Storage::NativeType{"QQuickItem"},
2622                                                     Storage::PropertyDeclarationTraits::IsList
2623                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2624                               IsPropertyDeclaration("objects",
2625                                                     Storage::NativeType{"QQuickItem"},
2626                                                     Storage::PropertyDeclarationTraits::IsList),
2627                               IsPropertyDeclaration("data",
2628                                                     Storage::NativeType{"QObject"},
2629                                                     Storage::PropertyDeclarationTraits::IsList))))));
2630 }
2631 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrows)2632 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovePropertyDeclarationWithAnAliasThrows)
2633 {
2634     Storage::Types types{createTypesWithAliases()};
2635     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2636     types[1].propertyDeclarations.pop_back();
2637 
2638     ASSERT_THROW(storage.synchronizeTypes({types[1]}, {sourceId2}),
2639                  Sqlite::ConstraintPreventsModification);
2640 }
2641 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemovePropertyDeclarationAndAlias)2642 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovePropertyDeclarationAndAlias)
2643 {
2644     Storage::Types types{createTypesWithAliases()};
2645     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2646     types[1].propertyDeclarations.pop_back();
2647     types[2].aliasDeclarations.pop_back();
2648 
2649     storage.synchronizeTypes({types[1], types[2]}, {sourceId2, sourceId3});
2650 
2651     ASSERT_THAT(storage.fetchTypes(),
2652                 Contains(AllOf(
2653                     IsStorageType(importId2,
2654                                   "QAliasItem",
2655                                   Storage::NativeType{"QQuickItem"},
2656                                   TypeAccessSemantics::Reference,
2657                                   sourceId3),
2658                     Field(&Storage::Type::propertyDeclarations,
2659                           UnorderedElementsAre(
2660                               IsPropertyDeclaration("items",
2661                                                     Storage::NativeType{"QQuickItem"},
2662                                                     Storage::PropertyDeclarationTraits::IsList
2663                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2664                               IsPropertyDeclaration("data",
2665                                                     Storage::NativeType{"QObject"},
2666                                                     Storage::PropertyDeclarationTraits::IsList))))));
2667 }
2668 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarationThrows)2669 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarationThrows)
2670 {
2671     Storage::Types types{createTypesWithAliases()};
2672     types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Object2"};
2673     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2674 
2675     ASSERT_THROW(storage.synchronizeTypes({}, {sourceId4}), Sqlite::ConstraintPreventsModification);
2676 }
2677 
TEST_F(ProjectStorageSlowTest,SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration)2678 TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration)
2679 {
2680     Storage::Types types{createTypesWithAliases()};
2681     types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Object2"};
2682     storage.synchronizeTypes(types, {sourceId1, sourceId2, sourceId3, sourceId4});
2683     types[2].aliasDeclarations.pop_back();
2684 
2685     storage.synchronizeTypes({types[0], types[2]}, {sourceId1, sourceId3});
2686 
2687     ASSERT_THAT(storage.fetchTypes(),
2688                 Contains(AllOf(
2689                     IsStorageType(importId2,
2690                                   "QAliasItem",
2691                                   Storage::NativeType{"QQuickItem"},
2692                                   TypeAccessSemantics::Reference,
2693                                   sourceId3),
2694                     Field(&Storage::Type::propertyDeclarations,
2695                           UnorderedElementsAre(
2696                               IsPropertyDeclaration("items",
2697                                                     Storage::NativeType{"QQuickItem"},
2698                                                     Storage::PropertyDeclarationTraits::IsList
2699                                                         | Storage::PropertyDeclarationTraits::IsReadOnly),
2700                               IsPropertyDeclaration("data",
2701                                                     Storage::NativeType{"QObject"},
2702                                                     Storage::PropertyDeclarationTraits::IsList))))));
2703 }
2704 
2705 } // namespace
2706