File indexing completed on 2023-10-01 07:35:56
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2019 Sirgienko Nikita <warquark@gmail.com> 0004 */ 0005 0006 #include "testr.h" 0007 0008 #include "session.h" 0009 #include "backend.h" 0010 #include "expression.h" 0011 #include "result.h" 0012 #include "imageresult.h" 0013 #include "helpresult.h" 0014 #include "syntaxhelpobject.h" 0015 #include "completionobject.h" 0016 #include "defaultvariablemodel.h" 0017 0018 #include <QDebug> 0019 #include <QTextDocument> 0020 #include <QSyntaxHighlighter> 0021 0022 QString TestR::backendName() 0023 { 0024 return QLatin1String("R"); 0025 } 0026 0027 void TestR::testSimpleCommand() 0028 { 0029 Cantor::Expression* e=evalExp( QLatin1String("2+2") ); 0030 0031 QVERIFY( e!=nullptr ); 0032 QVERIFY( e->result()!=nullptr ); 0033 0034 QCOMPARE( cleanOutput( e->result()->data().toString() ), QLatin1String("[1] 4") ); 0035 } 0036 0037 void TestR::testMultilineCommand() 0038 { 0039 Cantor::Expression* e = evalExp(QLatin1String("print(2+2)\nprint(7*5)")); 0040 0041 QVERIFY(e != nullptr); 0042 QVERIFY(e->result() != nullptr); 0043 QCOMPARE(cleanOutput( e->result()->data().toString() ), QLatin1String("[1] 4\n[1] 35")); 0044 } 0045 0046 void TestR::testCodeWithComments() 0047 { 0048 Cantor::Expression* e=evalExp( QLatin1String("2+2 #comment") ); 0049 0050 QVERIFY( e!=nullptr ); 0051 QVERIFY( e->result()!=nullptr ); 0052 0053 QCOMPARE( cleanOutput( e->result()->data().toString() ), QLatin1String("[1] 4") ); 0054 } 0055 0056 void TestR::testCommandQueue() 0057 { 0058 Cantor::Expression* e1=session()->evaluateExpression(QLatin1String("0+1")); 0059 Cantor::Expression* e2=session()->evaluateExpression(QLatin1String("1+1")); 0060 Cantor::Expression* e3=evalExp(QLatin1String("1+2")); 0061 0062 qDebug() << e1 << e1->command() << e1->status(); 0063 qDebug() << e2 << e2->command() << e2->status(); 0064 qDebug() << e3 << e3->command() << e3->status(); 0065 0066 QVERIFY(e1!=nullptr); 0067 QVERIFY(e2!=nullptr); 0068 QVERIFY(e3!=nullptr); 0069 0070 QVERIFY(e1->result()); 0071 QVERIFY(e2->result()); 0072 QVERIFY(e3->result()); 0073 0074 QCOMPARE(cleanOutput(e1->result()->data().toString()), QLatin1String("[1] 1")); 0075 QCOMPARE(cleanOutput(e2->result()->data().toString()), QLatin1String("[1] 2")); 0076 QCOMPARE(cleanOutput(e3->result()->data().toString()), QLatin1String("[1] 3")); 0077 } 0078 0079 void TestR::testVariablesCreatingFromCode() 0080 { 0081 QAbstractItemModel* model = session()->variableModel(); 0082 QVERIFY(model != nullptr); 0083 0084 Cantor::Expression* e=evalExp(QLatin1String("a1 = 15; b1 = 'S'; d1 = c(1,2,3)")); 0085 0086 QVERIFY(e!=nullptr); 0087 QVERIFY(e->result() != nullptr); 0088 0089 while (session()->status() != Cantor::Session::Done) 0090 waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status))); 0091 0092 QCOMPARE(model->rowCount(), 3); 0093 0094 QCOMPARE(model->index(0,0).data().toString(), QLatin1String("a1")); 0095 QCOMPARE(model->index(0,1).data().toString(), QLatin1String("15")); 0096 0097 QCOMPARE(model->index(1,0).data().toString(), QLatin1String("b1")); 0098 QCOMPARE(model->index(1,1).data().toString(), QLatin1String("S")); 0099 0100 QCOMPARE(model->index(2,0).data().toString(), QLatin1String("d1")); 0101 QCOMPARE(model->index(2,1).data().toString(), QLatin1String("1, 2, 3")); 0102 0103 evalExp(QLatin1String("rm(a1,b1,d1)")); 0104 } 0105 0106 void TestR::testVariableCleanupAfterRestart() 0107 { 0108 QAbstractItemModel* model = session()->variableModel(); 0109 QVERIFY(model != nullptr); 0110 0111 while(session()->status() != Cantor::Session::Done) 0112 waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status))); 0113 0114 QCOMPARE(model->rowCount(), 0); 0115 0116 Cantor::Expression* e=evalExp(QLatin1String("h1 = 15; h2 = 'S';")); 0117 QVERIFY(e!=nullptr); 0118 0119 while (session()->status() != Cantor::Session::Done) 0120 waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status))); 0121 0122 QCOMPARE(model->rowCount(), 2); 0123 0124 session()->logout(); 0125 session()->login(); 0126 0127 QCOMPARE(model->rowCount(), 0); 0128 } 0129 0130 void TestR::testVariableDefinition() 0131 { 0132 Cantor::Expression* e = evalExp(QLatin1String("testvar <- \"value\"; testvar")); 0133 0134 QVERIFY(e != nullptr); 0135 QCOMPARE(e->status(), Cantor::Expression::Done); 0136 QVERIFY(e->result() != nullptr); 0137 QCOMPARE(cleanOutput(e->result()->data().toString()), QLatin1String("[1] \"value\"")); 0138 0139 evalExp(QLatin1String("rm(testvar)")); 0140 } 0141 0142 void TestR::testMatrixDefinition() 0143 { 0144 Cantor::Expression* e = evalExp(QLatin1String("matrix(1:9, nrow = 3, ncol = 3)")); 0145 0146 QVERIFY(e != nullptr); 0147 QCOMPARE(e->status(), Cantor::Expression::Done); 0148 QVERIFY(e->result() != nullptr); 0149 QCOMPARE(e->result()->data().toString(), QLatin1String( 0150 " [,1] [,2] [,3]\n" 0151 "[1,] 1 4 7\n" 0152 "[2,] 2 5 8\n" 0153 "[3,] 3 6 9" 0154 )); 0155 } 0156 0157 void TestR::testCommentExpression() 0158 { 0159 Cantor::Expression* e = evalExp(QLatin1String("#only comment")); 0160 0161 QVERIFY(e != nullptr); 0162 QCOMPARE(e->status(), Cantor::Expression::Status::Done); 0163 QCOMPARE(e->results().size(), 0); 0164 } 0165 0166 void TestR::testMultilineCommandWithComment() 0167 { 0168 Cantor::Expression* e = evalExp(QLatin1String( 0169 "print(2+2) \n" 0170 "#comment in middle \n" 0171 "print(7*5)")); 0172 0173 QVERIFY(e != nullptr); 0174 QCOMPARE(e->status(), Cantor::Expression::Status::Done); 0175 QVERIFY(e->result() != nullptr); 0176 QVERIFY(e->result()->data().toString() == QLatin1String("[1] 4\n[1] 35")); 0177 } 0178 0179 void TestR::testInvalidSyntax() 0180 { 0181 Cantor::Expression* e=evalExp( QLatin1String("2+2*+?!<") ); 0182 0183 QVERIFY( e!=nullptr ); 0184 QCOMPARE( e->status(), Cantor::Expression::Error ); 0185 } 0186 0187 void TestR::testCompletion() 0188 { 0189 // Actual completion needs session in Done state 0190 while (session()->status() != Cantor::Session::Done) 0191 waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status))); 0192 0193 Cantor::CompletionObject* help = session()->completionFor(QLatin1String("pi"), 2); 0194 waitForSignal(help, SIGNAL(fetchingDone())); 0195 0196 // Checks all completions for this request 0197 // This correct for R 3.4.4 0198 const QStringList& completions = help->completions(); 0199 qDebug() << completions; 0200 QCOMPARE(completions.size(), 5); 0201 QVERIFY(completions.contains(QLatin1String("pi"))); 0202 QVERIFY(completions.contains(QLatin1String("pico"))); 0203 QVERIFY(completions.contains(QLatin1String("pictex"))); 0204 QVERIFY(completions.contains(QLatin1String("pie"))); 0205 QVERIFY(completions.contains(QLatin1String("pipe"))); 0206 } 0207 0208 void TestR::testSimplePlot() 0209 { 0210 Cantor::Expression* e = evalExp(QLatin1String("plot(c(1, 4, 9, 16))")); 0211 0212 QVERIFY(e != nullptr); 0213 QCOMPARE(e->status(), Cantor::Expression::Status::Done); 0214 QVERIFY(e->result() != nullptr); 0215 QCOMPARE(e->result()->type(), (int)Cantor::ImageResult::Type); 0216 } 0217 0218 void TestR::testComplexPlot() 0219 { 0220 const QLatin1String cmd( 0221 "# Define 2 vectors\n" 0222 "cars <- c(1, 3, 6, 4, 9)\n" 0223 "trucks <- c(2, 5, 4, 5, 12)\n" 0224 "\n" 0225 "# Calculate range from 0 to max value of cars and trucks\n" 0226 "g_range <- range(0, cars, trucks)\n" 0227 "\n" 0228 "# Graph autos using y axis that ranges from 0 to max \n" 0229 "# value in cars or trucks vector. Turn off axes and \n" 0230 "# annotations (axis labels) so we can specify them ourself\n" 0231 "plot(cars, type=\"o\", col=\"blue\", ylim=g_range, \n" 0232 " axes=FALSE, ann=FALSE)\n" 0233 "\n" 0234 "# Make x axis using Mon-Fri labels\n" 0235 "axis(1, at=1:5, lab=c(\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\"))\n" 0236 "\n" 0237 "# Make y axis with horizontal labels that display ticks at \n" 0238 "# every 4 marks. 4*0:g_range[2] is equivalent to c(0,4,8,12).\n" 0239 "axis(2, las=1, at=4*0:g_range[2])\n" 0240 "\n" 0241 "# Create box around plot\n" 0242 "box()\n" 0243 "\n" 0244 "# Graph trucks with red dashed line and square points\n" 0245 "lines(trucks, type=\"o\", pch=22, lty=2, col=\"red\")\n" 0246 "\n" 0247 "# Create a title with a red, bold/italic font\n" 0248 "title(main=\"Autos\", col.main=\"red\", font.main=4)\n" 0249 "\n" 0250 "# Label the x and y axes with dark green text\n" 0251 "title(xlab=\"Days\", col.lab=rgb(0,0.5,0))\n" 0252 "title(ylab=\"Total\", col.lab=rgb(0,0.5,0))\n" 0253 "\n" 0254 "# Create a legend at (1, g_range[2]) that is slightly smaller \n" 0255 "# (cex) and uses the same line colors and points used by \n" 0256 "# the actual plots \n" 0257 "legend(1, g_range[2], c(\"cars\",\"trucks\"), cex=0.8, \n" 0258 " col=c(\"blue\",\"red\"), pch=21:22, lty=1:2);\n" 0259 ); 0260 0261 Cantor::Expression* e = evalExp(cmd); 0262 0263 QVERIFY(e != nullptr); 0264 QCOMPARE(e->status(), Cantor::Expression::Status::Done); 0265 QVERIFY(e->result() != nullptr); 0266 QCOMPARE(e->result()->type(), (int)Cantor::ImageResult::Type); 0267 evalExp(QLatin1String("rm(cars, trucks, g_range)")); 0268 } 0269 0270 void TestR::testHelpRequest() 0271 { 0272 QSKIP("Skip, until moving R help to help panel insteadof scripteditor"); 0273 Cantor::Expression* e = evalExp(QLatin1String("?print")); 0274 0275 QVERIFY(e != nullptr); 0276 QCOMPARE(e->status(), Cantor::Expression::Status::Done); 0277 QVERIFY(e->result() != nullptr); 0278 QCOMPARE(e->result()->type(), (int)Cantor::HelpResult::Type); 0279 } 0280 0281 void TestR::testSyntaxHelp() 0282 { 0283 QSKIP("Skip, until adding this feature to R backend"); 0284 Cantor::SyntaxHelpObject* help = session()->syntaxHelpFor(QLatin1String("filter")); 0285 help->fetchSyntaxHelp(); 0286 waitForSignal(help, SIGNAL(done())); 0287 0288 QVERIFY(help->toHtml().contains(QLatin1String("filter"))); 0289 } 0290 0291 void TestR::testInformationRequest() 0292 { 0293 Cantor::Expression* e=session()->evaluateExpression(QLatin1String("readline(prompt=\"Enter number: \")")); 0294 QVERIFY(e!=nullptr); 0295 waitForSignal(e, SIGNAL(needsAdditionalInformation(QString))); 0296 e->addInformation(QLatin1String("12")); 0297 0298 waitForSignal(e, SIGNAL(statusChanged(Cantor::Expression::Status))); 0299 QVERIFY(e->result()!=nullptr); 0300 0301 QCOMPARE(e->result()->data().toString(), QLatin1String("[1] \"12\"")); 0302 } 0303 0304 void TestR::testLoginLogout() 0305 { 0306 // Logout from session twice and all must works fine 0307 session()->logout(); 0308 session()->logout(); 0309 0310 // Login in session twice and all must works fine 0311 session()->login(); 0312 session()->login(); 0313 } 0314 0315 void TestR::testRestartWhileRunning() 0316 { 0317 Cantor::Expression* e1=session()->evaluateExpression(QLatin1String("Sys.sleep(5)")); 0318 0319 session()->logout(); 0320 QCOMPARE(e1->status(), Cantor::Expression::Interrupted); 0321 session()->login(); 0322 0323 Cantor::Expression* e2=evalExp( QLatin1String("2+2") ); 0324 0325 QVERIFY(e2 != nullptr); 0326 QVERIFY(e2->result() != nullptr); 0327 0328 QCOMPARE(cleanOutput(e2->result()->data().toString() ), QLatin1String("[1] 4")); 0329 } 0330 0331 QTEST_MAIN( TestR ) 0332