diff --git a/src/backends/julia/tests/testjulia.cpp b/src/backends/julia/tests/testjulia.cpp index 9032b8d8..b557d956 100644 --- a/src/backends/julia/tests/testjulia.cpp +++ b/src/backends/julia/tests/testjulia.cpp @@ -1,122 +1,273 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * --- * Copyright (C) 2016 Ivan Lakhtanov */ #include "testjulia.h" #include "session.h" #include "backend.h" #include "expression.h" #include "result.h" #include "textresult.h" +#include "imageresult.h" +#include "defaultvariablemodel.h" +#include "completionobject.h" QString TestJulia::backendName() { return QLatin1String("julia"); } void TestJulia::testOneLine() { Cantor::Expression *e = evalExp(QLatin1String("2 + 3")); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Done); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QCOMPARE(e->result()->data().toString(), QLatin1String("5")); QVERIFY(e->errorMessage().isEmpty()); } void TestJulia::testOneLineWithPrint() { Cantor::Expression *e = evalExp(QLatin1String("print(2 + 3)")); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Done); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QCOMPARE(e->result()->data().toString(), QLatin1String("5")); QVERIFY(e->errorMessage().isEmpty()); } void TestJulia::testException() { Cantor::Expression *e = evalExp(QLatin1String("sqrt(-1)")); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Error); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QVERIFY( not e->errorMessage().isEmpty() and e->errorMessage().contains(QLatin1String( "sqrt will only return a complex result if called with a " "complex argument. Try sqrt(complex(x))." )) ); } void TestJulia::testSyntaxError() { Cantor::Expression *e = evalExp(QLatin1String("for i = 1:10\nprint(i)")); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Error); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QVERIFY( not e->errorMessage().isEmpty() and e->errorMessage().contains(QLatin1String( "syntax: incomplete: \"for\" at none:1 requires end" )) ); } void TestJulia::testMultilineCode() { Cantor::Expression *e = evalExp(QLatin1String( "q = 0; # comment\n" "# sdfsdf\n" "for i = 1:10\n" " q += i\n" "end\n" "print(q)" )); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Done); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QCOMPARE(e->result()->data().toString(), QLatin1String("55")); QVERIFY(e->errorMessage().isEmpty()); } void TestJulia::testPartialResultOnException() { Cantor::Expression *e = evalExp(QLatin1String( "for i = 1:5\n" " print(i)\n" "end\n" "sqrt(-1)\n" )); QVERIFY(e != nullptr); QCOMPARE(e->status(), Cantor::Expression::Error); QVERIFY(e->result()->type() == Cantor::TextResult::Type); QCOMPARE(e->result()->data().toString(), QLatin1String("12345")); QVERIFY( not e->errorMessage().isEmpty() and e->errorMessage().contains(QLatin1String( "sqrt will only return a complex result if called with a " "complex argument. Try sqrt(complex(x))." )) ); } +void TestJulia::testInlinePlot() +{ + Cantor::Expression *e = evalExp(QLatin1String( + "import GR\n" + "GR.plot(linspace(-1, 1), sin(linspace(-1, 1)))\n" + )); + QVERIFY(e != nullptr); + QCOMPARE(e->status(), Cantor::Expression::Done); + QVERIFY(e->result()->type() == Cantor::ImageResult::Type); +} + +void TestJulia::testInlinePlotWithExceptionAndPartialResult() +{ + Cantor::Expression *e = evalExp(QLatin1String( + "import GR\n" + "print(\"gonna plot\")\n" + "sqrt(-1)\n" + "GR.plot(linspace(-1, 1), sin(linspace(-1, 1)))\n" + )); + QVERIFY(e != nullptr); + QCOMPARE(e->status(), Cantor::Expression::Error); + QVERIFY(e->result()->type() == Cantor::TextResult::Type); + QCOMPARE(e->result()->data().toString(), QLatin1String("gonna plot")); + QVERIFY( + not e->errorMessage().isEmpty() + and e->errorMessage().contains(QLatin1String( + "sqrt will only return a complex result if called with a " + "complex argument. Try sqrt(complex(x))." + )) + ); +} + +void TestJulia::testAddVariablesFromCode() +{ + evalExp(QLatin1String("a = 0; b = 1; c = 2; d = 3\n")); + + auto variableModel = session()->variableModel(); + QStringList variableNames = + QString::fromLatin1("a b c d").split(QLatin1String(" ")); + + for (int i = 0; i < variableNames.size(); i++) { + QModelIndexList matchedVariables = variableModel->match( + variableModel->index(0, 0), + Qt::DisplayRole, + QVariant::fromValue(variableNames[i]), + -1, + Qt::MatchExactly + ); + QCOMPARE(matchedVariables.size(), 1); + auto match = matchedVariables[0]; + auto valueIndex = + variableModel->index(match.row(), match.column() + 1); + QVERIFY( + valueIndex.data(Qt::DisplayRole) == + QVariant::fromValue(QString::number(i)) + ); + } +} + +void TestJulia::testAddVariablesFromManager() +{ + auto variableModel = dynamic_cast( + session()->variableModel() + ); + QStringList variableNames = + QString::fromLatin1("a b c d").split(QLatin1String(" ")); + + for (int i = 0; i < variableNames.size(); i++) { + variableModel->addVariable(variableNames[i], QString::number(i)); + + QModelIndexList matchedVariables = variableModel->match( + variableModel->index(0, 0), + Qt::DisplayRole, + QVariant::fromValue(variableNames[i]), + -1, + Qt::MatchExactly + ); + QCOMPARE(matchedVariables.size(), 1); + auto match = matchedVariables[0]; + auto valueIndex = + variableModel->index(match.row(), match.column() + 1); + QVERIFY( + valueIndex.data(Qt::DisplayRole) == + QVariant::fromValue(QString::number(i)) + ); + } +} + +void TestJulia::testRemoveVariables() +{ + auto variableModel = dynamic_cast( + session()->variableModel() + ); + QStringList variableNames = + QString::fromLatin1("a b c d").split(QLatin1String(" ")); + + for (int i = 0; i < variableNames.size(); i++) { + variableModel->addVariable(variableNames[i], QString::number(i)); + } + for (int i = 0; i < variableNames.size(); i += 2) { + variableModel->removeVariable(variableNames[i]); + } + + for (int i = 0; i < variableNames.size(); i++) { + QModelIndexList matchedVariables = variableModel->match( + variableModel->index(0, 0), + Qt::DisplayRole, + QVariant::fromValue(variableNames[i]), + -1, + Qt::MatchExactly + ); + if (i % 2 == 0) { + QVERIFY(matchedVariables.isEmpty()); + } else { + QCOMPARE(matchedVariables.size(), 1); + auto match = matchedVariables[0]; + auto valueIndex = + variableModel->index(match.row(), match.column() + 1); + QVERIFY( + valueIndex.data(Qt::DisplayRole) == + QVariant::fromValue(QString::number(i)) + ); + } + } +} + +void TestJulia::testAutoCompletion() +{ + auto prefix = QLatin1String("Ba"); + auto completionObject = session()->completionFor(prefix); + // Give sometime for Qt's singleShot in fetch completions to trigger + QTest::qWait(500); + auto completions = completionObject->completions(); + + QStringList completionsToCheck; + completionsToCheck << QLatin1String("Base"); + completionsToCheck << QLatin1String("Base64DecodePipe"); + completionsToCheck << QLatin1String("Base64EncodePipe"); + + for (auto completion : completionsToCheck) { + QVERIFY(completions.contains(completion)); + } + + for (auto completion : completionsToCheck) { + QVERIFY(completion.startsWith(prefix)); + } +} + QTEST_MAIN(TestJulia) #include "testjulia.moc" diff --git a/src/backends/julia/tests/testjulia.h b/src/backends/julia/tests/testjulia.h index 7ed4a879..0b0320a0 100644 --- a/src/backends/julia/tests/testjulia.h +++ b/src/backends/julia/tests/testjulia.h @@ -1,37 +1,84 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * --- * Copyright (C) 2016 Ivan Lakhtanov */ #pragma once #include class TestJulia: public BackendTest { Q_OBJECT private Q_SLOTS: + /** + * Test simple one-line command. Check that last result is printed + */ void testOneLine(); + /** + * Test one-line command returning `nothing`. No result is printed, except + * what `print` does + */ void testOneLineWithPrint(); + /** + * Test command, that emits exception + */ void testException(); + /** + * Test command consisting of multiple lines, including comments. + */ void testMultilineCode(); + /** + * Test command with malformed syntax + */ void testSyntaxError(); + /** + * Test that results gathered before exception occured are shown + */ void testPartialResultOnException(); + /** + * Tests that inline plot is shown + */ + void testInlinePlot(); + /** + * Tests that when exception occured and plotting is done, partial + * text results shown to user + */ + void testInlinePlotWithExceptionAndPartialResult(); + + /** + * Test registering new variables, when added by command + */ + void testAddVariablesFromCode(); + /** + * Test registering new variables, when added from variable manager + */ + void testAddVariablesFromManager(); + /** + * Test that removing variable unregisters it + */ + void testRemoveVariables(); + + /** + * Test that auto completion provides expected results + */ + void testAutoCompletion(); + private: virtual QString backendName(); };