diff options
Diffstat (limited to 'util/cmake/tests')
37 files changed, 1179 insertions, 0 deletions
diff --git a/util/cmake/tests/__init__.py b/util/cmake/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/util/cmake/tests/__init__.py diff --git a/util/cmake/tests/data/comment_scope.pro b/util/cmake/tests/data/comment_scope.pro new file mode 100644 index 0000000000..be43cad37d --- /dev/null +++ b/util/cmake/tests/data/comment_scope.pro @@ -0,0 +1,6 @@ +# QtCore can't be compiled with -Wl,-no-undefined because it uses the "environ" +# variable and on FreeBSD and OpenBSD, this variable is in the final executable itself. +# OpenBSD 6.0 will include environ in libc. +freebsd|openbsd: QMAKE_LFLAGS_NOUNDEF = + +include(animation/animation.pri) diff --git a/util/cmake/tests/data/complex_assign.pro b/util/cmake/tests/data/complex_assign.pro new file mode 100644 index 0000000000..d251afcdd5 --- /dev/null +++ b/util/cmake/tests/data/complex_assign.pro @@ -0,0 +1,2 @@ +qmake-clean.commands += (cd qmake && $(MAKE) clean ":-(==)-:" '(Foo)' ) + diff --git a/util/cmake/tests/data/complex_condition.pro b/util/cmake/tests/data/complex_condition.pro new file mode 100644 index 0000000000..bc3369bd63 --- /dev/null +++ b/util/cmake/tests/data/complex_condition.pro @@ -0,0 +1,4 @@ +!system("dbus-send --session --type=signal / local.AutotestCheck.Hello >$$QMAKE_SYSTEM_NULL_DEVICE 2>&1") { + SOURCES = dbus.cpp +} + diff --git a/util/cmake/tests/data/complex_values.pro b/util/cmake/tests/data/complex_values.pro new file mode 100644 index 0000000000..4d747c1dd7 --- /dev/null +++ b/util/cmake/tests/data/complex_values.pro @@ -0,0 +1,22 @@ +linux:!static { + precompile_header { + # we'll get an error if we just use SOURCES += + no_pch_assembler.commands = $$QMAKE_CC -c $(CFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} + no_pch_assembler.dependency_type = TYPE_C + no_pch_assembler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} + no_pch_assembler.input = NO_PCH_ASM + no_pch_assembler.name = compiling[no_pch] ${QMAKE_FILE_IN} + silent: no_pch_assembler.commands = @echo compiling[no_pch] ${QMAKE_FILE_IN} && $$no_pch_assembler.commands + CMAKE_ANGLE_GLES2_IMPLIB_RELEASE = libGLESv2.$${QMAKE_EXTENSION_STATICLIB} + HOST_BINS = $$[QT_HOST_BINS] + CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/ + TR_EXCLUDE += ../3rdparty/* + + QMAKE_EXTRA_COMPILERS += no_pch_assembler + NO_PCH_ASM += global/minimum-linux.S + } else { + SOURCES += global/minimum-linux.S + } + HEADERS += global/minimum-linux_p.h +} + diff --git a/util/cmake/tests/data/condition_without_scope.pro b/util/cmake/tests/data/condition_without_scope.pro new file mode 100644 index 0000000000..2aa1237c12 --- /dev/null +++ b/util/cmake/tests/data/condition_without_scope.pro @@ -0,0 +1,2 @@ +write_file("a", contents)|error() + diff --git a/util/cmake/tests/data/contains_scope.pro b/util/cmake/tests/data/contains_scope.pro new file mode 100644 index 0000000000..0f51350a45 --- /dev/null +++ b/util/cmake/tests/data/contains_scope.pro @@ -0,0 +1,4 @@ +contains(DEFINES,QT_EVAL):include(eval.pri) + +HOST_BINS = $$[QT_HOST_BINS] + diff --git a/util/cmake/tests/data/definetest.pro b/util/cmake/tests/data/definetest.pro new file mode 100644 index 0000000000..76b63d239f --- /dev/null +++ b/util/cmake/tests/data/definetest.pro @@ -0,0 +1,6 @@ +defineTest(pathIsAbsolute) { + p = $$clean_path($$1) + !isEmpty(p):isEqual(p, $$absolute_path($$p)): return(true) + return(false) +} + diff --git a/util/cmake/tests/data/else.pro b/util/cmake/tests/data/else.pro new file mode 100644 index 0000000000..bbf9c5ac9f --- /dev/null +++ b/util/cmake/tests/data/else.pro @@ -0,0 +1,6 @@ + +linux { + SOURCES += a.cpp +} else { + SOURCES += b.cpp +} diff --git a/util/cmake/tests/data/else2.pro b/util/cmake/tests/data/else2.pro new file mode 100644 index 0000000000..f2ef36ec28 --- /dev/null +++ b/util/cmake/tests/data/else2.pro @@ -0,0 +1,4 @@ + +osx: A = 1 +else: win32: B = 2 +else: C = 3 diff --git a/util/cmake/tests/data/else3.pro b/util/cmake/tests/data/else3.pro new file mode 100644 index 0000000000..0de9c2c1d9 --- /dev/null +++ b/util/cmake/tests/data/else3.pro @@ -0,0 +1,7 @@ +qtConfig(timezone) { + A = 1 +} else:win32 { + B = 2 +} else { + C = 3 +} diff --git a/util/cmake/tests/data/else4.pro b/util/cmake/tests/data/else4.pro new file mode 100644 index 0000000000..9ed676ccfa --- /dev/null +++ b/util/cmake/tests/data/else4.pro @@ -0,0 +1,6 @@ +qtConfig(timezone) { + A = 1 +} else:win32: B = 2 +else { + C = 3 +} diff --git a/util/cmake/tests/data/else5.pro b/util/cmake/tests/data/else5.pro new file mode 100644 index 0000000000..3de76af50a --- /dev/null +++ b/util/cmake/tests/data/else5.pro @@ -0,0 +1,10 @@ +# comments +qtConfig(timezone) { # bar + A = 1 +} else:win32 { + B = 2 # foo +} else { C = 3 +# baz + # foobar +} +# endcomment diff --git a/util/cmake/tests/data/else6.pro b/util/cmake/tests/data/else6.pro new file mode 100644 index 0000000000..9eaa834a19 --- /dev/null +++ b/util/cmake/tests/data/else6.pro @@ -0,0 +1,11 @@ +qtConfig(timezone) \ +{ + A = \ +1 +} \ +else:win32: \ +B = 2 +else: \ + C \ += 3 + diff --git a/util/cmake/tests/data/else7.pro b/util/cmake/tests/data/else7.pro new file mode 100644 index 0000000000..e663b1c05e --- /dev/null +++ b/util/cmake/tests/data/else7.pro @@ -0,0 +1,2 @@ +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x65000000 + diff --git a/util/cmake/tests/data/else8.pro b/util/cmake/tests/data/else8.pro new file mode 100644 index 0000000000..6d4d5f01ed --- /dev/null +++ b/util/cmake/tests/data/else8.pro @@ -0,0 +1,5 @@ +qtConfig(timezone) { A = 1 } else:win32: {\ +B = 2 \ +} else: \ + C \ += 3 \ diff --git a/util/cmake/tests/data/escaped_value.pro b/util/cmake/tests/data/escaped_value.pro new file mode 100644 index 0000000000..7c95b1fc30 --- /dev/null +++ b/util/cmake/tests/data/escaped_value.pro @@ -0,0 +1,2 @@ +MODULE_AUX_INCLUDES = \ + \$\$QT_MODULE_INCLUDE_BASE/QtANGLE diff --git a/util/cmake/tests/data/for.pro b/util/cmake/tests/data/for.pro new file mode 100644 index 0000000000..5751432980 --- /dev/null +++ b/util/cmake/tests/data/for.pro @@ -0,0 +1,11 @@ +SOURCES = main.cpp +for (config, SIMD) { + uc = $$upper($$config) + DEFINES += QT_COMPILER_SUPPORTS_$${uc} + + add_cflags { + cflags = QMAKE_CFLAGS_$${uc} + !defined($$cflags, var): error("This compiler does not support $${uc}") + QMAKE_CXXFLAGS += $$eval($$cflags) + } +} diff --git a/util/cmake/tests/data/function_if.pro b/util/cmake/tests/data/function_if.pro new file mode 100644 index 0000000000..9af018f864 --- /dev/null +++ b/util/cmake/tests/data/function_if.pro @@ -0,0 +1,4 @@ +pathIsAbsolute($$CMAKE_HOST_DATA_DIR) { + CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/ +} + diff --git a/util/cmake/tests/data/include.pro b/util/cmake/tests/data/include.pro new file mode 100644 index 0000000000..22d8a40919 --- /dev/null +++ b/util/cmake/tests/data/include.pro @@ -0,0 +1,3 @@ +A = 42 +include(foo) # load foo +B=23 diff --git a/util/cmake/tests/data/lc.pro b/util/cmake/tests/data/lc.pro new file mode 100644 index 0000000000..def80e7c95 --- /dev/null +++ b/util/cmake/tests/data/lc.pro @@ -0,0 +1,10 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qmacstyle \ + qstyle \ + qstyleoption \ + qstylesheetstyle \ + +!qtConfig(private_tests): SUBDIRS -= \ + qstylesheetstyle \ + diff --git a/util/cmake/tests/data/lc_with_comment.pro b/util/cmake/tests/data/lc_with_comment.pro new file mode 100644 index 0000000000..176913dfc8 --- /dev/null +++ b/util/cmake/tests/data/lc_with_comment.pro @@ -0,0 +1,22 @@ +SUBDIRS = \ +# dds \ + tga \ + wbmp + +MYVAR = foo # comment +MYVAR = foo2# comment +MYVAR = foo3# comment # + +MYVAR = foo4# comment # + +## +# +# +## + + # + # +# + # # + +MYVAR = foo5# comment # # diff --git a/util/cmake/tests/data/load.pro b/util/cmake/tests/data/load.pro new file mode 100644 index 0000000000..c9717e9832 --- /dev/null +++ b/util/cmake/tests/data/load.pro @@ -0,0 +1,3 @@ +A = 42 +load(foo)# load foo +B=23 diff --git a/util/cmake/tests/data/multi_condition_divided_by_lc.pro b/util/cmake/tests/data/multi_condition_divided_by_lc.pro new file mode 100644 index 0000000000..23254231df --- /dev/null +++ b/util/cmake/tests/data/multi_condition_divided_by_lc.pro @@ -0,0 +1,3 @@ +equals(a): \ + greaterThan(a):flags += 1 + diff --git a/util/cmake/tests/data/multiline_assign.pro b/util/cmake/tests/data/multiline_assign.pro new file mode 100644 index 0000000000..42a3d0a674 --- /dev/null +++ b/util/cmake/tests/data/multiline_assign.pro @@ -0,0 +1,4 @@ +A = 42 \ + 43 \ + 44 +B=23 diff --git a/util/cmake/tests/data/nested_function_calls.pro b/util/cmake/tests/data/nested_function_calls.pro new file mode 100644 index 0000000000..5ecc53f1cc --- /dev/null +++ b/util/cmake/tests/data/nested_function_calls.pro @@ -0,0 +1,2 @@ +requires(qtConfig(dlopen)) + diff --git a/util/cmake/tests/data/quoted.pro b/util/cmake/tests/data/quoted.pro new file mode 100644 index 0000000000..61682aa0d0 --- /dev/null +++ b/util/cmake/tests/data/quoted.pro @@ -0,0 +1,5 @@ +if(linux*|hurd*):!cross_compile:!static:!*-armcc* { + prog=$$quote(if (/program interpreter: (.*)]/) { print $1; }) + DEFINES += ELF_INTERPRETER=\\\"$$system(LC_ALL=C readelf -l /bin/ls | perl -n -e \'$$prog\')\\\" +} + diff --git a/util/cmake/tests/data/single_line_for.pro b/util/cmake/tests/data/single_line_for.pro new file mode 100644 index 0000000000..806d08a49c --- /dev/null +++ b/util/cmake/tests/data/single_line_for.pro @@ -0,0 +1,4 @@ +for(d, sd): \ + exists($$d/$${d}.pro): \ + SUBDIRS += $$d + diff --git a/util/cmake/tests/data/sql.pro b/util/cmake/tests/data/sql.pro new file mode 100644 index 0000000000..a9d7fc7c5a --- /dev/null +++ b/util/cmake/tests/data/sql.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = \ + kernel \ diff --git a/util/cmake/tests/data/standardpaths.pro b/util/cmake/tests/data/standardpaths.pro new file mode 100644 index 0000000000..4b45788e4f --- /dev/null +++ b/util/cmake/tests/data/standardpaths.pro @@ -0,0 +1,17 @@ +win32 { + !winrt { + SOURCES +=io/qstandardpaths_win.cpp + } else { + SOURCES +=io/qstandardpaths_winrt.cpp + } +} else:unix { + mac { + OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm + } else:android:!android-embedded { + SOURCES += io/qstandardpaths_android.cpp + } else:haiku { + SOURCES += io/qstandardpaths_haiku.cpp + } else { + SOURCES += io/qstandardpaths_unix.cpp + } +} diff --git a/util/cmake/tests/data/unset.pro b/util/cmake/tests/data/unset.pro new file mode 100644 index 0000000000..7ffb0582f1 --- /dev/null +++ b/util/cmake/tests/data/unset.pro @@ -0,0 +1,2 @@ +unset(f16c_cxx) + diff --git a/util/cmake/tests/data/value_function.pro b/util/cmake/tests/data/value_function.pro new file mode 100644 index 0000000000..598e4fadbd --- /dev/null +++ b/util/cmake/tests/data/value_function.pro @@ -0,0 +1,2 @@ +TARGET = Dummy +TARGET = $$qtLibraryTarget($$TARGET) diff --git a/util/cmake/tests/test_lc_fixup.py b/util/cmake/tests/test_lc_fixup.py new file mode 100755 index 0000000000..42094a5288 --- /dev/null +++ b/util/cmake/tests/test_lc_fixup.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the plugins of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from qmake_parser import fixup_linecontinuation + + +def test_no_change(): + input = "test \\\nline2\n line3" + output = "test line2\n line3" + result = fixup_linecontinuation(input) + assert output == result + + +def test_fix(): + input = "test \\\t\nline2\\\n line3\\ \nline4 \\ \t\nline5\\\n\n\n" + output = "test line2 line3 line4 line5 \n\n" + result = fixup_linecontinuation(input) + assert output == result diff --git a/util/cmake/tests/test_logic_mapping.py b/util/cmake/tests/test_logic_mapping.py new file mode 100755 index 0000000000..c18c3ddc65 --- /dev/null +++ b/util/cmake/tests/test_logic_mapping.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the plugins of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from condition_simplifier import simplify_condition + + +def validate_simplify(input: str, expected: str) -> None: + output = simplify_condition(input) + assert output == expected + + +def validate_simplify_unchanged(input: str) -> None: + validate_simplify(input, input) + + +def test_simplify_on(): + validate_simplify_unchanged('ON') + + +def test_simplify_off(): + validate_simplify_unchanged('OFF') + + +def test_simplify_not_on(): + validate_simplify('NOT ON', 'OFF') + + +def test_simplify_not_off(): + validate_simplify('NOT OFF', 'ON') + + +def test_simplify_isEmpty(): + validate_simplify_unchanged('isEmpty(foo)') + + +def test_simplify_not_isEmpty(): + validate_simplify_unchanged('NOT isEmpty(foo)') + + +def test_simplify_simple_and(): + validate_simplify_unchanged('QT_FEATURE_bar AND QT_FEATURE_foo') + + +def test_simplify_simple_or(): + validate_simplify_unchanged('QT_FEATURE_bar OR QT_FEATURE_foo') + + +def test_simplify_simple_not(): + validate_simplify_unchanged('NOT QT_FEATURE_foo') + + +def test_simplify_simple_and_reorder(): + validate_simplify('QT_FEATURE_foo AND QT_FEATURE_bar', 'QT_FEATURE_bar AND QT_FEATURE_foo') + + +def test_simplify_simple_or_reorder(): + validate_simplify('QT_FEATURE_foo OR QT_FEATURE_bar', 'QT_FEATURE_bar OR QT_FEATURE_foo') + + +def test_simplify_unix_or_win32(): + validate_simplify('WIN32 OR UNIX', 'ON') + + +def test_simplify_unix_or_win32_or_foobar_or_barfoo(): + validate_simplify('WIN32 OR UNIX OR foobar OR barfoo', 'ON') + + +def test_simplify_not_not_bar(): + validate_simplify(' NOT NOT bar ', 'bar') + + +def test_simplify_not_unix(): + validate_simplify('NOT UNIX', 'WIN32') + + +def test_simplify_not_win32(): + validate_simplify('NOT WIN32', 'UNIX') + + +def test_simplify_unix_and_win32(): + validate_simplify('WIN32 AND UNIX', 'OFF') + + +def test_simplify_unix_or_win32(): + validate_simplify('WIN32 OR UNIX', 'ON') + + +def test_simplify_unix_and_win32_or_foobar_or_barfoo(): + validate_simplify('WIN32 AND foobar AND UNIX AND barfoo', 'OFF') + + +def test_simplify_watchos_and_win32(): + validate_simplify('APPLE_WATCHOS AND WIN32', 'OFF') + + +def test_simplify_win32_and_watchos(): + validate_simplify('WIN32 AND APPLE_WATCHOS', 'OFF') + + +def test_simplify_apple_and_appleosx(): + validate_simplify('APPLE AND APPLE_OSX', 'APPLE_OSX') + + +def test_simplify_apple_or_appleosx(): + validate_simplify('APPLE OR APPLE_OSX', 'APPLE') + + +def test_simplify_apple_or_appleosx_level1(): + validate_simplify('foobar AND (APPLE OR APPLE_OSX )', 'APPLE AND foobar') + + +def test_simplify_apple_or_appleosx_level1_double(): + validate_simplify('foobar AND (APPLE OR APPLE_OSX )', 'APPLE AND foobar') + + +def test_simplify_apple_or_appleosx_level1_double_with_extra_spaces(): + validate_simplify('foobar AND (APPLE OR APPLE_OSX ) ' + 'AND ( APPLE_OSX OR APPLE )', 'APPLE AND foobar') + + +def test_simplify_apple_or_appleosx_level2(): + validate_simplify('foobar AND ( ( APPLE OR APPLE_WATCHOS ) ' + 'OR APPLE_OSX ) AND ( APPLE_OSX OR APPLE ) ' + 'AND ( (WIN32 OR WINRT) OR UNIX) ', 'APPLE AND foobar') + + +def test_simplify_not_apple_and_appleosx(): + validate_simplify('NOT APPLE AND APPLE_OSX', 'OFF') + + +def test_simplify_unix_and_bar_or_win32(): + validate_simplify('WIN32 AND bar AND UNIX', 'OFF') + + +def test_simplify_unix_or_bar_or_win32(): + validate_simplify('WIN32 OR bar OR UNIX', 'ON') + + +def test_simplify_complex_true(): + validate_simplify('WIN32 OR ( APPLE OR UNIX)', 'ON') + + +def test_simplify_apple_unix_freebsd(): + validate_simplify('( APPLE OR ( UNIX OR FREEBSD ))', 'UNIX') + + +def test_simplify_apple_unix_freebsd_foobar(): + validate_simplify('( APPLE OR ( UNIX OR FREEBSD ) OR foobar)', + 'UNIX OR foobar') + + +def test_simplify_complex_false(): + validate_simplify('WIN32 AND foobar AND ( ' + 'APPLE OR ( UNIX OR FREEBSD ))', + 'OFF') + + +def test_simplify_android_not_apple(): + validate_simplify('ANDROID AND NOT ANDROID_EMBEDDED AND NOT APPLE_OSX', + 'ANDROID AND NOT ANDROID_EMBEDDED') diff --git a/util/cmake/tests/test_operations.py b/util/cmake/tests/test_operations.py new file mode 100755 index 0000000000..c1e5f1b250 --- /dev/null +++ b/util/cmake/tests/test_operations.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the plugins of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from pro2cmake import AddOperation, SetOperation, UniqueAddOperation, RemoveOperation + +def test_add_operation(): + op = AddOperation(['bar', 'buz']) + + result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x) + assert ['foo', 'bar', 'bar', 'buz'] == result + + +def test_uniqueadd_operation(): + op = UniqueAddOperation(['bar', 'buz']) + + result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x) + assert ['foo', 'bar', 'buz'] == result + + +def test_set_operation(): + op = SetOperation(['bar', 'buz']) + + result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x) + assert ['bar', 'buz'] == result + + +def test_remove_operation(): + op = RemoveOperation(['bar', 'buz']) + + result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x) + assert ['foo', '-buz'] == result diff --git a/util/cmake/tests/test_parsing.py b/util/cmake/tests/test_parsing.py new file mode 100755 index 0000000000..95653dc39d --- /dev/null +++ b/util/cmake/tests/test_parsing.py @@ -0,0 +1,352 @@ +#!/usr/bin/env python3 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the plugins of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +import os +from qmake_parser import QmakeParser + + +_tests_path = os.path.dirname(os.path.abspath(__file__)) + + +def validate_op(key, op, value, to_validate): + assert key == to_validate['key'] + assert op == to_validate['operation'] + assert value == to_validate.get('value', None) + + +def validate_single_op(key, op, value, to_validate): + assert len(to_validate) == 1 + validate_op(key, op, value, to_validate[0]) + + +def evaluate_condition(to_validate): + assert 'condition' in to_validate + assert 'statements' in to_validate + + return (to_validate['condition'], + to_validate['statements'], + to_validate.get('else_statements', {})) + + +def validate_default_else_test(file_name): + result = parse_file(file_name) + assert len(result) == 1 + + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + assert cond == 'qtConfig(timezone)' + validate_single_op('A', '=', ['1'], if_branch) + + assert len(else_branch) == 1 + (cond2, if2_branch, else2_branch) = evaluate_condition(else_branch[0]) + assert cond2 == 'win32' + validate_single_op('B', '=', ['2'], if2_branch) + validate_single_op('C', '=', ['3'], else2_branch) + + +def parse_file(file): + p = QmakeParser(debug=True) + result = p.parseFile(file) + + print('\n\n#### Parser result:') + print(result) + print('\n#### End of parser result.\n') + + print('\n\n####Parser result dictionary:') + print(result.asDict()) + print('\n#### End of parser result dictionary.\n') + + result_dictionary = result.asDict() + + assert len(result_dictionary) == 1 + + return result_dictionary['statements'] + + +def test_else(): + result = parse_file(_tests_path + '/data/else.pro') + assert len(result) == 1 + + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + + assert cond == 'linux' + validate_single_op('SOURCES', '+=', ['a.cpp'], if_branch) + validate_single_op('SOURCES', '+=', ['b.cpp'], else_branch) + + +def test_else2(): + result = parse_file(_tests_path + '/data/else2.pro') + assert len(result) == 1 + + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + assert cond == 'osx' + validate_single_op('A', '=', ['1'], if_branch) + + assert len(else_branch) == 1 + (cond2, if2_branch, else2_branch) = evaluate_condition(else_branch[0]) + assert cond2 == 'win32' + validate_single_op('B', '=', ['2'], if2_branch) + + validate_single_op('C', '=', ['3'], else2_branch) + + +def test_else3(): + validate_default_else_test(_tests_path + '/data/else3.pro') + + +def test_else4(): + validate_default_else_test(_tests_path + '/data/else4.pro') + + +def test_else5(): + validate_default_else_test(_tests_path + '/data/else5.pro') + + +def test_else6(): + validate_default_else_test(_tests_path + '/data/else6.pro') + + +def test_else7(): + result = parse_file(_tests_path + '/data/else7.pro') + assert len(result) == 1 + + +def test_else8(): + validate_default_else_test(_tests_path + '/data/else8.pro') + + +def test_multiline_assign(): + result = parse_file(_tests_path + '/data/multiline_assign.pro') + assert len(result) == 2 + validate_op('A', '=', ['42', '43', '44'], result[0]) + validate_op('B', '=', ['23'], result[1]) + + +def test_include(): + result = parse_file(_tests_path + '/data/include.pro') + assert len(result) == 3 + validate_op('A', '=', ['42'], result[0]) + include = result[1] + assert len(include) == 1 + assert include.get('included', '') == 'foo' + validate_op('B', '=', ['23'], result[2]) + + +def test_load(): + result = parse_file(_tests_path + '/data/load.pro') + assert len(result) == 3 + validate_op('A', '=', ['42'], result[0]) + load = result[1] + assert len(load) == 1 + assert load.get('loaded', '') == 'foo' + validate_op('B', '=', ['23'], result[2]) + + +def test_definetest(): + result = parse_file(_tests_path + '/data/definetest.pro') + assert len(result) == 1 + assert result[0] == [] + + +def test_for(): + result = parse_file(_tests_path + '/data/for.pro') + assert len(result) == 2 + validate_op('SOURCES', '=', ['main.cpp'], result[0]) + assert result[1] == [] + + +def test_single_line_for(): + result = parse_file(_tests_path + '/data/single_line_for.pro') + assert len(result) == 1 + assert result[0] == [] + + +def test_unset(): + result = parse_file(_tests_path + '/data/unset.pro') + assert len(result) == 1 + assert result[0] == [] + + +def test_quoted(): + result = parse_file(_tests_path + '/data/quoted.pro') + assert len(result) == 1 + + +def test_complex_values(): + result = parse_file(_tests_path + '/data/complex_values.pro') + assert len(result) == 1 + + +def test_function_if(): + result = parse_file(_tests_path + '/data/function_if.pro') + assert len(result) == 1 + + +def test_realworld_standardpaths(): + result = parse_file(_tests_path + '/data/standardpaths.pro') + + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + assert cond == 'win32' + assert len(if_branch) == 1 + assert len(else_branch) == 1 + + # win32: + (cond1, if_branch1, else_branch1) = evaluate_condition(if_branch[0]) + assert cond1 == '!winrt' + assert len(if_branch1) == 1 + validate_op('SOURCES', '+=', ['io/qstandardpaths_win.cpp'], if_branch1[0]) + assert len(else_branch1) == 1 + validate_op('SOURCES', '+=', ['io/qstandardpaths_winrt.cpp'], else_branch1[0]) + + # unix: + (cond2, if_branch2, else_branch2) = evaluate_condition(else_branch[0]) + assert cond2 == 'unix' + assert len(if_branch2) == 1 + assert len(else_branch2) == 0 + + # mac / else: + (cond3, if_branch3, else_branch3) = evaluate_condition(if_branch2[0]) + assert cond3 == 'mac' + assert len(if_branch3) == 1 + validate_op('OBJECTIVE_SOURCES', '+=', ['io/qstandardpaths_mac.mm'], if_branch3[0]) + assert len(else_branch3) == 1 + + # android / else: + (cond4, if_branch4, else_branch4) = evaluate_condition(else_branch3[0]) + assert cond4 == 'android && !android-embedded' + assert len(if_branch4) == 1 + validate_op('SOURCES', '+=', ['io/qstandardpaths_android.cpp'], if_branch4[0]) + assert len(else_branch4) == 1 + + # haiku / else: + (cond5, if_branch5, else_branch5) = evaluate_condition(else_branch4[0]) + assert cond5 == 'haiku' + assert len(if_branch5) == 1 + validate_op('SOURCES', '+=', ['io/qstandardpaths_haiku.cpp'], if_branch5[0]) + assert len(else_branch5) == 1 + validate_op('SOURCES', '+=', ['io/qstandardpaths_unix.cpp'], else_branch5[0]) + + +def test_realworld_comment_scope(): + result = parse_file(_tests_path + '/data/comment_scope.pro') + assert len(result) == 2 + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + assert cond == 'freebsd|openbsd' + assert len(if_branch) == 1 + validate_op('QMAKE_LFLAGS_NOUNDEF', '=', None, if_branch[0]) + + assert result[1].get('included', '') == 'animation/animation.pri' + + +def test_realworld_contains_scope(): + result = parse_file(_tests_path + '/data/contains_scope.pro') + assert len(result) == 2 + + +def test_realworld_complex_assign(): + result = parse_file(_tests_path + '/data/complex_assign.pro') + assert len(result) == 1 + validate_op('qmake-clean.commands', '+=', '( cd qmake && $(MAKE) clean ":-(==)-:" \'(Foo)\' )'.split(), + result[0]) + + +def test_realworld_complex_condition(): + result = parse_file(_tests_path + '/data/complex_condition.pro') + assert len(result) == 1 + (cond, if_branch, else_branch) = evaluate_condition(result[0]) + assert cond == '!system("dbus-send --session --type=signal / ' \ + 'local.AutotestCheck.Hello >$$QMAKE_SYSTEM_NULL_DEVICE ' \ + '2>&1")' + assert len(if_branch) == 1 + validate_op('SOURCES', '=', ['dbus.cpp'], if_branch[0]) + + assert len(else_branch) == 0 + + +def test_realworld_sql(): + result = parse_file(_tests_path + '/data/sql.pro') + assert len(result) == 2 + validate_op('TEMPLATE', '=', ['subdirs'], result[0]) + validate_op('SUBDIRS', '=', ['kernel'], result[1]) + + +def test_realworld_qtconfig(): + result = parse_file(_tests_path + '/data/escaped_value.pro') + assert len(result) == 1 + validate_op('MODULE_AUX_INCLUDES', '=', ['\\$\\$QT_MODULE_INCLUDE_BASE/QtANGLE'], result[0]) + + +def test_realworld_lc(): + result = parse_file(_tests_path + '/data/lc.pro') + assert len(result) == 3 + + +def test_realworld_lc_with_comment_in_between(): + result = parse_file(_tests_path + '/data/lc_with_comment.pro') + + my_var = result[1]['value'][0] + assert my_var == 'foo' + + my_var = result[2]['value'][0] + assert my_var == 'foo2' + + my_var = result[3]['value'][0] + assert my_var == 'foo3' + + my_var = result[4]['value'][0] + assert my_var == 'foo4' + + my_var = result[5]['value'][0] + assert my_var == 'foo5' + + sub_dirs = result[0]['value'] + assert sub_dirs[0] == 'tga' + assert sub_dirs[1] == 'wbmp' + assert len(result) == 6 + + +def test_condition_without_scope(): + result = parse_file(_tests_path + '/data/condition_without_scope.pro') + assert len(result) == 1 + + +def test_multi_condition_divided_by_lc(): + result = parse_file(_tests_path + '/data/multi_condition_divided_by_lc.pro') + assert len(result) == 1 + + +def test_nested_function_calls(): + result = parse_file(_tests_path + '/data/nested_function_calls.pro') + assert len(result) == 1 + +def test_value_function(): + result = parse_file(_tests_path + '/data/value_function.pro') + target = result[0]['value'][0] + assert target == 'Dummy' + value = result[1]['value'] + assert value[0] == '$$TARGET' diff --git a/util/cmake/tests/test_scope_handling.py b/util/cmake/tests/test_scope_handling.py new file mode 100755 index 0000000000..1db8b2a079 --- /dev/null +++ b/util/cmake/tests/test_scope_handling.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the plugins of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from pro2cmake import Scope, SetOperation, merge_scopes, recursive_evaluate_scope + +import pytest +import typing + +ScopeList = typing.List[Scope] + +def _map_to_operation(**kwargs): + result = {} # type: typing.Mapping[str, typing.List[SetOperation]] + for (key, value) in kwargs.items(): + result[key] = [SetOperation([value])] + return result + + +def _new_scope(*, parent_scope=None, condition='', **kwargs) -> Scope: + return Scope(parent_scope=parent_scope, + qmake_file='file1', condition=condition, operations=_map_to_operation(**kwargs)) + + +def _evaluate_scopes(scopes: ScopeList) -> ScopeList: + for s in scopes: + if not s.parent: + recursive_evaluate_scope(s) + return scopes + + +def _validate(input_scopes: ScopeList, output_scopes: ScopeList): + merged_scopes = merge_scopes(input_scopes) + assert merged_scopes == output_scopes + + +def test_evaluate_one_scope(): + scope = _new_scope(condition='QT_FEATURE_foo', test1='bar') + + input_scope = scope + recursive_evaluate_scope(scope) + assert scope == input_scope + + +def test_evaluate_child_scope(): + scope = _new_scope(condition='QT_FEATURE_foo', test1='bar') + _new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar') + + input_scope = scope + recursive_evaluate_scope(scope) + + assert scope.total_condition == 'QT_FEATURE_foo' + assert len(scope.children) == 1 + assert scope.get_string('test1') == 'bar' + assert scope.get_string('test2', 'not found') == 'not found' + + child = scope.children[0] + assert child.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo' + assert child.get_string('test1', 'not found') == 'not found' + assert child.get_string('test2') == 'bar' + + +def test_evaluate_two_child_scopes(): + scope = _new_scope(condition='QT_FEATURE_foo', test1='bar') + _new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar') + _new_scope(parent_scope=scope, condition='QT_FEATURE_buz', test3='buz') + + input_scope = scope + recursive_evaluate_scope(scope) + + assert scope.total_condition == 'QT_FEATURE_foo' + assert len(scope.children) == 2 + assert scope.get_string('test1') == 'bar' + assert scope.get_string('test2', 'not found') == 'not found' + assert scope.get_string('test3', 'not found') == 'not found' + + child1 = scope.children[0] + assert child1.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo' + assert child1.get_string('test1', 'not found') == 'not found' + assert child1.get_string('test2') == 'bar' + assert child1.get_string('test3', 'not found') == 'not found' + + child2 = scope.children[1] + assert child2.total_condition == 'QT_FEATURE_buz AND QT_FEATURE_foo' + assert child2.get_string('test1', 'not found') == 'not found' + assert child2.get_string('test2') == '' + assert child2.get_string('test3', 'not found') == 'buz' + + +def test_evaluate_else_child_scopes(): + scope = _new_scope(condition='QT_FEATURE_foo', test1='bar') + _new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar') + _new_scope(parent_scope=scope, condition='else', test3='buz') + + input_scope = scope + recursive_evaluate_scope(scope) + + assert scope.total_condition == 'QT_FEATURE_foo' + assert len(scope.children) == 2 + assert scope.get_string('test1') == 'bar' + assert scope.get_string('test2', 'not found') == 'not found' + assert scope.get_string('test3', 'not found') == 'not found' + + child1 = scope.children[0] + assert child1.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo' + assert child1.get_string('test1', 'not found') == 'not found' + assert child1.get_string('test2') == 'bar' + assert child1.get_string('test3', 'not found') == 'not found' + + child2 = scope.children[1] + assert child2.total_condition == 'QT_FEATURE_foo AND NOT QT_FEATURE_bar' + assert child2.get_string('test1', 'not found') == 'not found' + assert child2.get_string('test2') == '' + assert child2.get_string('test3', 'not found') == 'buz' + + +def test_evaluate_invalid_else_child_scopes(): + scope = _new_scope(condition='QT_FEATURE_foo', test1='bar') + _new_scope(parent_scope=scope, condition='else', test3='buz') + _new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar') + + input_scope = scope + with pytest.raises(AssertionError): + recursive_evaluate_scope(scope) + + +def test_merge_empty_scope_list(): + _validate([], []) + + +def test_merge_one_scope(): + scopes = [_new_scope(test='foo')] + + recursive_evaluate_scope(scopes[0]) + + _validate(scopes, scopes) + + +def test_merge_one_on_scope(): + scopes = [_new_scope(condition='ON', test='foo')] + + recursive_evaluate_scope(scopes[0]) + + _validate(scopes, scopes) + + +def test_merge_one_off_scope(): + scopes = [_new_scope(condition='OFF', test='foo')] + + recursive_evaluate_scope(scopes[0]) + + _validate(scopes, []) + + +def test_merge_one_conditioned_scope(): + scopes = [_new_scope(condition='QT_FEATURE_foo', test='foo')] + + recursive_evaluate_scope(scopes[0]) + + _validate(scopes, scopes) + + +def test_merge_two_scopes_with_same_condition(): + scopes = [_new_scope(condition='QT_FEATURE_bar', test='foo'), + _new_scope(condition='QT_FEATURE_bar', test2='bar')] + + recursive_evaluate_scope(scopes[0]) + recursive_evaluate_scope(scopes[1]) + + result = merge_scopes(scopes) + + assert len(result) == 1 + r0 = result[0] + assert r0.total_condition == 'QT_FEATURE_bar' + assert r0.get_string('test') == 'foo' + assert r0.get_string('test2') == 'bar' + + +def test_merge_three_scopes_two_with_same_condition(): + scopes = [_new_scope(condition='QT_FEATURE_bar', test='foo'), + _new_scope(condition='QT_FEATURE_baz', test1='buz'), + _new_scope(condition='QT_FEATURE_bar', test2='bar')] + + recursive_evaluate_scope(scopes[0]) + recursive_evaluate_scope(scopes[1]) + recursive_evaluate_scope(scopes[2]) + + result = merge_scopes(scopes) + + assert len(result) == 2 + r0 = result[0] + assert r0.total_condition == 'QT_FEATURE_bar' + assert r0.get_string('test') == 'foo' + assert r0.get_string('test2') == 'bar' + + assert result[1] == scopes[1] + + +def test_merge_two_unrelated_on_off_scopes(): + scopes = [_new_scope(condition='ON', test='foo'), + _new_scope(condition='OFF', test2='bar')] + + recursive_evaluate_scope(scopes[0]) + recursive_evaluate_scope(scopes[1]) + + _validate(scopes, [scopes[0]]) + + +def test_merge_two_unrelated_on_off_scopes(): + scopes = [_new_scope(condition='OFF', test='foo'), + _new_scope(condition='ON', test2='bar')] + + recursive_evaluate_scope(scopes[0]) + recursive_evaluate_scope(scopes[1]) + + _validate(scopes, [scopes[1]]) + + +def test_merge_parent_child_scopes_with_different_conditions(): + scope = _new_scope(condition='FOO', test1='parent') + scopes = [scope, _new_scope(parent_scope=scope, condition='bar', test2='child')] + + recursive_evaluate_scope(scope) + + _validate(scopes, scopes) + + +def test_merge_parent_child_scopes_with_same_conditions(): + scope = _new_scope(condition='FOO AND bar', test1='parent') + scopes = [scope, _new_scope(parent_scope=scope, condition='FOO AND bar', test2='child')] + + recursive_evaluate_scope(scope) + + result = merge_scopes(scopes) + + assert len(result) == 1 + r0 = result[0] + assert r0.parent == None + assert r0.total_condition == 'FOO AND bar' + assert r0.get_string('test1') == 'parent' + assert r0.get_string('test2') == 'child' + + +def test_merge_parent_child_scopes_with_on_child_condition(): + scope = _new_scope(condition='FOO AND bar', test1='parent') + scopes = [scope, _new_scope(parent_scope=scope, condition='ON', test2='child')] + + recursive_evaluate_scope(scope) + + result = merge_scopes(scopes) + + assert len(result) == 1 + r0 = result[0] + assert r0.parent == None + assert r0.total_condition == 'FOO AND bar' + assert r0.get_string('test1') == 'parent' + assert r0.get_string('test2') == 'child' + + +# Real world examples: + +# qstandardpaths selection: + +def test_qstandardpaths_scopes(): + # top level: + scope1 = _new_scope(condition='ON', scope_id=1) + + # win32 { + scope2 = _new_scope(parent_scope=scope1, condition='WIN32') + # !winrt { + # SOURCES += io/qstandardpaths_win.cpp + scope3 = _new_scope(parent_scope=scope2, condition='NOT WINRT', + SOURCES='qsp_win.cpp') + # } else { + # SOURCES += io/qstandardpaths_winrt.cpp + scope4 = _new_scope(parent_scope=scope2, condition='else', + SOURCES='qsp_winrt.cpp') + # } + # else: unix { + scope5 = _new_scope(parent_scope=scope1, condition='else') + scope6 = _new_scope(parent_scope=scope5, condition='UNIX') + # mac { + # OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm + scope7 = _new_scope(parent_scope=scope6, condition='APPLE_OSX', SOURCES='qsp_mac.mm') + # } else:android:!android-embedded { + # SOURCES += io/qstandardpaths_android.cpp + scope8 = _new_scope(parent_scope=scope6, condition='else') + scope9 = _new_scope(parent_scope=scope8, + condition='ANDROID AND NOT ANDROID_EMBEDDED', + SOURCES='qsp_android.cpp') + # } else:haiku { + # SOURCES += io/qstandardpaths_haiku.cpp + scope10 = _new_scope(parent_scope=scope8, condition='else') + scope11 = _new_scope(parent_scope=scope10, condition='HAIKU', SOURCES='qsp_haiku.cpp') + # } else { + # SOURCES +=io/qstandardpaths_unix.cpp + scope12 = _new_scope(parent_scope=scope10, condition='else', SOURCES='qsp_unix.cpp') + # } + # } + + recursive_evaluate_scope(scope1) + + assert scope1.total_condition == 'ON' + assert scope2.total_condition == 'WIN32' + assert scope3.total_condition == 'WIN32 AND NOT WINRT' + assert scope4.total_condition == 'WINRT' + assert scope5.total_condition == 'UNIX' + assert scope6.total_condition == 'UNIX' + assert scope7.total_condition == 'APPLE_OSX' + assert scope8.total_condition == 'UNIX AND NOT APPLE_OSX' + assert scope9.total_condition == 'ANDROID AND NOT ANDROID_EMBEDDED' + assert scope10.total_condition == 'UNIX AND NOT APPLE_OSX AND (ANDROID_EMBEDDED OR NOT ANDROID)' + assert scope11.total_condition == 'HAIKU AND (ANDROID_EMBEDDED OR NOT ANDROID)' + assert scope12.total_condition == 'UNIX AND NOT APPLE_OSX AND NOT HAIKU AND (ANDROID_EMBEDDED OR NOT ANDROID)' + +def test_recursive_expansion(): + scope = _new_scope(A='Foo',B='$$A/Bar') + assert scope.get_string('A') == 'Foo' + assert scope.get_string('B') == '$$A/Bar' + assert scope._expand_value('$$B/Source.cpp') == ['Foo/Bar/Source.cpp'] + assert scope._expand_value('$$B') == ['Foo/Bar'] + |