1 /*
2 SPDX-FileCopyrightText: 2019 Andreas Cord-Landwehr <cordlandwehr@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6
7 #include "test_skeletonresource.h"
8 #include "../mocks/languagestub.h"
9 #include "core/language.h"
10 #include "core/phrase.h"
11 #include "core/resources/skeletonresource.h"
12 #include "core/unit.h"
13 #include "resourcerepositorystub.h"
14
15 #include <QDebug>
16 #include <QFile>
17 #include <QIODevice>
18 #include <QSignalSpy>
19 #include <QTemporaryFile>
20 #include <QTest>
21 #include <QXmlSchema>
22 #include <QXmlSchemaValidator>
23
TestSkeletonResource()24 TestSkeletonResource::TestSkeletonResource()
25 {
26 }
27
init()28 void TestSkeletonResource::init()
29 {
30 }
31
cleanup()32 void TestSkeletonResource::cleanup()
33 {
34 }
35
loadSkeletonResource()36 void TestSkeletonResource::loadSkeletonResource()
37 {
38 std::shared_ptr<ILanguage> language(new LanguageStub("de"));
39 ResourceRepositoryStub repository({language});
40 const QString courseDirectory = "data/contributorrepository/skeletons/";
41 const QString courseFile = courseDirectory + "skeleton.xml";
42
43 auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository);
44 QCOMPARE(skeleton->file().toLocalFile(), courseFile);
45 QCOMPARE(skeleton->id(), "skeleton-testdata");
46 QCOMPARE(skeleton->foreignId(), "skeleton-testdata"); // always same as ID
47 QCOMPARE(skeleton->title(), "Artikulate Test Course Title");
48 QCOMPARE(skeleton->description(), "Artikulate Test Course Description");
49 QVERIFY(skeleton->language() == nullptr); // a skeleton must not have a language
50
51 QCOMPARE(skeleton->units().count(), 2);
52
53 const auto unit = skeleton->units().first();
54 QVERIFY(unit != nullptr);
55 QCOMPARE(unit->id(), "{11111111-b885-4833-97ff-27cb1ca2f543}");
56 QCOMPARE(unit->title(), QStringLiteral("Numbers"));
57 QCOMPARE(unit->phrases().count(), 2);
58 QVERIFY(unit->course() != nullptr);
59 QCOMPARE(unit->course().get(), skeleton.get());
60
61 // note: this test takes the silent assumption that phrases are added to the list in same
62 // order as they are defined in the file. This assumption should be made explicit or dropped
63 const auto firstPhrase = unit->phrases().first();
64 QVERIFY(firstPhrase != nullptr);
65 QCOMPARE(firstPhrase->id(), "{22222222-9234-4da5-a6fe-dbd5104f57d5}");
66 QCOMPARE(firstPhrase->text(), "0");
67 QCOMPARE(firstPhrase->type(), Phrase::Type::Word);
68 const auto secondPhrase = unit->phrases().at(1);
69 QVERIFY(secondPhrase != nullptr);
70 QCOMPARE(secondPhrase->id(), "{333333333-b4a9-4264-9a26-75a55aa5d302}");
71 QCOMPARE(secondPhrase->text(), "1");
72 QCOMPARE(secondPhrase->type(), Phrase::Type::Word);
73 }
74
unitAddAndRemoveHandling()75 void TestSkeletonResource::unitAddAndRemoveHandling()
76 {
77 // boilerplate
78 std::shared_ptr<ILanguage> language(new LanguageStub("de"));
79 ResourceRepositoryStub repository({language});
80 const QString courseDirectory = "data/contributorrepository/skeletons/";
81 const QString courseFile = courseDirectory + "skeleton.xml";
82 auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository);
83
84 // begin of test
85 auto unit = Unit::create();
86 unit->setId("testunit");
87 const int initialUnitNumber = skeleton->units().count();
88 QCOMPARE(initialUnitNumber, 2);
89 QSignalSpy spyAboutToBeAdded(skeleton.get(), SIGNAL(unitAboutToBeAdded(std::shared_ptr<Unit>, int)));
90 QSignalSpy spyAdded(skeleton.get(), SIGNAL(unitAdded()));
91 QCOMPARE(spyAboutToBeAdded.count(), 0);
92 QCOMPARE(spyAdded.count(), 0);
93 auto sharedUnit = skeleton->addUnit(std::move(unit));
94 QCOMPARE(skeleton->units().count(), initialUnitNumber + 1);
95 QCOMPARE(spyAboutToBeAdded.count(), 1);
96 QCOMPARE(spyAdded.count(), 1);
97 QCOMPARE(sharedUnit->course(), skeleton);
98 }
99
coursePropertyChanges()100 void TestSkeletonResource::coursePropertyChanges()
101 {
102 // boilerplate
103 std::shared_ptr<ILanguage> language(new LanguageStub("de"));
104 ResourceRepositoryStub repository({language});
105 const QString courseDirectory = "data/contributorrepository/skeletons/";
106 const QString courseFile = courseDirectory + "skeleton.xml";
107 auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository);
108
109 // id
110 {
111 const QString value = "newId";
112 QSignalSpy spy(skeleton.get(), SIGNAL(idChanged()));
113 QCOMPARE(spy.count(), 0);
114 skeleton->setId(value);
115 QCOMPARE(skeleton->id(), value);
116 QCOMPARE(spy.count(), 1);
117 }
118
119 // title
120 {
121 const QString value = "newTitle";
122 QSignalSpy spy(skeleton.get(), SIGNAL(titleChanged()));
123 QCOMPARE(spy.count(), 0);
124 skeleton->setTitle(value);
125 QCOMPARE(skeleton->title(), value);
126 QCOMPARE(spy.count(), 1);
127 }
128
129 // description
130 {
131 const QString value = "newDescription";
132 QSignalSpy spy(skeleton.get(), SIGNAL(descriptionChanged()));
133 QCOMPARE(spy.count(), 0);
134 skeleton->setDescription(value);
135 QCOMPARE(skeleton->description(), value);
136 QCOMPARE(spy.count(), 1);
137 }
138 }
139
fileLoadSaveCompleteness()140 void TestSkeletonResource::fileLoadSaveCompleteness()
141 {
142 // boilerplate
143 std::shared_ptr<ILanguage> language(new LanguageStub("de"));
144 ResourceRepositoryStub repository({language});
145 const QString courseDirectory = "data/contributorrepository/skeletons/";
146 const QString courseFile = courseDirectory + "skeleton.xml";
147 auto skeleton = SkeletonResource::create(QUrl::fromLocalFile(courseFile), &repository);
148
149 QTemporaryFile outputFile;
150 outputFile.open();
151 skeleton->exportToFile(QUrl::fromLocalFile(outputFile.fileName()));
152
153 // note: this only works, since the resource manager not checks uniqueness of course ids!
154 auto loadedSkeleton = SkeletonResource::create(QUrl::fromLocalFile(outputFile.fileName()), &repository);
155
156 // test that we actually call the different files
157 QVERIFY(skeleton->file().toLocalFile() != loadedSkeleton->file().toLocalFile());
158 QCOMPARE(loadedSkeleton->id(), skeleton->id());
159 QCOMPARE(loadedSkeleton->foreignId(), skeleton->foreignId());
160 QCOMPARE(loadedSkeleton->title(), skeleton->title());
161 QCOMPARE(loadedSkeleton->description(), skeleton->description());
162 QCOMPARE(loadedSkeleton->language(), skeleton->language());
163 QCOMPARE(loadedSkeleton->units().count(), skeleton->units().count());
164
165 auto testUnit = skeleton->units().constFirst();
166 auto compareUnit = loadedSkeleton->units().constFirst();
167 QCOMPARE(testUnit->id(), compareUnit->id());
168 QCOMPARE(testUnit->foreignId(), compareUnit->foreignId());
169 QCOMPARE(testUnit->title(), compareUnit->title());
170 QCOMPARE(testUnit->phrases().count(), compareUnit->phrases().count());
171
172 std::shared_ptr<IPhrase> testPhrase = testUnit->phrases().constFirst();
173 std::shared_ptr<IPhrase> comparePhrase = Phrase::create();
174 // note that this actually means that we DO NOT respect phrase orders by list order
175 for (const auto &phrase : compareUnit->phrases()) {
176 if (testPhrase->id() == phrase->id()) {
177 comparePhrase = phrase;
178 break;
179 }
180 }
181 QVERIFY(testPhrase->id() == comparePhrase->id());
182 QVERIFY(testPhrase->foreignId() == comparePhrase->foreignId());
183 QVERIFY(testPhrase->text() == comparePhrase->text());
184 QVERIFY(testPhrase->type() == comparePhrase->type());
185 QVERIFY(testPhrase->sound().fileName() == comparePhrase->sound().fileName());
186 QVERIFY(testPhrase->phonemes().count() == comparePhrase->phonemes().count());
187 }
188
189 QTEST_GUILESS_MAIN(TestSkeletonResource)
190