aboutsummaryrefslogtreecommitdiffstats
path: root/tools/snippets_translate/tests/test_converter.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/snippets_translate/tests/test_converter.py')
-rw-r--r--tools/snippets_translate/tests/test_converter.py481
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