File indexing completed on 2024-05-19 11:21:24

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004     SPDX-FileCopyrightText: 2018-2023 by Alexander Semke (alexander.semke@web.de)
0005 */
0006 
0007 #include "testmaxima.h"
0008 
0009 #include "session.h"
0010 #include "backend.h"
0011 #include "expression.h"
0012 #include "result.h"
0013 #include "textresult.h"
0014 #include "imageresult.h"
0015 #include "epsresult.h"
0016 #include "syntaxhelpobject.h"
0017 #include "completionobject.h"
0018 #include "defaultvariablemodel.h"
0019 
0020 #include <config-cantorlib.h>
0021 
0022 QString TestMaxima::backendName()
0023 {
0024     return QLatin1String("maxima");
0025 }
0026 
0027 void TestMaxima::initTestCase() {
0028     if (QStandardPaths::findExecutable(QLatin1String("maxima")).isEmpty())
0029         QSKIP("Maxima executable not found");
0030     BackendTest::initTestCase();
0031 }
0032 
0033 void TestMaxima::testSimpleCommand()
0034 {
0035     auto* e = evalExp( QLatin1String("2+2") );
0036 
0037     QVERIFY( e!=nullptr );
0038     QVERIFY( e->result()!=nullptr );
0039 
0040     QCOMPARE( cleanOutput( e->result()->data().toString() ), QLatin1String("4") );
0041 }
0042 
0043 void TestMaxima::testMultilineCommand01()
0044 {
0045     auto* e = evalExp( QLatin1String("2+2;3+3") );
0046 
0047     QVERIFY(e != nullptr);
0048     QVERIFY(e->results().size() == 2);
0049 
0050     QCOMPARE(e->results().at(0)->data().toString(), QLatin1String("4"));
0051     QCOMPARE(e->results().at(1)->data().toString(), QLatin1String("6"));
0052 }
0053 
0054 /*
0055  * test multiple variable assignments, separated by ';'.
0056  */
0057 void TestMaxima::testMultilineCommand02()
0058 {
0059     auto* e = evalExp( QLatin1String(
0060         "var1:1;\n"
0061         "var2:2;\n"
0062         "var3:3;"
0063     ) );
0064 
0065     QVERIFY(e != nullptr);
0066     QVERIFY(e->results().size() == 3);
0067 
0068     QCOMPARE(e->results().at(0)->data().toString(), QLatin1String("1"));
0069     QCOMPARE(e->results().at(1)->data().toString(), QLatin1String("2"));
0070     QCOMPARE(e->results().at(2)->data().toString(), QLatin1String("3"));
0071 
0072     e = evalExp(QLatin1String("kill(var1, var2, var3)"));
0073     QVERIFY(e != nullptr);
0074 }
0075 
0076 /*
0077  * test multiple variable assignments with a supressed output.
0078  */
0079 void TestMaxima::testMultilineCommand03()
0080 {
0081     auto* e = evalExp( QLatin1String(
0082         "var1:1$\n"
0083         "var2:2;\n"
0084     ) );
0085 
0086     QVERIFY(e != nullptr);
0087     QVERIFY(e->results().size() == 1);
0088     QCOMPARE(e->results().at(0)->data().toString(), QLatin1String("2"));
0089 
0090     e = evalExp(QLatin1String("kill(var1, var2)"));
0091     QVERIFY(e != nullptr);
0092 }
0093 
0094 //WARNING: for this test to work, Integration of Plots must be enabled
0095 //and CantorLib must be compiled with EPS-support
0096 void TestMaxima::testPlot()
0097 {
0098     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0099         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0100 
0101     auto* e = evalExp( QLatin1String("plot2d(sin(x), [x, -10,10])") );
0102 
0103     QVERIFY( e!=nullptr );
0104     QVERIFY( e->result()!=nullptr );
0105 
0106     if(session()->status() == Cantor::Session::Running)
0107         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0108 
0109     QCOMPARE( e->result()->type(), (int)Cantor::ImageResult::Type );
0110     QVERIFY( !e->result()->data().isNull() );
0111     QVERIFY( e->errorMessage().isNull() );
0112 }
0113 
0114 void TestMaxima::testPlotMultiline()
0115 {
0116     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0117         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0118 
0119     auto* e = evalExp(QLatin1String(
0120                 "plot2d (x^2-y^3+3*y=2,\n"
0121                 "[x,-2.5,2.5],\n"
0122                 "[y,-2.5,2.5])"
0123     ));
0124 
0125     QVERIFY(e != nullptr);
0126     QVERIFY(e->result() != nullptr);
0127 
0128     if(session()->status() == Cantor::Session::Running)
0129         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0130 
0131     QCOMPARE(e->result()->type(), (int)Cantor::ImageResult::Type);
0132     QVERIFY(!e->result()->data().isNull());
0133     QVERIFY(e->errorMessage().isNull());
0134 }
0135 
0136 void TestMaxima::testPlotWithWhitespaces()
0137 {
0138     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0139         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0140 
0141     auto* e = evalExp(QLatin1String(
0142                 "\n"
0143                 "plot2d (x^2-y^3+3*y=2,\n"
0144                 "[x,-2.5,2.5],\n"
0145                 "[y,-2.5,2.5])"
0146                 "\n"
0147     ));
0148 
0149     QVERIFY(e != nullptr);
0150     QVERIFY(e->result() != nullptr);
0151 
0152     if(session()->status() == Cantor::Session::Running)
0153         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0154 
0155     QCOMPARE(e->result()->type(), (int)Cantor::ImageResult::Type);
0156     QVERIFY(!e->result()->data().isNull());
0157     QVERIFY(e->errorMessage().isNull());
0158 }
0159 
0160 void TestMaxima::testPlotWithAnotherTextResults()
0161 {
0162     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0163         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0164 
0165     auto* e = evalExp( QLatin1String(
0166         "2*2; \n"
0167         "plot2d(sin(x), [x, -10,10]); \n"
0168         "4*4;"
0169     ));
0170 
0171     if(session()->status() == Cantor::Session::Running)
0172         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0173 
0174     QVERIFY( e!=nullptr );
0175     QVERIFY( e->errorMessage().isNull() );
0176     QCOMPARE(e->results().size(), 3);
0177 
0178     QCOMPARE(e->results().at(0)->data().toString(), QLatin1String("4"));
0179 
0180     QCOMPARE( e->results().at(1)->type(), (int)Cantor::ImageResult::Type );
0181     QVERIFY( !e->results().at(1)->data().isNull() );
0182 
0183     QCOMPARE(e->results().at(2)->data().toString(), QLatin1String("16"));
0184 }
0185 
0186 void TestMaxima::testDraw()
0187 {
0188     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0189         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0190 
0191     auto* e = evalExp( QLatin1String("draw3d(explicit(x^2+y^2,x,-1,1,y,-1,1))") );
0192 
0193     QVERIFY(e != nullptr);
0194     QVERIFY(e->result() != nullptr);
0195 
0196     if(!e->result())
0197         waitForSignal(e, SIGNAL(gotResult()));
0198 
0199     QCOMPARE( e->result()->type(), (int)Cantor::ImageResult::Type );
0200     QVERIFY( !e->result()->data().isNull() );
0201     QVERIFY( e->errorMessage().isNull() );
0202 }
0203 
0204 void TestMaxima::testDrawMultiline()
0205 {
0206     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0207         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0208 
0209     auto* e = evalExp( QLatin1String(
0210         "draw(\n"
0211             "gr2d(\n"
0212                 "key=\"sin (x)\",grid=[2,2],\n"
0213                 "explicit(\n"
0214                     "sin(x),\n"
0215                     "x,0,2*%pi\n"
0216                 ")\n"
0217             "),\n"
0218             "gr2d(\n"
0219                 "key=\"cos (x)\",grid=[2,2],\n"
0220                 "explicit(\n"
0221                     "cos(x),\n"
0222                     "x,0,2*%pi\n"
0223                 ")\n"
0224             "))"
0225     ));
0226 
0227 
0228     QVERIFY(e != nullptr);
0229     QVERIFY(e->result() != nullptr);
0230 
0231     if(!e->result())
0232         waitForSignal(e, SIGNAL(gotResult()));
0233 
0234     QCOMPARE(e->result()->type(), (int)Cantor::ImageResult::Type);
0235     QVERIFY(!e->result()->data().isNull());
0236     QVERIFY(e->errorMessage().isNull());
0237 }
0238 
0239 void TestMaxima::testDrawWithAnotherTextResults()
0240 {
0241     if(QStandardPaths::findExecutable(QLatin1String("gnuplot")).isNull())
0242         QSKIP("gnuplot not found, maxima needs it for plotting", SkipSingle);
0243 
0244     auto* e = evalExp( QLatin1String(
0245         "2*2; \n"
0246         "draw3d(explicit(x^2+y^2,x,-1,1,y,-1,1)); \n"
0247         "4*4;"
0248     ));
0249 
0250     if (e->results().at(1)->type() == Cantor::TextResult::Type)
0251         waitForSignal(e, SIGNAL(resultReplaced));
0252 
0253     QVERIFY( e!=nullptr );
0254     QVERIFY( e->errorMessage().isNull() );
0255     QCOMPARE(e->results().size(), 3);
0256 
0257     QCOMPARE(e->results().at(0)->data().toString(), QLatin1String("4"));
0258 
0259     QCOMPARE( e->results().at(1)->type(), (int)Cantor::ImageResult::Type );
0260     QVERIFY( !e->results().at(1)->data().isNull() );
0261 
0262     QCOMPARE(e->results().at(2)->data().toString(), QLatin1String("16"));
0263 }
0264 
0265 void TestMaxima::testInvalidSyntax()
0266 {
0267     auto* e = evalExp( QLatin1String("2+2*(") );
0268 
0269     QVERIFY( e!=nullptr );
0270     QVERIFY( e->status()==Cantor::Expression::Error );
0271     QVERIFY( !e->errorMessage().isNull() );
0272     QCOMPARE(e->results().size(), 0);
0273 }
0274 
0275 void TestMaxima::testWarning01()
0276 {
0277     auto* e = evalExp( QLatin1String("rat(0.75*10)") );
0278 
0279     QVERIFY(e != nullptr);
0280     QVERIFY(e->results().size() == 2); //two results, the warning and the actual result of the calculation
0281 
0282     //the actual warning string "rat: replaced 7.5 by 15/2 = 7.5" which we don't checked since it's translated,
0283     //we just check it's existance.
0284     auto* result = dynamic_cast<Cantor::TextResult*>(e->results().at(0));
0285     QVERIFY(e != nullptr);
0286     QVERIFY(result->data().toString().isEmpty() == false);
0287     QVERIFY(result->isWarning() == true);
0288 
0289     //the result of the calculation
0290     QCOMPARE(e->results().at(1)->data().toString(), QLatin1String("15/2"));
0291 }
0292 
0293 /*!
0294  * test the output of the tex() function which is similarly formatted as other functions producing warning
0295  * but which shouldn't be treated as a warning.
0296  * */
0297 void TestMaxima::testWarning02()
0298 {
0299     auto* e = evalExp( QLatin1String("tex(\"sin(x)\")") );
0300 
0301     QVERIFY(e != nullptr);
0302     QVERIFY(e->results().size() == 2); //two results, the TeX output and an additional 'false'
0303 
0304     //the actual TeX string is of no interest for us, we just check it's existance.
0305     auto* result = dynamic_cast<Cantor::TextResult*>(e->results().at(0));
0306     QVERIFY(e != nullptr);
0307     QVERIFY(result->data().toString().isEmpty() == false);
0308     QVERIFY(result->isWarning() == false);
0309 }
0310 
0311 void TestMaxima::testExprNumbering()
0312 {
0313     auto* e = evalExp( QLatin1String("kill(labels)") ); //first reset the labels
0314 
0315     e=evalExp( QLatin1String("2+2") );
0316     QVERIFY( e!=nullptr );
0317     int id=e->id();
0318     QCOMPARE( id, 1 );
0319 
0320     e=evalExp( QString::fromLatin1("%o%1+1" ).arg( id ) );
0321     QVERIFY( e != nullptr );
0322     QVERIFY( e->result()!=nullptr );
0323     QCOMPARE( cleanOutput( e->result()->data().toString() ), QLatin1String( "5" ) );
0324 }
0325 
0326 void TestMaxima::testCommandQueue()
0327 {
0328     //only wait for the last Expression to return, so the queue gets
0329     //actually filled
0330 
0331     auto* e1 = session()->evaluateExpression(QLatin1String("0+1"));
0332     auto* e2 = session()->evaluateExpression(QLatin1String("1+1"));
0333     auto* e3 = evalExp(QLatin1String("1+2"));
0334 
0335     QVERIFY(e1!=nullptr);
0336     QVERIFY(e2!=nullptr);
0337     QVERIFY(e3!=nullptr);
0338 
0339     QVERIFY(e1->result());
0340     QVERIFY(e2->result());
0341     QVERIFY(e3->result());
0342 
0343     QCOMPARE(cleanOutput(e1->result()->data().toString()), QLatin1String("1"));
0344     QCOMPARE(cleanOutput(e2->result()->data().toString()), QLatin1String("2"));
0345     QCOMPARE(cleanOutput(e3->result()->data().toString()), QLatin1String("3"));
0346 }
0347 
0348 void TestMaxima::testSimpleExpressionWithComment()
0349 {
0350     auto* e = evalExp(QLatin1String("/*this is a comment*/2+2"));
0351     QVERIFY(e!=nullptr);
0352     QVERIFY(e->result()!=nullptr);
0353 
0354     QCOMPARE(cleanOutput(e->result()->data().toString()), QLatin1String("4"));
0355 }
0356 
0357 void TestMaxima::testCommentExpression()
0358 {
0359     auto* e = evalExp(QLatin1String("/*this is a comment*/"));
0360     QVERIFY(e!=nullptr);
0361     QVERIFY(e->result()==nullptr||e->result()->data().toString().isEmpty());
0362 }
0363 
0364 void TestMaxima::testNestedComment()
0365 {
0366     auto* e = evalExp(QLatin1String("/*/*this is still a comment*/*/2+2/*still/*a*/comment*//**/"));
0367     QVERIFY(e!=nullptr);
0368     QVERIFY(e->result()!=nullptr);
0369 
0370     QCOMPARE(cleanOutput(e->result()->data().toString()), QLatin1String("4"));
0371 }
0372 
0373 void TestMaxima::testUnmatchedComment()
0374 {
0375     auto* e = evalExp(QLatin1String("/*this comment doesn't end here!"));
0376     QVERIFY(e!=nullptr);
0377     QVERIFY(e->result()==nullptr);
0378     QVERIFY(e->status()==Cantor::Expression::Error);
0379 }
0380 
0381 void TestMaxima::testInvalidAssignment()
0382 {
0383     auto* e = evalExp(QLatin1String("0:a"));
0384     QVERIFY(e!=nullptr);
0385     //QVERIFY(e->result()==0);
0386     //QVERIFY(e->status()==Cantor::Expression::Error);
0387 
0388     if(session()->status() == Cantor::Session::Running)
0389         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0390 
0391     //make sure we didn't screw up the session
0392     auto* e2=evalExp(QLatin1String("2+2"));
0393     QVERIFY(e2!=nullptr);
0394     QVERIFY(e2->result()!=nullptr);
0395 
0396     QCOMPARE(cleanOutput(e2->result()->data().toString()), QLatin1String("4"));
0397 }
0398 
0399 void TestMaxima::testInformationRequest()
0400 {
0401     auto* e = session()->evaluateExpression(QLatin1String("integrate(x^n,x)"));
0402     QVERIFY(e!=nullptr);
0403     waitForSignal(e, SIGNAL(needsAdditionalInformation(QString)));
0404     e->addInformation(QLatin1String("N"));
0405 
0406     waitForSignal(e, SIGNAL(statusChanged(Cantor::Expression::Status)));
0407     QVERIFY(e->result()!=nullptr);
0408 
0409     QCOMPARE(cleanOutput(e->result()->data().toString()), QLatin1String("x^(n+1)/(n+1)"));
0410 }
0411 
0412 void TestMaxima::testHelpRequest()
0413 {
0414     QSKIP("TODO: failing on CI");
0415     //execute "??print"
0416     auto* e = session()->evaluateExpression(QLatin1String("??print"));
0417     QVERIFY(e != nullptr);
0418 
0419     //help result will be shown, but maxima still expects further input
0420     waitForSignal(e, SIGNAL(needsAdditionalInformation(QString)));
0421     QVERIFY(e->status() != Cantor::Expression::Done);
0422     QVERIFY(e->results().size() == 1); // one HelpResult showing the possible options for the answer
0423 
0424     //ask for help for the first flag of the print command
0425     e->addInformation(QLatin1String("0"));
0426 
0427     //no further input is required, we're done
0428     if (e->status() == Cantor::Expression::Computing)
0429         waitForSignal(e, SIGNAL(statusChanged(Cantor::Expression::Status)));
0430 
0431     QVERIFY(e->status() == Cantor::Expression::Done);
0432     QVERIFY(e->results().size() == 1); // final HelpResult
0433 }
0434 
0435 void TestMaxima::testSyntaxHelp()
0436 {
0437     auto* help = session()->syntaxHelpFor(QLatin1String("simplify_sum"));
0438     help->fetchSyntaxHelp();
0439     waitForSignal(help, SIGNAL(done()));
0440 
0441     bool trueHelpMessage= help->toHtml().contains(QLatin1String("simplify_sum"));
0442     bool problemsWithMaximaDocs = help->toHtml().contains(QLatin1String("INTERNAL-SIMPLE-FILE-ERROR"));
0443     QVERIFY(trueHelpMessage || problemsWithMaximaDocs);
0444 }
0445 
0446 void TestMaxima::testCompletion()
0447 {
0448     auto* help = session()->completionFor(QLatin1String("ask"), 3);
0449     waitForSignal(help, SIGNAL(fetchingDone()));
0450 
0451     // Checks all completions for this request
0452     // This correct for Maxima 5.41.0
0453     const QStringList& completions = help->completions();
0454     QVERIFY(completions.contains(QLatin1String("asksign")));
0455     QVERIFY(completions.contains(QLatin1String("askinteger")));
0456     QVERIFY(completions.contains(QLatin1String("askexp")));
0457 }
0458 
0459 void TestMaxima::testTextQuotes()
0460 {
0461     // check simple string
0462     auto* e1 = evalExp(QLatin1String("t1: \"test string\""));
0463     QVERIFY(e1 != nullptr);
0464 
0465     if(session()->status() == Cantor::Session::Running)
0466         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0467 
0468     QVERIFY(e1->result() != nullptr);
0469     QCOMPARE(e1->result()->type(), (int)Cantor::TextResult::Type );
0470     QCOMPARE(e1->result()->data().toString(), QLatin1String("test string"));
0471 
0472     // check string with quotes inside
0473     auto* e2 = evalExp(QLatin1String("t2: \"this is a \\\"quoted string\\\"\""));
0474     QVERIFY(e2 != nullptr);
0475 
0476     if(session()->status() == Cantor::Session::Running)
0477         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0478 
0479     QVERIFY(e2->result() != nullptr);
0480     QCOMPARE(e2->result()->type(), (int)Cantor::TextResult::Type );
0481     QCOMPARE(e2->result()->data().toString(), QLatin1String("this is a \"quoted string\""));
0482 
0483     auto* e = evalExp(QLatin1String("kill(t1, t2)"));
0484     QVERIFY(e != nullptr);
0485 }
0486 
0487 void TestMaxima::testVariableModel()
0488 {
0489     QAbstractItemModel* model = session()->variableModel();
0490     QVERIFY(model != nullptr);
0491 
0492     auto* e1 = evalExp(QLatin1String("a: 15"));
0493     auto* e2 = evalExp(QLatin1String("b: \"Hello, world!\""));
0494     auto* e3 = evalExp(QLatin1String("l: [1,2,3]"));
0495     auto* e4 = evalExp(QLatin1String("t: \"this is a \\\"quoted string\\\"\""));
0496     QVERIFY(e1 != nullptr);
0497     QVERIFY(e2 != nullptr);
0498     QVERIFY(e3 != nullptr);
0499     QVERIFY(e4 != nullptr);
0500 
0501     if(session()->status() == Cantor::Session::Running)
0502         waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
0503 
0504     QCOMPARE(4, model->rowCount());
0505 
0506     QVariant name = model->index(0,0).data();
0507     QCOMPARE(name.toString(),QLatin1String("a"));
0508 
0509     QVariant value = model->index(0,1).data();
0510     QCOMPARE(value.toString(),QLatin1String("15"));
0511 
0512     QVariant name1 = model->index(1,0).data();
0513     QCOMPARE(name1.toString(),QLatin1String("b"));
0514 
0515     QVariant value1 = model->index(1,1).data();
0516     QCOMPARE(value1.toString(),QLatin1String("Hello, world!"));
0517 
0518     QVariant name2 = model->index(2,0).data();
0519     QCOMPARE(name2.toString(),QLatin1String("l"));
0520 
0521     QVariant value2 = model->index(2,1).data();
0522     QCOMPARE(value2.toString(),QLatin1String("[1,2,3]"));
0523 
0524     QVariant name3 = model->index(3,0).data();
0525     QCOMPARE(name3.toString(),QLatin1String("t"));
0526 
0527     QVariant value3 = model->index(3,1).data();
0528     QCOMPARE(value3.toString(),QLatin1String("this is a \"quoted string\""));
0529 
0530     auto* e = evalExp(QLatin1String("kill(all)"));
0531     QVERIFY(e != nullptr);
0532 }
0533 
0534 void TestMaxima::testLispMode01()
0535 {
0536     //switch to the Lisp-mode
0537     auto* e1 = evalExp(QLatin1String("to_lisp();"));
0538     QVERIFY(e1 != nullptr);
0539 
0540     //evaluate a Lisp command and check the result
0541     auto* e2 = evalExp(QLatin1String("(cons 'a 'b)"));
0542     QVERIFY(e2 != nullptr);
0543     QVERIFY(e2->result() != nullptr);
0544     QCOMPARE(cleanOutput(e2->result()->data().toString()), QLatin1String("(A . B)"));
0545 
0546     //switch back to Maxima mode
0547     auto* e3 = evalExp(QLatin1String("(to-maxima)"));
0548     QVERIFY(e3 != nullptr);
0549 
0550     //evaluate a simple Maxima command
0551     auto* e4 = evalExp(QLatin1String("5+5"));
0552     QVERIFY(e4 != nullptr);
0553 
0554     QVERIFY(e4->result() != nullptr);
0555     QCOMPARE(cleanOutput(e4->result()->data().toString()), QLatin1String("10"));
0556 }
0557 
0558 void TestMaxima::testLoginLogout()
0559 {
0560     // Logout from session twice and all must works fine
0561     session()->logout();
0562     session()->logout();
0563 
0564     // Login in session twice and all must works fine
0565     session()->login();
0566     session()->login();
0567 }
0568 
0569 void TestMaxima::testRestartWhileRunning()
0570 {
0571     QSKIP("This test is not working yet.", SkipSingle);
0572     auto* e1 = session()->evaluateExpression(QLatin1String(":lisp (sleep 5)"));
0573     QVERIFY(e1 != nullptr);
0574 
0575     session()->logout();
0576 
0577     QCOMPARE(e1->status(), Cantor::Expression::Interrupted);
0578     session()->login();
0579 
0580     auto* e2=evalExp( QLatin1String("2+2") );
0581 
0582     QVERIFY(e2 != nullptr);
0583     QVERIFY(e2->result() != nullptr);
0584 
0585     QCOMPARE(cleanOutput(e2->result()->data().toString() ), QLatin1String("4"));
0586 }
0587 
0588 QTEST_MAIN( TestMaxima )
0589