diff options
author | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2013-07-04 20:11:10 +0200 |
---|---|---|
committer | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2013-10-01 14:23:00 +0200 |
commit | 11aeaea86f99bb00ef328c6f439d5549131cfc28 (patch) | |
tree | cc15cb55e6b7e6ad0d65065b49506c7f979e8d51 /src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp | |
parent | 3a64f8a344b1c702f66331a4fa21807f0a017762 (diff) | |
download | qt-creator-11aeaea86f99bb00ef328c6f439d5549131cfc28.tar.gz |
CppEditor: "Follow Symbol Under Cursor" for virtual functions
F2 on a virtual function call presents a list of overrides in derived
classes. The function declaration of the static type is shown
immediately at the top.
Task-number: QTCREATORBUG-9611
Change-Id: I80ce906fa06272dc9fbd1662cd17500b8c77067f
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp')
-rw-r--r-- | src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp | 346 |
1 files changed, 306 insertions, 40 deletions
diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 46ff3e159b..f922b20de3 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -29,8 +29,13 @@ #include "cppeditor.h" #include "cppeditorplugin.h" +#include "cppelementevaluator.h" +#include "cppvirtualfunctionassistprovider.h" #include <coreplugin/plugintestutils.h> +#include <texteditor/codeassist/iassistproposal.h> +#include <texteditor/codeassist/iassistprocessor.h> +#include <texteditor/codeassist/basicproposalitemlistmodel.h> #include <utils/fileutils.h> #include <QDebug> @@ -57,6 +62,60 @@ using namespace Core; namespace { +/// A fake virtual functions assist provider that runs processor->perform() already in configure() +class VirtualFunctionTestAssistProvider : public VirtualFunctionAssistProvider +{ +public: + VirtualFunctionTestAssistProvider(CPPEditorWidget *editorWidget) + : m_editorWidget(editorWidget) + {} + + // Invoke the processor already here to calculate the proposals. Return false in order to + // indicate that configure failed, so the actual code assist invocation leading to a pop-up + // will not happen. + bool configure(CPlusPlus::Class *startClass, CPlusPlus::Function *function, + const CPlusPlus::Snapshot &snapshot, bool openInNextSplit) + { + VirtualFunctionAssistProvider::configure(startClass, function, snapshot, openInNextSplit); + + IAssistProcessor *processor = createProcessor(); + IAssistInterface *interface = m_editorWidget->createAssistInterface(FollowSymbol, + ExplicitlyInvoked); + IAssistProposal *immediateProposal = processor->immediateProposal(interface); + IAssistProposal *finalProposal = processor->perform(interface); + + m_immediateItems = itemList(immediateProposal->model()); + m_finalItems = itemList(finalProposal->model()); + + return false; + } + + static QStringList itemList(IAssistProposalModel *imodel) + { + QStringList immediateItems; + BasicProposalItemListModel *model = dynamic_cast<BasicProposalItemListModel *>(imodel); + if (!model) + return immediateItems; + if (model->isSortable(QString())) + model->sort(QString()); + model->removeDuplicates(); + + for (int i = 0, size = model->size(); i < size; ++i) { + const QString text = model->text(i); + immediateItems.append(text); + } + + return immediateItems; + } + +public: + QStringList m_immediateItems; + QStringList m_finalItems; + +private: + CPPEditorWidget *m_editorWidget; +}; + class TestDocument; typedef QSharedPointer<TestDocument> TestDocumentPtr; @@ -136,12 +195,16 @@ class TestCase { public: enum CppEditorAction { - FollowSymbolUnderCursor, - SwitchBetweenMethodDeclarationDefinition + FollowSymbolUnderCursorAction, + SwitchBetweenMethodDeclarationDefinitionAction }; - TestCase(CppEditorAction action, const QByteArray &source); - TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles); + TestCase(CppEditorAction action, const QByteArray &source, + const QStringList &expectedVirtualFunctionImmediateProposal = QStringList(), + const QStringList &expectedVirtualFunctionFinalProposal = QStringList()); + TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles, + const QStringList &expectedVirtualSymbolsImmediateProposal = QStringList(), + const QStringList &expectedVirtualSymbolsFinalProposal = QStringList()); ~TestCase(); void run(bool expectedFail = false); @@ -158,12 +221,18 @@ private: private: CppEditorAction m_action; QList<TestDocumentPtr> m_testFiles; + QStringList m_expectedVirtualSymbolsImmediateProposal; // for virtual functions + QStringList m_expectedVirtualSymbolsFinalProposals; // for virtual functions }; /// Convenience function for creating a TestDocument. /// See TestDocument. -TestCase::TestCase(CppEditorAction action, const QByteArray &source) +TestCase::TestCase(CppEditorAction action, const QByteArray &source, + const QStringList &expectedVirtualFunctionImmediateProposal, + const QStringList &expectedVirtualFunctionFinalProposal) : m_action(action) + , m_expectedVirtualSymbolsImmediateProposal(expectedVirtualFunctionImmediateProposal) + , m_expectedVirtualSymbolsFinalProposals(expectedVirtualFunctionFinalProposal) { m_testFiles << TestDocument::create(source, QLatin1String("file.cpp")); init(); @@ -173,9 +242,13 @@ TestCase::TestCase(CppEditorAction action, const QByteArray &source) /// Exactly one test document must be provided that contains '@', the initial position marker. /// Exactly one test document must be provided that contains '$', the target position marker. /// It can be the same document. -TestCase::TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles) +TestCase::TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles, + const QStringList &expectedVirtualSymbolsImmediateProposal, + const QStringList &expectedVirtualSymbolsFinalProposal) : m_action(action) , m_testFiles(theTestFiles) + , m_expectedVirtualSymbolsImmediateProposal(expectedVirtualSymbolsImmediateProposal) + , m_expectedVirtualSymbolsFinalProposals(expectedVirtualSymbolsFinalProposal) { init(); } @@ -292,12 +365,29 @@ void TestCase::run(bool expectedFail) // qDebug() << "Initial line:" << initialTestFile->editor->currentLine(); // qDebug() << "Initial column:" << initialTestFile->editor->currentColumn() - 1; + QStringList immediateVirtualSymbolResults; + QStringList finalVirtualSymbolResults; + // Trigger the action switch (m_action) { - case FollowSymbolUnderCursor: + case FollowSymbolUnderCursorAction: { + CPPEditorWidget *widget = initialTestFile->editorWidget; + FollowSymbolUnderCursor *delegate = widget->followSymbolUnderCursorDelegate(); + VirtualFunctionAssistProvider *original = delegate->virtualFunctionAssistProvider(); + + // Set test provider, run and get results + QScopedPointer<VirtualFunctionTestAssistProvider> testProvider( + new VirtualFunctionTestAssistProvider(widget)); + delegate->setVirtualFunctionAssistProvider(testProvider.data()); initialTestFile->editorWidget->openLinkUnderCursor(); + immediateVirtualSymbolResults = testProvider->m_immediateItems; + finalVirtualSymbolResults = testProvider->m_finalItems; + + // Restore original test provider + delegate->setVirtualFunctionAssistProvider(original); break; - case SwitchBetweenMethodDeclarationDefinition: + } + case SwitchBetweenMethodDeclarationDefinitionAction: CppEditorPlugin::instance()->switchDeclarationDefinition(); break; default: @@ -318,10 +408,16 @@ void TestCase::run(bool expectedFail) &expectedLine, &expectedColumn); // qDebug() << "Expected line:" << expectedLine; // qDebug() << "Expected column:" << expectedColumn; + if (expectedFail) QEXPECT_FAIL("", "Contributor works on a fix.", Abort); QCOMPARE(currentTextEditor->currentLine(), expectedLine); QCOMPARE(currentTextEditor->currentColumn() - 1, expectedColumn); + +// qDebug() << immediateVirtualSymbolResults; +// qDebug() << finalVirtualSymbolResults; + QCOMPARE(immediateVirtualSymbolResults, m_expectedVirtualSymbolsImmediateProposal); + QCOMPARE(finalVirtualSymbolResults, m_expectedVirtualSymbolsFinalProposals); } } // anonymous namespace @@ -354,7 +450,7 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_fromFunctionDeclara ; testFiles << TestDocument::create(sourceContents, QLatin1String("file.cpp")); - TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinition, testFiles); + TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinitionAction, testFiles); test.run(); } @@ -386,7 +482,7 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_fromFunctionDefinit ; testFiles << TestDocument::create(sourceContents, QLatin1String("file.cpp")); - TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinition, testFiles); + TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinitionAction, testFiles); test.run(); } @@ -418,7 +514,7 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_fromFunctionBody() ; testFiles << TestDocument::create(sourceContents, QLatin1String("file.cpp")); - TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinition, testFiles); + TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinitionAction, testFiles); test.run(); } @@ -450,7 +546,7 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_fromReturnType() ; testFiles << TestDocument::create(sourceContents, QLatin1String("file.cpp")); - TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinition, testFiles); + TestCase test(TestCase::SwitchBetweenMethodDeclarationDefinitionAction, testFiles); test.run(); } @@ -465,7 +561,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_globalVarFromFunction() "}\n" // Line 5 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -483,7 +579,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_funLocalVarHidesClassMember() "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -503,7 +599,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_funLocalVarHidesNamespaceMemb "}\n" // Line 10 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -521,7 +617,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_loopLocalVarHidesOuterScopeVa "}\n"; ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -539,7 +635,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_loopLocalVarHidesOuterScopeVa "}\n"; ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -553,7 +649,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_subsequentDefinedClassMember( "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -569,7 +665,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_classMemberHidesOuterTypeDef( "};\n" // Line 5 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -584,7 +680,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_globalVarFromEnum() "}\n" // Line 5 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(/*expectedFail =*/ true); } @@ -599,7 +695,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_selfInitialization() "}\n" // Line 5 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -612,7 +708,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_pointerToClassInClassDefiniti "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -626,7 +722,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_previouslyDefinedMemberFromAr "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -648,7 +744,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_outerStaticMemberVariableFrom "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -668,7 +764,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_memberVariableFollowingDotOpe "}\n" // Line 10 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -688,7 +784,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_memberVariableFollowingArrowO "}\n" // Line 10 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -707,7 +803,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_staticMemberVariableFollowing "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -727,7 +823,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_staticMemberVariableFollowing "}\n" // Line 10 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -748,7 +844,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_staticMemberVariableFollowing "}\n" // Line 10 ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -762,7 +858,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_previouslyDefinedEnumValueFro "};\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -785,7 +881,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_nsMemberHidesNsMemberIntroduc "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -812,7 +908,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_baseClassFunctionIntroducedBy "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -839,7 +935,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_funWithSameNameAsBaseClassFun "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -858,7 +954,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_funLocalVarHidesOuterClass() "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -876,7 +972,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_classConstructor() "{\n" "}\n"; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -894,7 +990,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_classDestructor() "{\n" "}\n"; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -988,7 +1084,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_QObject_connect() return; } - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -1005,7 +1101,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_global "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -1024,7 +1120,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_namesp "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } @@ -1041,7 +1137,177 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_inside "}\n" ; - TestCase test(TestCase::FollowSymbolUnderCursor, source); + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); + test.run(); +} + +/// Check: Static type is base class pointer, all overrides are presented. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_allOverrides() +{ + const QByteArray source = + "struct A { virtual void virt() = 0; };\n" + "void A::virt() {}\n" + "\n" + "struct B : A { void virt(); };\n" + "void B::virt() {}\n" + "\n" + "struct C : B { void virt(); };\n" + "void C::virt() {}\n" + "\n" + "struct CD1 : C { void virt(); };\n" + "void CD1::virt() {}\n" + "\n" + "struct CD2 : C { void virt(); };\n" + "void CD2::virt() {}\n" + "\n" + "int f(A *o)\n" + "{\n" + " o->$@virt();\n" + "}\n" + ; + + const QStringList immediateResults = QStringList() + << QLatin1String("A::virt") + << QLatin1String("...searching overrides"); + const QStringList finalResults = QStringList() + << QLatin1String("A::virt") + << QLatin1String("A::virt") // TODO: Double entry + << QLatin1String("B::virt") + << QLatin1String("C::virt") + << QLatin1String("CD1::virt") + << QLatin1String("CD2::virt"); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: Static type is derived class pointer, only overrides of sub classes are presented. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides1() +{ + const QByteArray source = + "struct A { virtual void virt() = 0; };\n" + "void A::virt() {}\n" + "\n" + "struct B : A { void virt(); };\n" + "void B::virt() {}\n" + "\n" + "struct C : B { void virt(); };\n" + "void C::virt() {}\n" + "\n" + "struct CD1 : C { void virt(); };\n" + "void CD1::virt() {}\n" + "\n" + "struct CD2 : C { void virt(); };\n" + "void CD2::virt() {}\n" + "\n" + "int f(B *o)\n" + "{\n" + " o->$@virt();\n" + "}\n" + ; + + const QStringList immediateResults = QStringList() + << QLatin1String("B::virt") + << QLatin1String("...searching overrides"); + const QStringList finalResults = QStringList() + << QLatin1String("B::virt") + << QLatin1String("B::virt") // Double entry + << QLatin1String("C::virt") + << QLatin1String("CD1::virt") + << QLatin1String("CD2::virt"); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: Virtual function call in member of class hierarchy, only possible overrides are presented. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides2() +{ + const QByteArray source = + "struct A { virtual void f(); };\n" + "void A::f() {}\n" + "\n" + "struct B : public A { void f(); };\n" + "void B::f() {}\n" + "\n" + "struct C : public B { void g() { f$@(); } }; \n" + "\n" + "struct D : public C { void f(); };\n" + "void D::f() {}\n" + ; + + const QStringList immediateResults = QStringList() + << QLatin1String("B::f") + << QLatin1String("...searching overrides"); + const QStringList finalResults = QStringList() + << QLatin1String("B::f") + << QLatin1String("B::f") + << QLatin1String("D::f"); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: Do not trigger on qualified function calls. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified() +{ + const QByteArray source = + "struct A { virtual void f(); };\n" + "void A::$f() {}\n" + "\n" + "struct B : public A {\n" + " void f();\n" + " void g() { A::@f(); }\n" + "};\n" + ; + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); + test.run(); +} + +/// Check: Do not trigger on member function declaration. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDeclaration() +{ + const QByteArray source = + "struct A { virtual void f(); };\n" + "void A::f() {}\n" + "\n" + "struct B : public A { void f@(); };\n" + "void B::$f() {}\n" + ; + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); + test.run(); +} + +/// Check: Do not trigger on function definition. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefinition() +{ + const QByteArray source = + "struct A { virtual void f(); };\n" + "void A::f() {}\n" + "\n" + "struct B : public A { void $f(); };\n" + "void B::@f() {}\n" + ; + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); + test.run(); +} + +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnNonPointerNonReference() +{ + const QByteArray source = + "struct A { virtual void f(); };\n" + "void A::f() {}\n" + "\n" + "struct B : public A { void f(); };\n" + "void B::$f() {}\n" + "\n" + "void client(B b) { b.@f(); }\n" + ; + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); test.run(); } |