diff options
Diffstat (limited to 'tools/snippets_translate/tests/test_converter.py')
-rw-r--r-- | tools/snippets_translate/tests/test_converter.py | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/tools/snippets_translate/tests/test_converter.py b/tools/snippets_translate/tests/test_converter.py new file mode 100644 index 000000000..084cc8a6d --- /dev/null +++ b/tools/snippets_translate/tests/test_converter.py @@ -0,0 +1,481 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +from converter import snippet_translate as st + + +def multi_st(lines): + result = [st(l) for l in lines.split("\n")] + return "\n".join(result) + + +def test_comments(): + assert st("// This is a comment") == "# This is a comment" + assert st("// double slash // inside") == "# double slash // inside" + + +def test_comments_eol(): + assert st("a = 1; // comment") == "a = 1 # comment" + assert st("while ( 1 != 1 ) { // comment") == "while 1 != 1: # comment" + + +def test_qdoc_snippets(): + assert st("//! [0]") == "//! [0]" + + +def test_arrow(): + assert st("label->setText('something')") == "label.setText('something')" + + +def test_curly_braces(): + assert st(" {") == "" + assert st("}") == "" + assert st("while (true){") == "while True:" + assert st("while (true) { ") == "while True:" + + +def test_inc_dec(): + assert st("++i;") == "i = i + 1" + assert st("i--;") == "i = i - 1" + + +def test_and_or(): + assert st("while (a && b)") == "while a and b:" + assert st("else if (a || b && c)") == "elif a or b and c:" + + +def test_while_if_elseif(): + assert st("while(a)") == "while a:" + assert st("if (condition){") == "if condition:" + assert st(" if (condition){") == " if condition:" + assert st("} else if (a) {") == " elif a:" + assert ( + st("if (!m_vbo.isCreated()) // init() failed,") + == "if not m_vbo.isCreated(): # init() failed," + ) + # Special case, second line from a condition + assert ( + st("&& event->answerRect().intersects(dropFrame->geometry()))") + == "and event.answerRect().intersects(dropFrame.geometry()))" + ) + + +def test_else(): + assert st("else") == "else:" + assert st("} else {") == "else:" + assert st("}else") == "else:" + assert st("else {") == "else:" + + +def test_new(): + assert st("a = new Something(...);") == "a = Something(...)" + assert st("a = new Something") == "a = Something()" + assert st("foo(new X, new Y(b), new Z)") == "foo(X(), Y(b), Z())" + # Class member initialization list + assert st("m_mem(new Something(p)),") == "m_mem(Something(p))," + assert st("m_mem(new Something),") == "m_mem(Something())," + + +def test_semicolon(): + assert st("a = 1;") == "a = 1" + assert st("};") == "" + + +def test_include(): + assert st('#include "something.h"') == "from something import *" + assert st("#include <QtCore>") == "from PySide6 import QtCore" + assert st("#include <QLabel>") == "from PySide6.QtWidgets import QLabel" + assert st("#include <NotQt>") == "" + assert st('#include strange"') == "" + + +def test_main(): + assert st("int main(int argc, char *argv[])") == 'if __name__ == "__main__":' + + +def test_cast(): + assert st("a = reinterpret_cast<type>(data);") == "a = type(data)" + assert st("a = reinterpret_cast<type*>(data) * 9;") == "a = type(data) * 9" + assert ( + st("elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;") + == "elapsed = (elapsed + QTimer(sender()).interval()) % 1000" + ) + assert ( + st("a = qobject_cast<type*>(data) * 9 + static_cast<int>(42)") + == "a = type(data) * 9 + int(42)" + ) + + +def test_double_colon(): + assert st("Qt::Align") == "Qt.Align" + assert st('QSound::play("mysounds/bells.wav");') == 'QSound.play("mysounds/bells.wav")' + assert st("Widget::method") == "Widget.method" + + # multiline statement connect statement + # eg: connect(reply, &QNetworkReply::errorOccurred, + # this, &MyClass::slotError); + assert st("this, &MyClass::slotError);") == "self.slotError)" + + +def test_connects(): + assert ( + st("connect(button, &QPushButton::clicked, this, &MyClass::slotClicked);") + == "button.clicked.connect(self.slotClicked)" + ) + assert ( + st("connect(m_ui->button, &QPushButton::clicked, this, &MyClass::slotClicked);") + == "m_ui.button.clicked.connect(self.slotClicked)" + ) + assert ( + st("connect(button.get(), &QPushButton::clicked, this, &MyClass::slotClicked);") + == "button.clicked.connect(self.slotClicked)" + ) + + +def test_cout_endl(): + assert st("cout << 'hello' << 'world' << endl") == "print('hello', 'world')" + assert st(" cout << 'hallo' << 'welt' << endl") == " print('hallo', 'welt')" + assert st("cout << 'hi'") == "print('hi')" + assert st("'world' << endl") == "print('world')" + + assert st("cout << circ.at(i) << endl;") == "print(circ.at(i))" + assert ( + st('cout << "Element name: " << qPrintable(e.tagName()) << "\n";') + == 'print("Element name: ", qPrintable(e.tagName()), "\n")' + ) + assert ( + st('cout << "First occurrence of Harumi is at position " << i << Qt::endl;') + == 'print("First occurrence of Harumi is at position ", i)' + ) + assert st('cout << "Found Jeanette" << endl;') == 'print("Found Jeanette")' + assert st('cout << "The key: " << it.key() << Qt::endl') == 'print("The key: ", it.key())' + assert ( + st("cout << (*constIterator).toLocal8Bit().constData() << Qt::endl;") + == "print((constIterator).toLocal8Bit().constData())" + ) + assert st("cout << ba[0]; // prints H") == "print(ba[0]) # prints H" + assert ( + st('cout << "Also the value: " << (*it) << Qt::endl;') == 'print("Also the value: ", (it))' + ) + assert st('cout << "[" << *data << "]" << Qt::endl;') == 'print("[", data, "]")' + + assert st('out << "Qt rocks!" << Qt::endl;') == 'print(out, "Qt rocks!")' + assert st(' std::cout << "MyObject::MyObject()\n";') == ' print("MyObject::MyObject()\n")' + assert st('qDebug() << "Retrieved:" << retrieved;') == 'print("Retrieved:", retrieved)' + + +def test_variable_declaration(): + assert st("QLabel label;") == "label = QLabel()" + assert st('QLabel label("Hello");') == 'label = QLabel("Hello")' + assert st("Widget w;") == "w = Widget()" + assert st('QLabel *label = new QLabel("Hello");') == 'label = QLabel("Hello")' + assert st('QLabel label = a_function("Hello");') == 'label = a_function("Hello")' + assert st('QString a = "something";') == 'a = "something"' + assert st("int var;") == "var = int()" + assert st("float v = 0.1;") == "v = 0.1" + assert st("QSome<thing> var;") == "var = QSome()" + assert st("QQueue<int> queue;") == "queue = QQueue()" + assert st("QVBoxLayout *layout = new QVBoxLayout;") == "layout = QVBoxLayout()" + assert st("QPointer<QLabel> label = new QLabel;") == "label = QLabel()" + assert st("QMatrix4x4 matrix;") == "matrix = QMatrix4x4()" + assert st("QList<QImage> collage =") == "collage =" + assert st("bool b = true;") == "b = True" + assert st("Q3DBars *m_graph = nullptr;") == "m_graph = None" + # Do not fall for member function definitions + assert st("Q3DBars *Graph::bars() const") == "Q3DBars Graph.bars()" + # Do not fall for member function declarations + assert st("virtual Q3DBars *bars();") == "virtual Q3DBars bars()" + + +def test_for(): + assert st("for (int i = 0; i < 10; i++)") == "for i in range(0, 10):" + assert st(" for (int i = 0; i < 10; i+=2)") == " for i in range(0, 10, 2):" + assert st("for (int i = 10; i >= 0; i-=2)") == "for i in range(-1, 10, -2):" + assert st("for (int i = 0; i < 10; ++i)") == "for i in range(0, 10):" + assert ( + st("for (int c = 0;" "c < model.columnCount();" "++c) {") + == "for c in range(0, model.columnCount()):" + ) + assert ( + st("for (int c = 0;" "c < table->columns();" "++c) {") + == "for c in range(0, table.columns()):" + ) + assert st("for (int i = 0; i <= 10; i++)") == "for i in range(0, 11):" + assert st("for (int i = 10; i >= 0; i--)") == "for i in range(-1, 10, -1):" + + ## if contains "begin()" and "end()", do a 'for it in var' + assert ( + st( + "for (QHash<int, QString>::const_iterator it = hash.cbegin()," + "end = hash.cend(); it != end; ++it)" + ) + == "for it in hash:" + ) + assert ( + st("for (QTextBlock it = doc->begin();" "it != doc->end(); it = it.next())") + == "for it in doc:" + ) + assert st("for (auto it = map.begin(); it != map.end(); ++it) {") == "for it in map:" + assert st("for (i = future.constBegin(); i != future.constEnd(); ++i)") == "for i in future:" + assert st("for (it = block.begin(); !(it.atEnd()); ++it) {") == "for it in block:" + assert ( + st(" for (it = snippetPaths.constBegin();" "it != snippetPaths.constEnd(); ++it)") + == " for it in snippetPaths:" + ) + + assert st("for (QChar ch : s)") == "for ch in s:" + assert ( + st("for (const QByteArray &ext : " "qAsConst(extensionList))") + == "for ext in extensionList:" + ) + assert st("for (QTreeWidgetItem *item : found) {") == "for item in found:" + + # TODO: Strange cases + # for ( ; it != end; ++it) { + # for (; !elt.isNull(); elt = elt.nextSiblingElement("entry")) { + # for (int i = 0; ids[i]; ++i) + # for (int i = 0; i < (1>>20); ++i) + # for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) + + +def test_emit(): + assert st("emit sliderPressed();") == "sliderPressed.emit()" + assert st("emit actionTriggered(action);") == "actionTriggered.emit(action)" + assert st("emit activeChanged(d->m_active);") == "activeChanged.emit(d.m_active)" + assert st("emit dataChanged(index, index);") == "dataChanged.emit(index, index)" + assert st("emit dataChanged(index, index, {role});") == "dataChanged.emit(index, index, {role})" + assert ( + st('emit dragResult(tr("The data was copied here."));') + == 'dragResult.emit(tr("The data was copied here."))' + ) + assert ( + st("emit mimeTypes(event->mimeData()->formats());") + == "mimeTypes.emit(event.mimeData().formats())" + ) + assert ( + st("emit q_ptr->averageFrequencyChanged(m_averageFrequency);") + == "q_ptr.averageFrequencyChanged.emit(m_averageFrequency)" + ) + assert st("emit q_ptr->frequencyChanged();") == "q_ptr.frequencyChanged.emit()" + assert ( + st("emit rangeChanged(d->minimum, d->maximum);") + == "rangeChanged.emit(d.minimum, d.maximum)" + ) + assert ( + st("emit sliderMoved((d->position = value));") == "sliderMoved.emit((d.position = value))" + ) + assert ( + st("emit stateChanged(QContactAction::FinishedState);") + == "stateChanged.emit(QContactAction.FinishedState)" + ) + assert st("emit textCompleted(lineEdit->text());") == "textCompleted.emit(lineEdit.text())" + assert ( + st("emit updateProgress(newstat, m_watcher->progressMaximum());") + == "updateProgress.emit(newstat, m_watcher.progressMaximum())" + ) + + +def test_void_functions(): + assert st("void Something::Method(int a, char *b) {") == "def Method(self, a, b):" + assert ( + st("void MainWindow::updateMenus(QListWidgetItem *current)") + == "def updateMenus(self, current):" + ) + assert ( + st("void MyScrollArea::scrollContentsBy(int dx, int dy)") + == "def scrollContentsBy(self, dx, dy):" + ) + assert st("void Wrapper::wrapper6() {") == "def wrapper6(self):" + assert st("void MyClass::setPriority(Priority) {}") == "def setPriority(self, Priority): pass" + assert st("void MyException::raise() const { throw *this; }") == "def raise(self): raise self" + assert st("void tst_Skip::test_data()") == "def test_data(self):" + assert st("void util_function_does_nothing()") == "def util_function_does_nothing():" + assert st("static inline void cleanup(MyCustomClass *pointer)") == "def cleanup(pointer):" + # TODO: Which name? + assert st("void RenderWindow::exposeEvent(QExposeEvent *)") == "def exposeEvent(self, arg__0):" + + +def test_classes(): + assert st("class MyWidget //: public QWidget") == "class MyWidget(): #: public QWidget" + assert st("class MyMfcView : public CView") == "class MyMfcView(CView):" + assert st("class MyGame : public QObject {") == "class MyGame(QObject):" + assert st("class tst_Skip") == "class tst_Skip():" + assert st("class A : public B, protected C") == "class A(B, C):" + assert st("class A : public B, public C") == "class A(B, C):" + assert st("class SomeTemplate<int> : public QFrame") == "class SomeTemplate(QFrame):" + # This is a tricky situation because it has a multi line dependency: + # class MyMemberSheetExtension : public QObject, + # public QDesignerMemberSheetExtension + # { + # we will use the leading comma to trust it's the previously situation. + assert st("class A : public QObject,") == "class A(QObject," + assert st("class B {...};") == "class B(): pass" + + +def test_constuctors(): + assert st("MyWidget::MyWidget(QWidget *parent)") == "def __init__(self, parent):" + assert st("Window::Window()") == "def __init__(self):" + + +def test_inheritance_init(): + assert ( + st(": QClass(fun(re, 1, 2), parent), a(1)") + == " super().__init__(fun(re, 1, 2), parent)\n self.a = 1" + ) + assert ( + st(": QQmlNdefRecord(copyFooRecord(record), parent)") + == " super().__init__(copyFooRecord(record), parent)" + ) + assert ( + st(" : QWidget(parent), helper(helper)") + == " super().__init__(parent)\n self.helper = helper" + ) + assert st(" : QWidget(parent)") == " super().__init__(parent)" + assert ( + st(": a(0), bB(99), cC2(1), p_S(10),") + == " self.a = 0\n self.bB = 99\n self.cC2 = 1\n self.p_S = 10" + ) + assert ( + st(": QAbstractFileEngineIterator(nameFilters, filters), index(0) ") + == " super().__init__(nameFilters, filters)\n self.index = 0" + ) + assert ( + st(": m_document(doc), m_text(text)") == " self.m_document = doc\n self.m_text = text" + ) + assert st(": m_size(size) { }") == " self.m_size = size" + assert ( + st(": option->palette.color(QPalette::Mid);") + == " self.option.palette.color = QPalette.Mid" + ) + assert st(": QSqlResult(driver) {}") == " super().__init__(driver)" + + +def test_arrays(): + assert st("static const GLfloat vertices[] = {") == "vertices = {" + assert st("static const char *greeting_strings[] = {") == "greeting_strings = {" + assert st("uchar arrow_bits[] = {0x3f, 0x1f, 0x0f}") == "arrow_bits = {0x3f, 0x1f, 0x0f}" + assert st("QList<int> vector { 1, 2, 3, 4 };") == "vector = { 1, 2, 3, 4 }" + + +def test_functions(): + assert st("int Class::method(a, b, c)") == "def method(self, a, b, c):" + assert st("QStringView Message::body() const") == "def body(self):" + assert st("void Ren::exEvent(QExp *)") == "def exEvent(self, arg__0):" + assert ( + st("QString myDecoderFunc(const QByteArray &localFileName);") + == "def myDecoderFunc(localFileName):" + ) + assert st("return QModelIndex();") == "return QModelIndex()" + + +def test_foreach(): + assert st("foreach (item, selected) {") == "for item in selected:" + assert st("foreach (const QVariant &v, iterable) {") == "for v in iterable:" + assert st("foreach (QObject *obj, list)") == "for obj in list:" + assert ( + st("foreach (const QContactTag& tag, contact.details<QContactTag>()) {") + == "for tag in contact.details():" + ) + + +def test_structs(): + assert st("struct ScopedPointerCustomDeleter") == "class ScopedPointerCustomDeleter():" + assert st("struct Wrapper : public QWidget {") == "class Wrapper(QWidget):" + assert st("struct Window {") == "class Window():" + + +def test_ternary_operator(): + assert st("int a = 1 ? b > 0 : 3") == "a = 1 if b > 0 else 3" + assert ( + st("if (!game.saveGame(json ? Game::Json : Game::Binary))") + == "if not game.saveGame(json if Game.Json else Game.Binary):" + ) + + +def test_useless_qt_classes(): + assert st('result += QLatin1String("; ");') == 'result += "; "' + assert st('result += QString::fromLatin1("; ");') == 'result += "; "' + assert ( + st('result = QStringLiteral("A") + QStringLiteral("B");') + == 'result = "A" + "B"') + assert st("<< QLatin1Char('\0') << endl;") == "print('\0')" + assert st('result = u"A"_s;') == 'result = "A"' + + +def test_special_cases(): + assert ( + st('http->setProxy("proxy.example.com", 3128);') + == 'http.setProxy("proxy.example.com", 3128)' + ) + assert st("delete something;") == "del something" + assert ( + st("m_program->setUniformValue(m_matrixUniform, matrix);") + == "m_program.setUniformValue(m_matrixUniform, matrix)" + ) + assert ( + st("QObject::connect(&window1, &Window::messageSent,") + == "window1.messageSent.connect(" + ) + assert st("double num;") == "num = float()" + + # Leave a comment to remember it comes from C++ + assert st("public:") == "# public" + assert st("private:") == "# private" + + #iterator declaration + assert st("std::vector<int>::iterator i;") == "" + + # TODO: Handle the existing ones with Python equivalents + # assert st("std::...") + + # FIXME: Maybe a better interpretation? + # assert st("QDebug operator<<(QDebug dbg, const Message &message)") == "def __str__(self):" + + # TODO: Maybe play with the format? + # assert st('m_o.append(tr("version: %1.%2").arg(a).arg(b))') == 'm_o.append(tr("version: {1}.{2}".format(a, b)' + + +def test_lambdas(): + # QtConcurrent::blockingMap(vector, [](int &x) { x *= 2; }); + + # QList<QImage> collage = QtConcurrent::mappedReduced(images, + # [&size](const QImage &image) { + # return image.scaled(size, size); + # }, + # addToCollage + # ).results(); + pass + + +def test_switch_case(): + source = """switch (v) { +case 1: + f1(); + break; +case ClassName::EnumValue: + f2(); + break; +default: + f3(); + break; +} +""" + expected = """ +if v == 1: + f1() + break +elif v == ClassName.EnumValue: + f2() + break +else: + f3() + break + +""" + + assert multi_st(source) == expected + + +def test_std_function(): + # std::function<QImage(const QImage &)> scale = [](const QImage &img) { + pass |