* [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests
@ 2021-12-05 10:53 Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest Ricardo Martincoski
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Ricardo Martincoski @ 2021-12-05 10:53 UTC (permalink / raw)
To: buildroot; +Cc: Ricardo Martincoski
So anyone willing to contribute to check-package can run all tests in
less than 1 second by using:
$ python3 -m pytest -v utils/checkpackagelib/
Most test cases are in the form:
@pytest.mark.parametrize('testname,filename,string,expected', function)
- testname: a short description of the scenario tested, added in order
to improve readability of the log when some tests fail
- filename: the filename the check-package function being tested thinks
it is testing
- string: the content of the file being sent to the function under test
- expect: all expected warnings that a given function from
check-package should generate for a given file named filename and
with string as its content.
Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
Cc: Arnout Vandecappelle <arnout@mind.be>
---
NOTICE there are 2 tests failing, see the fix in:
http://patchwork.ozlabs.org/project/buildroot/patch/20211115235336.3814968-1-ricardo.martincoski@gmail.com/
See a sample running in the GitLab CI:
without the fix:
https://gitlab.com/RicardoMartincoski/buildroot/-/pipelines/422862195
with the fix:
https://gitlab.com/RicardoMartincoski/buildroot/-/pipelines/422862127
Example of a failure, showing enough information to track down the test
that fails:
|testname = 'immediate assignment inside conditional and unconditional override outside'
|filename = 'any.mk'
|string = 'VAR_1 = VALUE1\nifeq (condition)\nVAR_1 := $(VAR_1), VALUE2\nendif\nVAR_1 := $(VAR_1), VALUE2\n'
|expected = [['any.mk:3: immediate assignment to append to variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n'], ['any.mk:5: unconditional override of variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n']]
|
| @pytest.mark.parametrize('testname,filename,string,expected', overridden_variable)
| def test_overridden_variable(testname, filename, string, expected):
| warnings = util.check_file(m.OverriddenVariable, filename, string)
|> assert warnings == expected
|E AssertionError: assert [['any.mk:3: ...), VALUE2\n']] == [['any.mk:3: i...), VALUE2\n']]
|E At index 0 diff: ['any.mk:3: conditional override of variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n'] != ['any.mk:3: immediate assignment to append to variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n']
|E Full diff:
|E - [['any.mk:3: conditional override of variable VAR_1',
|E + [['any.mk:3: immediate assignment to append to variable VAR_1',
|E 'VAR_1 := $(VAR_1), VALUE2\n'],
|E ['any.mk:5: unconditional override of variable VAR_1',
|E 'VAR_1 := $(VAR_1), VALUE2\n']]
|
|utils/checkpackagelib/test_lib_mk.py:168: AssertionError
|===================== 2 failed, 180 passed in 0.79 seconds =====================
---
utils/checkpackagelib/test_lib.py | 212 ++++++++
utils/checkpackagelib/test_lib_config.py | 387 +++++++++++++++
utils/checkpackagelib/test_lib_hash.py | 137 ++++++
utils/checkpackagelib/test_lib_mk.py | 590 +++++++++++++++++++++++
utils/checkpackagelib/test_lib_patch.py | 96 ++++
utils/checkpackagelib/test_util.py | 8 +
6 files changed, 1430 insertions(+)
create mode 100644 utils/checkpackagelib/test_lib.py
create mode 100644 utils/checkpackagelib/test_lib_config.py
create mode 100644 utils/checkpackagelib/test_lib_hash.py
create mode 100644 utils/checkpackagelib/test_lib_mk.py
create mode 100644 utils/checkpackagelib/test_lib_patch.py
create mode 100644 utils/checkpackagelib/test_util.py
diff --git a/utils/checkpackagelib/test_lib.py b/utils/checkpackagelib/test_lib.py
new file mode 100644
index 0000000000..976a63d84d
--- /dev/null
+++ b/utils/checkpackagelib/test_lib.py
@@ -0,0 +1,212 @@
+import pytest
+import checkpackagelib.test_util as util
+import checkpackagelib.lib as m
+
+
+ConsecutiveEmptyLines = [
+ ('1 line (no newline)',
+ 'any',
+ '',
+ []),
+ ('1 line',
+ 'any',
+ '\n',
+ []),
+ ('2 lines',
+ 'any',
+ '\n'
+ '\n',
+ [['any:2: consecutive empty lines']]),
+ ('more than 2 consecutive',
+ 'any',
+ '\n'
+ '\n'
+ '\n',
+ [['any:2: consecutive empty lines'],
+ ['any:3: consecutive empty lines']]),
+ ('ignore whitespace 1',
+ 'any',
+ '\n'
+ ' ',
+ [['any:2: consecutive empty lines']]),
+ ('ignore whitespace 2',
+ 'any',
+ ' \n'
+ '\t\n',
+ [['any:2: consecutive empty lines']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', ConsecutiveEmptyLines)
+def test_ConsecutiveEmptyLines(testname, filename, string, expected):
+ warnings = util.check_file(m.ConsecutiveEmptyLines, filename, string)
+ assert warnings == expected
+
+
+EmptyLastLine = [
+ ('ignore empty file',
+ 'any',
+ '',
+ []),
+ ('empty line (newline)',
+ 'any',
+ '\n',
+ [['any:1: empty line at end of file']]),
+ ('empty line (space, newline)',
+ 'any',
+ ' \n',
+ [['any:1: empty line at end of file']]),
+ ('empty line (space, no newline)',
+ 'any',
+ ' ',
+ [['any:1: empty line at end of file']]),
+ ('warn for the last of 2',
+ 'any',
+ '\n'
+ '\n',
+ [['any:2: empty line at end of file']]),
+ ('warn for the last of 3',
+ 'any',
+ '\n'
+ '\n'
+ '\n',
+ [['any:3: empty line at end of file']]),
+ ('ignore whitespace',
+ 'any',
+ ' \n'
+ '\t\n',
+ [['any:2: empty line at end of file']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', EmptyLastLine)
+def test_EmptyLastLine(testname, filename, string, expected):
+ warnings = util.check_file(m.EmptyLastLine, filename, string)
+ assert warnings == expected
+
+
+NewlineAtEof = [
+ ('good',
+ 'any',
+ 'text\n',
+ []),
+ ('text (bad)',
+ 'any',
+ '\n'
+ 'text',
+ [['any:2: missing newline at end of file',
+ 'text']]),
+ ('space (bad)',
+ 'any',
+ '\n'
+ ' ',
+ [['any:2: missing newline at end of file',
+ ' ']]),
+ ('tab (bad)',
+ 'any',
+ '\n'
+ '\t',
+ [['any:2: missing newline at end of file',
+ '\t']]),
+ ('even for file with one line',
+ 'any',
+ ' ',
+ [['any:1: missing newline at end of file',
+ ' ']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', NewlineAtEof)
+def test_NewlineAtEof(testname, filename, string, expected):
+ warnings = util.check_file(m.NewlineAtEof, filename, string)
+ assert warnings == expected
+
+
+TrailingSpace = [
+ ('good',
+ 'any',
+ 'text\n',
+ []),
+ ('ignore missing newline',
+ 'any',
+ '\n'
+ 'text',
+ []),
+ ('spaces',
+ 'any',
+ 'text \n',
+ [['any:1: line contains trailing whitespace',
+ 'text \n']]),
+ ('tabs after text',
+ 'any',
+ 'text\t\t\n',
+ [['any:1: line contains trailing whitespace',
+ 'text\t\t\n']]),
+ ('mix of tabs and spaces',
+ 'any',
+ ' \n'
+ ' ',
+ [['any:1: line contains trailing whitespace',
+ ' \n'],
+ ['any:2: line contains trailing whitespace',
+ ' ']]),
+ ('blank line with tabs',
+ 'any',
+ '\n'
+ '\t',
+ [['any:2: line contains trailing whitespace',
+ '\t']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', TrailingSpace)
+def test_TrailingSpace(testname, filename, string, expected):
+ warnings = util.check_file(m.TrailingSpace, filename, string)
+ assert warnings == expected
+
+
+Utf8Characters = [
+ ('usual',
+ 'any',
+ 'text\n',
+ []),
+ ('acceptable character',
+ 'any',
+ '\x60',
+ []),
+ ('unacceptable character',
+ 'any',
+ '\x81',
+ [['any:1: line contains UTF-8 characters',
+ '\x81']]),
+ ('2 warnings',
+ 'any',
+ 'text\n'
+ 'text \xc8 text\n'
+ '\xc9\n',
+ [['any:2: line contains UTF-8 characters',
+ 'text \xc8 text\n'],
+ ['any:3: line contains UTF-8 characters',
+ '\xc9\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', Utf8Characters)
+def test_Utf8Characters(testname, filename, string, expected):
+ warnings = util.check_file(m.Utf8Characters, filename, string)
+ assert warnings == expected
+
+
+def test_all_check_functions_are_used():
+ import inspect
+ import checkpackagelib.lib_config as lib_config
+ import checkpackagelib.lib_hash as lib_hash
+ import checkpackagelib.lib_mk as lib_mk
+ import checkpackagelib.lib_patch as lib_patch
+ c_config = [c[0] for c in inspect.getmembers(lib_config, inspect.isclass)]
+ c_hash = [c[0] for c in inspect.getmembers(lib_hash, inspect.isclass)]
+ c_mk = [c[0] for c in inspect.getmembers(lib_mk, inspect.isclass)]
+ c_patch = [c[0] for c in inspect.getmembers(lib_patch, inspect.isclass)]
+ c_all = c_config + c_hash + c_mk + c_patch
+ c_common = [c[0] for c in inspect.getmembers(m, inspect.isclass)]
+ assert set(c_common) <= set(c_all)
diff --git a/utils/checkpackagelib/test_lib_config.py b/utils/checkpackagelib/test_lib_config.py
new file mode 100644
index 0000000000..91a549adf2
--- /dev/null
+++ b/utils/checkpackagelib/test_lib_config.py
@@ -0,0 +1,387 @@
+import pytest
+import checkpackagelib.test_util as util
+import checkpackagelib.lib_config as m
+
+
+AttributesOrder = [
+ ('good example',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'default y\n'
+ 'depends on BR2_USE_BAR # runtime\n'
+ 'select BR2_PACKAGE_BAZ\n'
+ 'help\n'
+ '\t help text\n',
+ []),
+ ('depends before default',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'depends on BR2_USE_BAR\n'
+ 'default y\n',
+ [['any:4: attributes order: type, default, depends on, select, help (url#_config_files)',
+ 'default y\n']]),
+ ('select after help',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'help\n'
+ '\t help text\n'
+ 'select BR2_PACKAGE_BAZ\n',
+ [['any:5: attributes order: type, default, depends on, select, help (url#_config_files)',
+ 'select BR2_PACKAGE_BAZ\n']]),
+ ('string',
+ 'any',
+ 'config BR2_PACKAGE_FOO_PLUGINS\n'
+ 'string "foo plugins"\n'
+ 'default "all"\n',
+ []),
+ ('ignore tabs',
+ 'any',
+ 'config\tBR2_PACKAGE_FOO_PLUGINS\n'
+ 'default\t"all"\n'
+ 'string\t"foo plugins"\n',
+ [['any:3: attributes order: type, default, depends on, select, help (url#_config_files)',
+ 'string\t"foo plugins"\n']]),
+ ('choice',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'if BR2_PACKAGE_FOO\n'
+ '\n'
+ 'choice\n'
+ 'prompt "type of foo"\n'
+ 'default BR2_PACKAGE_FOO_STRING\n'
+ '\n'
+ 'config BR2_PACKAGE_FOO_NONE\n'
+ 'bool "none"\n'
+ '\n'
+ 'config BR2_PACKAGE_FOO_STRING\n'
+ 'bool "string"\n'
+ '\n'
+ 'endchoice\n'
+ '\n'
+ 'endif\n'
+ '\n',
+ []),
+ ('type after default',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'if BR2_PACKAGE_FOO\n'
+ '\n'
+ 'choice\n'
+ 'default BR2_PACKAGE_FOO_STRING\n'
+ 'prompt "type of foo"\n',
+ [['any:7: attributes order: type, default, depends on, select, help (url#_config_files)',
+ 'prompt "type of foo"\n']]),
+ ('menu',
+ 'any',
+ 'menuconfig BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'help\n'
+ '\t help text\n'
+ '\t help text\n'
+ '\n'
+ 'if BR2_PACKAGE_FOO\n'
+ '\n'
+ 'menu "foo plugins"\n'
+ 'config BR2_PACKAGE_FOO_COUNTER\n'
+ 'bool "counter"\n'
+ '\n'
+ 'endmenu\n'
+ '\n'
+ 'endif\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', AttributesOrder)
+def test_AttributesOrder(testname, filename, string, expected):
+ warnings = util.check_file(m.AttributesOrder, filename, string)
+ assert warnings == expected
+
+
+CommentsMenusPackagesOrder = [
+ ('top menu (good)',
+ 'package/Config.in',
+ 'menu "Target packages"\n'
+ 'source "package/busybox/Config.in"\n'
+ 'source "package/skeleton/Config.in"\n',
+ []),
+ ('top menu (bad)',
+ 'package/Config.in',
+ 'source "package/skeleton/Config.in"\n'
+ 'source "package/busybox/Config.in"\n',
+ [['package/Config.in:2: Packages in: The top level menu,\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: busybox',
+ 'source "package/busybox/Config.in"\n']]),
+ ('menu (bad)',
+ 'package/Config.in',
+ 'menu "Target packages"\n'
+ 'source "package/skeleton/Config.in"\n'
+ 'source "package/busybox/Config.in"\n',
+ [['package/Config.in:3: Packages in: menu "Target packages",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: busybox',
+ 'source "package/busybox/Config.in"\n']]),
+ ('underscore (good)',
+ 'package/Config.in.host',
+ 'menu "Hardware handling"\n'
+ 'menu "Firmware"\n'
+ 'endmenu\n'
+ 'source "package/usb_modeswitch/Config.in"\n'
+ 'source "package/usbmount/Config.in"\n',
+ []),
+ ('underscore (bad)',
+ 'package/Config.in.host',
+ 'menu "Hardware handling"\n'
+ 'menu "Firmware"\n'
+ 'endmenu\n'
+ 'source "package/usbmount/Config.in"\n'
+ 'source "package/usb_modeswitch/Config.in"\n',
+ [['package/Config.in.host:5: Packages in: menu "Hardware handling",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: usb_modeswitch',
+ 'source "package/usb_modeswitch/Config.in"\n']]),
+ ('ignore other files',
+ 'any other file',
+ 'menu "Hardware handling"\n'
+ 'source "package/bbb/Config.in"\n'
+ 'source "package/aaa/Config.in"\n',
+ []),
+ ('dash (bad)',
+ 'package/Config.in',
+ 'menu "packages"\n'
+ 'source "package/a_a/Config.in"\n'
+ 'source "package/a-a/Config.in"\n'
+ 'source "package/a1a/Config.in"\n'
+ 'source "package/aAa/Config.in"\n'
+ 'source "package/aaa/Config.in"\n',
+ [['package/Config.in:3: Packages in: menu "packages",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: a-a',
+ 'source "package/a-a/Config.in"\n']]),
+ ('underscore (bad)',
+ 'package/Config.in',
+ 'menu "packages"\n'
+ 'source "package/a-a/Config.in"\n'
+ 'source "package/a1a/Config.in"\n'
+ 'source "package/a_a/Config.in"\n'
+ 'source "package/aAa/Config.in"\n'
+ 'source "package/aaa/Config.in"\n',
+ [['package/Config.in:4: Packages in: menu "packages",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: a_a',
+ 'source "package/a_a/Config.in"\n']]),
+ ('digit (bad)',
+ 'package/Config.in',
+ 'menu "packages"\n'
+ 'source "package/a-a/Config.in"\n'
+ 'source "package/a_a/Config.in"\n'
+ 'source "package/aAa/Config.in"\n'
+ 'source "package/a1a/Config.in"\n'
+ 'source "package/aaa/Config.in"\n',
+ [['package/Config.in:5: Packages in: menu "packages",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: a1a',
+ 'source "package/a1a/Config.in"\n']]),
+ ('capitals (bad)',
+ 'package/Config.in',
+ 'menu "packages"\n'
+ 'source "package/a-a/Config.in"\n'
+ 'source "package/a_a/Config.in"\n'
+ 'source "package/a1a/Config.in"\n'
+ 'source "package/aaa/Config.in"\n'
+ 'source "package/aAa/Config.in"\n',
+ [['package/Config.in:6: Packages in: menu "packages",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: aAa',
+ 'source "package/aAa/Config.in"\n']]),
+ ('digits, capitals, underscore (good)',
+ 'package/Config.in',
+ 'menu "packages"\n'
+ 'source "package/a-a/Config.in"\n'
+ 'source "package/a_a/Config.in"\n'
+ 'source "package/a1a/Config.in"\n'
+ 'source "package/aAa/Config.in"\n'
+ 'source "package/aaa/Config.in"\n',
+ []),
+ ('conditional menu (good)',
+ 'package/Config.in',
+ 'menu "Other"\n'
+ 'source "package/linux-pam/Config.in"\n'
+ 'if BR2_PACKAGE_LINUX_PAM\n'
+ 'comment "linux-pam plugins"\n'
+ 'source "package/libpam-radius-auth/Config.in"\n'
+ 'source "package/libpam-tacplus/Config.in"\n'
+ 'endif\n'
+ 'source "package/liquid-dsp/Config.in"\n',
+ []),
+ ('conditional menu (bad)',
+ 'package/Config.in',
+ 'menu "Other"\n'
+ 'source "package/linux-pam/Config.in"\n'
+ 'if BR2_PACKAGE_LINUX_PAM\n'
+ 'comment "linux-pam plugins"\n'
+ 'source "package/libpam-tacplus/Config.in"\n'
+ 'source "package/libpam-radius-auth/Config.in"\n'
+ 'endif\n'
+ 'source "package/liquid-dsp/Config.in"\n',
+ [['package/Config.in:6: Packages in: comment "linux-pam plugins",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: libpam-radius-auth',
+ 'source "package/libpam-radius-auth/Config.in"\n']]),
+ ('no conditional (bad)',
+ 'package/Config.in',
+ 'menu "Other"\n'
+ 'source "package/linux-pam/Config.in"\n'
+ 'source "package/libpam-radius-auth/Config.in"\n'
+ 'source "package/libpam-tacplus/Config.in"\n'
+ 'source "package/liquid-dsp/Config.in"\n',
+ [['package/Config.in:3: Packages in: menu "Other",\n'
+ ' are not alphabetically ordered;\n'
+ " correct order: '-', '_', digits, capitals, lowercase;\n"
+ ' first incorrect package: libpam-radius-auth',
+ 'source "package/libpam-radius-auth/Config.in"\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', CommentsMenusPackagesOrder)
+def test_CommentsMenusPackagesOrder(testname, filename, string, expected):
+ warnings = util.check_file(m.CommentsMenusPackagesOrder, filename, string)
+ assert warnings == expected
+
+
+HelpText = [
+ ('single line',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'bool "foo"\n'
+ 'default y\n'
+ 'depends on BR2_USE_BAR # runtime\n'
+ 'select BR2_PACKAGE_BAZ\n'
+ 'help\n'
+ '\t help text\n',
+ []),
+ ('larger than 72',
+ 'any',
+ 'help\n'
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 123\n'
+ '\t help text\n',
+ [['any:3: help text: <tab><2 spaces><62 chars> (url#writing-rules-config-in)',
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 123\n',
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12']]),
+ ('long url at beginning of line',
+ 'any',
+ 'help\n'
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
+ '\t http://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
+ '\t https://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
+ '\t git://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
+ []),
+ ('long url not at beginning of line',
+ 'any',
+ 'help\n'
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
+ '\t refer to http://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
+ '\n'
+ '\t http://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
+ [['any:3: help text: <tab><2 spaces><62 chars> (url#writing-rules-config-in)',
+ '\t refer to http://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12']]),
+ ('allow beautified items',
+ 'any',
+ 'help\n'
+ '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
+ '\t summary:\n'
+ '\t - enable that config\n'
+ '\t - built it\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', HelpText)
+def test_HelpText(testname, filename, string, expected):
+ warnings = util.check_file(m.HelpText, filename, string)
+ assert warnings == expected
+
+
+Indent = [
+ ('good example',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ '\tbool "foo"\n'
+ '\tdefault y\n'
+ '\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n'
+ '\tdepends on BR2_INSTALL_LIBSTDCPP\n'
+ '# very useful comment\n'
+ '\tselect BR2_PACKAGE_BAZ\n'
+ '\thelp\n'
+ '\t help text\n'
+ '\n'
+ 'comment "foo needs toolchain w/ C++, threads"\n'
+ '\tdepends on !BR2_INSTALL_LIBSTDCPP || \\\n'
+ '\t\t!BR2_TOOLCHAIN_HAS_THREADS\n'
+ '\n'
+ 'source "package/foo/bar/Config.in"\n',
+ []),
+ ('spaces',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ ' bool "foo"\n',
+ [['any:2: should be indented with one tab (url#_config_files)',
+ ' bool "foo"\n']]),
+ ('without indent',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ 'default y\n',
+ [['any:2: should be indented with one tab (url#_config_files)',
+ 'default y\n']]),
+ ('too much tabs',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ '\t\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n',
+ [['any:2: should be indented with one tab (url#_config_files)',
+ '\t\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n']]),
+ ('help',
+ 'any',
+ 'config BR2_PACKAGE_FOO\n'
+ ' help\n',
+ [['any:2: should be indented with one tab (url#_config_files)',
+ ' help\n']]),
+ ('continuation line',
+ 'any',
+ 'comment "foo needs toolchain w/ C++, threads"\n'
+ '\tdepends on !BR2_INSTALL_LIBSTDCPP || \\\n'
+ ' !BR2_TOOLCHAIN_HAS_THREADS\n',
+ [['any:3: continuation line should be indented using tabs',
+ ' !BR2_TOOLCHAIN_HAS_THREADS\n']]),
+ ('comment with tabs',
+ 'any',
+ '\tcomment "foo needs toolchain w/ C++, threads"\n',
+ [['any:1: should not be indented',
+ '\tcomment "foo needs toolchain w/ C++, threads"\n']]),
+ ('comment with spaces',
+ 'any',
+ ' comment "foo needs toolchain w/ C++, threads"\n',
+ [['any:1: should not be indented',
+ ' comment "foo needs toolchain w/ C++, threads"\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', Indent)
+def test_Indent(testname, filename, string, expected):
+ warnings = util.check_file(m.Indent, filename, string)
+ assert warnings == expected
diff --git a/utils/checkpackagelib/test_lib_hash.py b/utils/checkpackagelib/test_lib_hash.py
new file mode 100644
index 0000000000..c160a394e9
--- /dev/null
+++ b/utils/checkpackagelib/test_lib_hash.py
@@ -0,0 +1,137 @@
+import pytest
+import checkpackagelib.test_util as util
+import checkpackagelib.lib_hash as m
+
+
+HashNumberOfFields = [
+ ('empty file',
+ 'any',
+ '',
+ []),
+ ('empty line',
+ 'any',
+ '\n',
+ []),
+ ('ignore whitespace',
+ 'any',
+ '\t\n',
+ []),
+ ('ignore comments',
+ 'any',
+ '# text\n',
+ []),
+ ('1 field',
+ 'any',
+ 'field1\n',
+ [['any:1: expected three fields (url#adding-packages-hash)',
+ 'field1\n']]),
+ ('2 fields',
+ 'any',
+ 'field1 field2\n',
+ [['any:1: expected three fields (url#adding-packages-hash)',
+ 'field1 field2\n']]),
+ ('4 fields',
+ 'any',
+ 'field1 field2 field3 field4\n',
+ [['any:1: expected three fields (url#adding-packages-hash)',
+ 'field1 field2 field3 field4\n']]),
+ ('with 1 space',
+ 'any',
+ 'field1 field2 field3\n',
+ []),
+ ('many spaces',
+ 'any',
+ ' field1 field2 field3\n',
+ []),
+ ('tabs',
+ 'any',
+ 'field1\tfield2\tfield3\n',
+ []),
+ ('mix of tabs and spaces',
+ 'any',
+ '\tfield1\t field2\t field3 \n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', HashNumberOfFields)
+def test_HashNumberOfFields(testname, filename, string, expected):
+ warnings = util.check_file(m.HashNumberOfFields, filename, string)
+ assert warnings == expected
+
+
+HashType = [
+ ('ignore empty files',
+ 'any',
+ '',
+ []),
+ ('ignore 1 field',
+ 'any',
+ 'text\n',
+ []),
+ ('wrong type',
+ 'any',
+ 'text text\n',
+ [['any:1: unexpected type of hash (url#adding-packages-hash)',
+ 'text text\n']]),
+ ('none',
+ 'any',
+ 'none text\n',
+ []),
+ ('md5 (good)',
+ 'any',
+ 'md5 12345678901234567890123456789012\n',
+ []),
+ ('md5 (short)',
+ 'any',
+ 'md5 123456\n',
+ [['any:1: hash size does not match type (url#adding-packages-hash)',
+ 'md5 123456\n',
+ 'expected 32 hex digits']]),
+ ('ignore space before',
+ 'any',
+ ' md5 12345678901234567890123456789012\n',
+ []),
+ ('2 spaces',
+ 'any',
+ 'md5 12345678901234567890123456789012\n',
+ []),
+ ('ignore tabs',
+ 'any',
+ 'md5\t12345678901234567890123456789012\n',
+ []),
+ ('common typo',
+ 'any',
+ 'md5sum 12345678901234567890123456789012\n',
+ [['any:1: unexpected type of hash (url#adding-packages-hash)',
+ 'md5sum 12345678901234567890123456789012\n']]),
+ ('md5 (too long)',
+ 'any',
+ 'md5 123456789012345678901234567890123\n',
+ [['any:1: hash size does not match type (url#adding-packages-hash)',
+ 'md5 123456789012345678901234567890123\n',
+ 'expected 32 hex digits']]),
+ ('sha1 (good)',
+ 'any',
+ 'sha1 1234567890123456789012345678901234567890\n',
+ []),
+ ('sha256',
+ 'any',
+ 'sha256 1234567890123456789012345678901234567890123456789012345678901234\n',
+ []),
+ ('sha384',
+ 'any',
+ 'sha384 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\n',
+ []),
+ ('sha512',
+ 'any',
+ 'sha512 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'
+ '9012345678\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', HashType)
+def test_HashType(testname, filename, string, expected):
+ warnings = util.check_file(m.HashType, filename, string)
+ assert warnings == expected
diff --git a/utils/checkpackagelib/test_lib_mk.py b/utils/checkpackagelib/test_lib_mk.py
new file mode 100644
index 0000000000..49fa216fcd
--- /dev/null
+++ b/utils/checkpackagelib/test_lib_mk.py
@@ -0,0 +1,590 @@
+import pytest
+import checkpackagelib.test_util as util
+import checkpackagelib.lib_mk as m
+
+
+Indent = [
+ ('ignore comment at beginning of line',
+ 'any',
+ '# very useful comment\n',
+ []),
+ ('ignore comment at end of line',
+ 'any',
+ ' # very useful comment\n',
+ []),
+ ('do not indent on conditional (good)',
+ 'any',
+ 'ifeq ($(BR2_TOOLCHAIN_HAS_THREADS),y)\n'
+ 'FOO_CONF_OPTS += something\n'
+ 'endef\n',
+ []),
+ ('do not indent on conditional (bad)',
+ 'any',
+ 'ifeq ($(BR2_TOOLCHAIN_HAS_THREADS),y)\n'
+ '\tFOO_CONF_OPTS += something\n'
+ 'endef\n',
+ [['any:2: unexpected indent with tabs',
+ '\tFOO_CONF_OPTS += something\n']]),
+ ('indent after line that ends in backslash (good)',
+ 'any',
+ 'FOO_CONF_OPTS += \\\n'
+ '\tsomething\n',
+ []),
+ ('indent after line that ends in backslash (bad)',
+ 'any',
+ 'FOO_CONF_OPTS += \\\n'
+ 'something\n',
+ [['any:2: expected indent with tabs',
+ 'something\n']]),
+ ('indent after 2 lines that ends in backslash (good)',
+ 'any',
+ 'FOO_CONF_OPTS += \\\n'
+ '\tsomething \\\n'
+ '\tsomething_else\n',
+ []),
+ ('indent after 2 lines that ends in backslash (bad)',
+ 'any',
+ 'FOO_CONF_OPTS += \\\n'
+ '\tsomething \\\n'
+ '\tsomething_else \\\n'
+ 'FOO_CONF_OPTS += another_thing\n',
+ [['any:4: expected indent with tabs',
+ 'FOO_CONF_OPTS += another_thing\n']]),
+ ('indent inside define (good)',
+ 'any',
+ 'define FOO_SOMETHING\n'
+ '\tcommand\n'
+ '\tcommand \\\n'
+ '\t\targuments\n'
+ 'endef\n'
+ 'FOO_POST_PATCH_HOOKS += FOO_SOMETHING\n',
+ []),
+ ('indent inside define (bad, no indent)',
+ 'any',
+ 'define FOO_SOMETHING\n'
+ 'command\n'
+ 'endef\n',
+ [['any:2: expected indent with tabs',
+ 'command\n']]),
+ ('indent inside define (bad, spaces)',
+ 'any',
+ 'define FOO_SOMETHING\n'
+ ' command\n'
+ 'endef\n',
+ [['any:2: expected indent with tabs',
+ ' command\n']]),
+ ('indent make target (good)',
+ 'any',
+ 'make_target:\n'
+ '\tcommand\n'
+ '\n',
+ []),
+ ('indent make target (bad)',
+ 'any',
+ 'make_target:\n'
+ ' command\n'
+ '\n',
+ [['any:2: expected indent with tabs',
+ ' command\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', Indent)
+def test_Indent(testname, filename, string, expected):
+ warnings = util.check_file(m.Indent, filename, string)
+ assert warnings == expected
+
+
+OverriddenVariable = [
+ ('simple assignment',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n',
+ []),
+ ('unconditional override (variable without underscore)',
+ 'any.mk',
+ 'VAR1 = VALUE1\n'
+ 'VAR1 = VALUE1\n',
+ [['any.mk:2: unconditional override of variable VAR1',
+ 'VAR1 = VALUE1\n']]),
+ ('unconditional override (variable with underscore, same value)',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'VAR_1 = VALUE1\n',
+ [['any.mk:2: unconditional override of variable VAR_1',
+ 'VAR_1 = VALUE1\n']]),
+ ('unconditional override (variable with underscore, different value)',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'VAR_1 = VALUE2\n',
+ [['any.mk:2: unconditional override of variable VAR_1',
+ 'VAR_1 = VALUE2\n']]),
+ ('warn for unconditional override even with wrong number of spaces',
+ 'any.mk',
+ 'VAR_1= VALUE1\n'
+ 'VAR_1 =VALUE2\n',
+ [['any.mk:2: unconditional override of variable VAR_1',
+ 'VAR_1 =VALUE2\n']]),
+ ('warn for := override',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'VAR_1 := VALUE2\n',
+ [['any.mk:2: unconditional override of variable VAR_1',
+ 'VAR_1 := VALUE2\n']]),
+ ('append values outside conditional (good)',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'VAR_1 += VALUE2\n',
+ []),
+ ('append values outside conditional (bad)',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'VAR_1 := $(VAR_1), VALUE2\n',
+ [['any.mk:2: unconditional override of variable VAR_1',
+ 'VAR_1 := $(VAR_1), VALUE2\n']]),
+ ('immediate assignment inside conditional',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'ifeq (condition)\n'
+ 'VAR_1 := $(VAR_1), VALUE2\n',
+ [['any.mk:3: immediate assignment to append to variable VAR_1',
+ 'VAR_1 := $(VAR_1), VALUE2\n']]),
+ ('immediate assignment inside conditional and unconditional override outside',
+ 'any.mk',
+ 'VAR_1 = VALUE1\n'
+ 'ifeq (condition)\n'
+ 'VAR_1 := $(VAR_1), VALUE2\n'
+ 'endif\n'
+ 'VAR_1 := $(VAR_1), VALUE2\n',
+ [['any.mk:3: immediate assignment to append to variable VAR_1',
+ 'VAR_1 := $(VAR_1), VALUE2\n'],
+ ['any.mk:5: unconditional override of variable VAR_1',
+ 'VAR_1 := $(VAR_1), VALUE2\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', OverriddenVariable)
+def test_OverriddenVariable(testname, filename, string, expected):
+ warnings = util.check_file(m.OverriddenVariable, filename, string)
+ assert warnings == expected
+
+
+PackageHeader = [
+ ('first line (good)',
+ 'any',
+ 80 * '#' + '\n',
+ []),
+ ('first line (bad)',
+ 'any',
+ '# very useful comment\n',
+ [['any:1: should be 80 hashes (url#writing-rules-mk)',
+ '# very useful comment\n',
+ 80 * '#']]),
+ ('second line (bad)',
+ 'any',
+ 80 * '#' + '\n'
+ '# package\n',
+ [['any:2: should be 1 hash (url#writing-rules-mk)',
+ '# package\n']]),
+ ('full header (good)',
+ 'any',
+ 80 * '#' + '\n'
+ '#\n'
+ '# package\n'
+ '#\n' +
+ 80 * '#' + '\n'
+ '\n',
+ []),
+ ('blank line after header (good)',
+ 'any',
+ 80 * '#' + '\n'
+ '#\n'
+ '# package\n'
+ '#\n' +
+ 80 * '#' + '\n'
+ '\n'
+ 'FOO_VERSION = 1\n',
+ []),
+ ('blank line after header (bad)',
+ 'any',
+ 80 * '#' + '\n'
+ '#\n'
+ '# package\n'
+ '#\n' +
+ 80 * '#' + '\n'
+ 'FOO_VERSION = 1\n',
+ [['any:6: should be a blank line (url#writing-rules-mk)',
+ 'FOO_VERSION = 1\n']]),
+ ('wrong number of hashes',
+ 'any',
+ 79 * '#' + '\n'
+ '#\n'
+ '# package\n'
+ '#\n' +
+ 81 * '#' + '\n'
+ '\n',
+ [['any:1: should be 80 hashes (url#writing-rules-mk)',
+ 79 * '#' + '\n',
+ 80 * '#'],
+ ['any:5: should be 80 hashes (url#writing-rules-mk)',
+ 81 * '#' + '\n',
+ 80 * '#']]),
+ ('allow include without header',
+ 'any',
+ 'include $(sort $(wildcard package/foo/*/*.mk))\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', PackageHeader)
+def test_PackageHeader(testname, filename, string, expected):
+ warnings = util.check_file(m.PackageHeader, filename, string)
+ assert warnings == expected
+
+
+RemoveDefaultPackageSourceVariable = [
+ ('bad',
+ 'any.mk',
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
+ [['any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
+ ('bad with path',
+ './any.mk',
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
+ [['./any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
+ ('warn for correct line',
+ './any.mk',
+ '\n'
+ '\n'
+ '\n'
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
+ [['./any.mk:4: remove default value of _SOURCE variable (url#generic-package-reference)',
+ 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
+ ('warn ignoring missing spaces',
+ './any.mk',
+ 'ANY_SOURCE=any-$(ANY_VERSION).tar.gz\n',
+ [['./any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
+ 'ANY_SOURCE=any-$(ANY_VERSION).tar.gz\n']]),
+ ('good',
+ './any.mk',
+ 'ANY_SOURCE = aNy-$(ANY_VERSION).tar.gz\n',
+ []),
+ ('gcc exception',
+ 'gcc.mk',
+ 'GCC_SOURCE = gcc-$(GCC_VERSION).tar.gz\n',
+ []),
+ ('binutils exception',
+ './binutils.mk',
+ 'BINUTILS_SOURCE = binutils-$(BINUTILS_VERSION).tar.gz\n',
+ []),
+ ('gdb exception',
+ 'gdb/gdb.mk',
+ 'GDB_SOURCE = gdb-$(GDB_VERSION).tar.gz\n',
+ []),
+ ('package name with dash',
+ 'python-subprocess32.mk',
+ 'PYTHON_SUBPROCESS32_SOURCE = python-subprocess32-$(PYTHON_SUBPROCESS32_VERSION).tar.gz\n',
+ [['python-subprocess32.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
+ 'PYTHON_SUBPROCESS32_SOURCE = python-subprocess32-$(PYTHON_SUBPROCESS32_VERSION).tar.gz\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', RemoveDefaultPackageSourceVariable)
+def test_RemoveDefaultPackageSourceVariable(testname, filename, string, expected):
+ warnings = util.check_file(m.RemoveDefaultPackageSourceVariable, filename, string)
+ assert warnings == expected
+
+
+SpaceBeforeBackslash = [
+ ('no backslash',
+ 'any.mk',
+ '\n',
+ []),
+ ('ignore missing indent',
+ 'any.mk',
+ 'define ANY_SOME_FIXUP\n'
+ 'for i in $$(find $(STAGING_DIR)/usr/lib* -name "any*.la"); do \\\n',
+ []),
+ ('ignore missing space',
+ 'any.mk',
+ 'ANY_CONF_ENV= \\\n'
+ '\tap_cv_void_ptr_lt_long=no \\\n',
+ []),
+ ('variable',
+ 'any.mk',
+ '\n'
+ 'ANY = \\\n',
+ []),
+ ('2 spaces',
+ 'any.mk',
+ 'ANY = \\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY = \\\n']]),
+ ('warn about correct line',
+ 'any.mk',
+ '\n'
+ 'ANY = \\\n',
+ [['any.mk:2: use only one space before backslash',
+ 'ANY = \\\n']]),
+ ('tab',
+ 'any.mk',
+ 'ANY =\t\\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY =\t\\\n']]),
+ ('tabs',
+ 'any.mk',
+ 'ANY =\t\t\\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY =\t\t\\\n']]),
+ ('spaces and tabs',
+ 'any.mk',
+ 'ANY = \t\t\\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY = \t\t\\\n']]),
+ ('mixed spaces and tabs 1',
+ 'any.mk',
+ 'ANY = \t \t\\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY = \t \t\\\n']]),
+ ('mixed spaces and tabs 2',
+ 'any.mk',
+ 'ANY = \t \\\n',
+ [['any.mk:1: use only one space before backslash',
+ 'ANY = \t \\\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', SpaceBeforeBackslash)
+def test_SpaceBeforeBackslash(testname, filename, string, expected):
+ warnings = util.check_file(m.SpaceBeforeBackslash, filename, string)
+ assert warnings == expected
+
+
+TrailingBackslash = [
+ ('no backslash',
+ 'any.mk',
+ 'ANY = \n',
+ []),
+ ('one line',
+ 'any.mk',
+ 'ANY = \\\n',
+ []),
+ ('2 lines',
+ 'any.mk',
+ 'ANY = \\\n'
+ '\\\n',
+ []),
+ ('empty line after',
+ 'any.mk',
+ 'ANY = \\\n'
+ '\n',
+ [['any.mk:1: remove trailing backslash',
+ 'ANY = \\\n']]),
+ ('line with spaces after',
+ 'any.mk',
+ 'ANY = \\\n'
+ ' \n',
+ [['any.mk:1: remove trailing backslash',
+ 'ANY = \\\n']]),
+ ('line with tabs after',
+ 'any.mk',
+ 'ANY = \\\n'
+ '\t\n',
+ [['any.mk:1: remove trailing backslash',
+ 'ANY = \\\n']]),
+ ('ignore if commented',
+ 'any.mk',
+ '# ANY = \\\n'
+ '\n',
+ []),
+ ('real example',
+ 'any.mk',
+ 'ANY_CONF_ENV= \t\\\n'
+ '\tap_cv_void_ptr_lt_long=no \\\n'
+ '\n',
+ [['any.mk:2: remove trailing backslash',
+ '\tap_cv_void_ptr_lt_long=no \\\n']]),
+ ('ignore whitespace 1',
+ 'any.mk',
+ 'ANY = \t\t\\\n',
+ []),
+ ('ignore whitespace 2',
+ 'any.mk',
+ 'ANY = \t \t\\\n',
+ []),
+ ('ignore whitespace 3',
+ 'any.mk',
+ 'ANY = \t \\\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', TrailingBackslash)
+def test_TrailingBackslash(testname, filename, string, expected):
+ warnings = util.check_file(m.TrailingBackslash, filename, string)
+ assert warnings == expected
+
+
+TypoInPackageVariable = [
+ ('good',
+ 'any.mk',
+ 'ANY_VAR = \n',
+ []),
+ ('good with path 1',
+ './any.mk',
+ 'ANY_VAR += \n',
+ []),
+ ('good with path 2',
+ 'any/any.mk',
+ 'ANY_VAR = \n',
+ []),
+ ('bad =',
+ 'any.mk',
+ 'OTHER_VAR = \n',
+ [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
+ 'OTHER_VAR = \n']]),
+ ('bad +=',
+ 'any.mk',
+ 'OTHER_VAR += \n',
+ [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
+ 'OTHER_VAR += \n']]),
+ ('ignore missing space',
+ 'any.mk',
+ 'OTHER_VAR= \n',
+ [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
+ 'OTHER_VAR= \n']]),
+ ('use path in the warning',
+ './any.mk',
+ 'OTHER_VAR = \n',
+ [['./any.mk:1: possible typo: OTHER_VAR -> *ANY*',
+ 'OTHER_VAR = \n']]),
+ ('another name',
+ 'other.mk',
+ 'ANY_VAR = \n',
+ [['other.mk:1: possible typo: ANY_VAR -> *OTHER*',
+ 'ANY_VAR = \n']]),
+ ('libc exception',
+ './any.mk',
+ 'BR_LIBC = \n',
+ []),
+ ('rootfs exception',
+ 'any.mk',
+ 'ROOTFS_ANY_VAR += \n',
+ []),
+ ('host (good)',
+ 'any.mk',
+ 'HOST_ANY_VAR += \n',
+ []),
+ ('host (bad)',
+ 'any.mk',
+ 'HOST_OTHER_VAR = \n',
+ [['any.mk:1: possible typo: HOST_OTHER_VAR -> *ANY*',
+ 'HOST_OTHER_VAR = \n']]),
+ ('provides',
+ 'any.mk',
+ 'ANY_PROVIDES = other thing\n'
+ 'OTHER_VAR = \n',
+ []),
+ ('ignore space',
+ 'any.mk',
+ 'ANY_PROVIDES = thing other \n'
+ 'OTHER_VAR = \n',
+ []),
+ ('wrong provides',
+ 'any.mk',
+ 'ANY_PROVIDES = other\n'
+ 'OTHERS_VAR = \n',
+ [['any.mk:2: possible typo: OTHERS_VAR -> *ANY*',
+ 'OTHERS_VAR = \n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', TypoInPackageVariable)
+def test_TypoInPackageVariable(testname, filename, string, expected):
+ warnings = util.check_file(m.TypoInPackageVariable, filename, string)
+ assert warnings == expected
+
+
+UselessFlag = [
+ ('autoreconf no',
+ 'any.mk',
+ 'ANY_AUTORECONF=NO\n',
+ [['any.mk:1: useless default value (url#_infrastructure_for_autotools_based_packages)',
+ 'ANY_AUTORECONF=NO\n']]),
+ ('host autoreconf no',
+ 'any.mk',
+ 'HOST_ANY_AUTORECONF\n',
+ []),
+ ('autoreconf yes',
+ 'any.mk',
+ 'ANY_AUTORECONF=YES\n',
+ []),
+ ('libtool_patch yes',
+ 'any.mk',
+ 'ANY_LIBTOOL_PATCH\t= YES\n',
+ [['any.mk:1: useless default value (url#_infrastructure_for_autotools_based_packages)',
+ 'ANY_LIBTOOL_PATCH\t= YES\n']]),
+ ('libtool_patch no',
+ 'any.mk',
+ 'ANY_LIBTOOL_PATCH= \t NO\n',
+ []),
+ ('generic',
+ 'any.mk',
+ 'ANY_INSTALL_IMAGES = NO\n'
+ 'ANY_INSTALL_REDISTRIBUTE = YES\n'
+ 'ANY_INSTALL_STAGING = NO\n'
+ 'ANY_INSTALL_TARGET = YES\n',
+ [['any.mk:1: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
+ 'ANY_INSTALL_IMAGES = NO\n'],
+ ['any.mk:2: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
+ 'ANY_INSTALL_REDISTRIBUTE = YES\n'],
+ ['any.mk:3: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
+ 'ANY_INSTALL_STAGING = NO\n'],
+ ['any.mk:4: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
+ 'ANY_INSTALL_TARGET = YES\n']]),
+ ('conditional',
+ 'any.mk',
+ 'ifneq (condition)\n'
+ 'ANY_INSTALL_IMAGES = NO\n'
+ 'endif\n'
+ 'ANY_INSTALL_REDISTRIBUTE = YES\n',
+ [['any.mk:4: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
+ 'ANY_INSTALL_REDISTRIBUTE = YES\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', UselessFlag)
+def test_UselessFlag(testname, filename, string, expected):
+ warnings = util.check_file(m.UselessFlag, filename, string)
+ assert warnings == expected
+
+
+VariableWithBraces = [
+ ('good',
+ 'xmlstarlet.mk',
+ 'XMLSTARLET_CONF_OPTS += \\\n'
+ '\t--with-libxml-prefix=$(STAGING_DIR)/usr \\\n',
+ []),
+ ('bad',
+ 'xmlstarlet.mk',
+ 'XMLSTARLET_CONF_OPTS += \\\n'
+ '\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n',
+ [['xmlstarlet.mk:2: use $() to delimit variables, not ${}',
+ '\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n']]),
+ ('expanded by the shell',
+ 'sg3_utils.mk',
+ '\tfor prog in xcopy zone; do \\\n'
+ '\t\t$(RM) $(TARGET_DIR)/usr/bin/sg_$${prog} ; \\\n'
+ '\tdone\n',
+ []),
+ ('comments',
+ 'any.mk',
+ '#\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n',
+ []),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', VariableWithBraces)
+def test_VariableWithBraces(testname, filename, string, expected):
+ warnings = util.check_file(m.VariableWithBraces, filename, string)
+ assert warnings == expected
diff --git a/utils/checkpackagelib/test_lib_patch.py b/utils/checkpackagelib/test_lib_patch.py
new file mode 100644
index 0000000000..3b6fadf38c
--- /dev/null
+++ b/utils/checkpackagelib/test_lib_patch.py
@@ -0,0 +1,96 @@
+import pytest
+import checkpackagelib.test_util as util
+import checkpackagelib.lib_patch as m
+
+
+ApplyOrder = [
+ ('standard', # catches https://bugs.busybox.net/show_bug.cgi?id=11271
+ '0001-description.patch',
+ '',
+ []),
+ ('standard with path',
+ 'path/0001-description.patch',
+ '',
+ []),
+ ('acceptable format',
+ '1-description.patch',
+ '',
+ []),
+ ('acceptable format with path',
+ 'path/1-description.patch',
+ '',
+ []),
+ ('old format',
+ 'package-0001-description.patch',
+ '',
+ [['package-0001-description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
+ ('old format with path',
+ 'path/package-0001-description.patch',
+ '',
+ [['path/package-0001-description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
+ ('missing number',
+ 'description.patch',
+ '',
+ [['description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
+ ('missing number with path',
+ 'path/description.patch',
+ '',
+ [['path/description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', ApplyOrder)
+def test_ApplyOrder(testname, filename, string, expected):
+ warnings = util.check_file(m.ApplyOrder, filename, string)
+ assert warnings == expected
+
+
+NumberedSubject = [
+ ('no subject',
+ 'patch',
+ '',
+ []),
+ ('acceptable because it is not a git patch',
+ 'patch',
+ 'Subject: [PATCH 24/105] text\n',
+ []),
+ ('good',
+ 'patch',
+ 'Subject: [PATCH] text\n'
+ 'diff --git a/configure.ac b/configure.ac\n',
+ []),
+ ('bad',
+ 'patch',
+ 'Subject: [PATCH 24/105] text\n'
+ 'diff --git a/configure.ac b/configure.ac\n',
+ [["patch:1: generate your patches with 'git format-patch -N'",
+ 'Subject: [PATCH 24/105] text\n']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', NumberedSubject)
+def test_NumberedSubject(testname, filename, string, expected):
+ warnings = util.check_file(m.NumberedSubject, filename, string)
+ assert warnings == expected
+
+
+Sob = [
+ ('good',
+ 'patch',
+ 'Signed-off-by: John Doe <johndoe@example.com>\n',
+ []),
+ ('empty',
+ 'patch',
+ '',
+ [['patch:0: missing Signed-off-by in the header (url#_format_and_licensing_of_the_package_patches)']]),
+ ('bad',
+ 'patch',
+ 'Subject: [PATCH 24/105] text\n',
+ [['patch:0: missing Signed-off-by in the header (url#_format_and_licensing_of_the_package_patches)']]),
+ ]
+
+
+@pytest.mark.parametrize('testname,filename,string,expected', Sob)
+def test_Sob(testname, filename, string, expected):
+ warnings = util.check_file(m.Sob, filename, string)
+ assert warnings == expected
diff --git a/utils/checkpackagelib/test_util.py b/utils/checkpackagelib/test_util.py
new file mode 100644
index 0000000000..23f2995e27
--- /dev/null
+++ b/utils/checkpackagelib/test_util.py
@@ -0,0 +1,8 @@
+def check_file(check_function, filename, string):
+ obj = check_function(filename, 'url')
+ result = []
+ result.append(obj.before())
+ for i, line in enumerate(string.splitlines(True)):
+ result.append(obj.check_line(i + 1, line))
+ result.append(obj.after())
+ return [r for r in result if r is not None]
--
2.25.1
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest
2021-12-05 10:53 [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Ricardo Martincoski
@ 2021-12-05 10:53 ` Ricardo Martincoski
2022-01-09 10:51 ` Romain Naour
2021-12-05 10:53 ` [Buildroot] [PATCH-next 3/4] utils/checkpackagelib: run unit tests on GitLab CI Ricardo Martincoski
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Ricardo Martincoski @ 2021-12-05 10:53 UTC (permalink / raw)
To: buildroot; +Cc: Ricardo Martincoski
... so the unit tests for check-package can run in the GitLab CI.
Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
---
support/docker/Dockerfile | 1 +
1 file changed, 1 insertion(+)
diff --git a/support/docker/Dockerfile b/support/docker/Dockerfile
index 2aee129668..a5d54b6e9d 100644
--- a/support/docker/Dockerfile
+++ b/support/docker/Dockerfile
@@ -40,6 +40,7 @@ RUN apt-get install -y --no-install-recommends \
python3-flake8 \
python3-nose2 \
python3-pexpect \
+ python3-pytest \
qemu-system-arm \
qemu-system-x86 \
rsync \
--
2.25.1
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Buildroot] [PATCH-next 3/4] utils/checkpackagelib: run unit tests on GitLab CI
2021-12-05 10:53 [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest Ricardo Martincoski
@ 2021-12-05 10:53 ` Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 4/4] utils/docker-run: new script Ricardo Martincoski
2022-01-08 22:37 ` [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Romain Naour
3 siblings, 0 replies; 7+ messages in thread
From: Ricardo Martincoski @ 2021-12-05 10:53 UTC (permalink / raw)
To: buildroot; +Cc: Ricardo Martincoski
... so we can catch regressions on check-package.
Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
---
DO NOT APPLY before applying the patch before, generating a new docker
image, uploading it, and updating the image name in the .gitlab-ci.yml
---
support/misc/gitlab-ci.yml.in | 4 ++++
support/scripts/generate-gitlab-ci-yml | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/support/misc/gitlab-ci.yml.in b/support/misc/gitlab-ci.yml.in
index be7951b3d2..47e72c3213 100644
--- a/support/misc/gitlab-ci.yml.in
+++ b/support/misc/gitlab-ci.yml.in
@@ -1,3 +1,7 @@
+.check-check-package_base:
+ script:
+ - python3 -m pytest -v utils/checkpackagelib/
+
.check-DEVELOPERS_base:
# get-developers should print just "No action specified"; if it prints
# anything else, it's a parse error.
diff --git a/support/scripts/generate-gitlab-ci-yml b/support/scripts/generate-gitlab-ci-yml
index 7d09279bbd..bb023d8ed2 100755
--- a/support/scripts/generate-gitlab-ci-yml
+++ b/support/scripts/generate-gitlab-ci-yml
@@ -26,7 +26,7 @@ gen_tests() {
local do_basics do_defconfigs do_runtime do_testpkg
local defconfigs_ext cfg tst
- basics=( DEVELOPERS flake8 package )
+ basics=( check-package DEVELOPERS flake8 package )
defconfigs=( $(cd configs; LC_ALL=C ls -1 *_defconfig) )
--
2.25.1
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Buildroot] [PATCH-next 4/4] utils/docker-run: new script
2021-12-05 10:53 [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 3/4] utils/checkpackagelib: run unit tests on GitLab CI Ricardo Martincoski
@ 2021-12-05 10:53 ` Ricardo Martincoski
2022-01-08 22:37 ` [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Romain Naour
3 siblings, 0 replies; 7+ messages in thread
From: Ricardo Martincoski @ 2021-12-05 10:53 UTC (permalink / raw)
To: buildroot; +Cc: Ricardo Martincoski
Add a small script to run commands in the same docker image used in the
GitLab CI.
For instance, one can run check-package unit tests without installing
pytest directly in the host:
$ ./utils/docker-run python3 -m pytest -v utils/checkpackagelib/
Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
---
utils/docker-run | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100755 utils/docker-run
diff --git a/utils/docker-run b/utils/docker-run
new file mode 100755
index 0000000000..499c194d13
--- /dev/null
+++ b/utils/docker-run
@@ -0,0 +1,7 @@
+#!/usr/bin/bash
+set -o errexit -o pipefail
+DIR=$(dirname "${0}")
+MAIN_DIR=$(readlink -f "${DIR}/..")
+IMAGE=$(grep ^image: "${MAIN_DIR}/.gitlab-ci.yml" | sed -e 's,^image: ,,g' | sed -e 's,\$CI_REGISTRY,registry.gitlab.com,g')
+set -x
+docker run -v ${MAIN_DIR}:/home/br-user -t "${IMAGE}" $*
--
2.25.1
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests
2021-12-05 10:53 [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Ricardo Martincoski
` (2 preceding siblings ...)
2021-12-05 10:53 ` [Buildroot] [PATCH-next 4/4] utils/docker-run: new script Ricardo Martincoski
@ 2022-01-08 22:37 ` Romain Naour
2022-01-10 22:42 ` ricardo.martincoski
3 siblings, 1 reply; 7+ messages in thread
From: Romain Naour @ 2022-01-08 22:37 UTC (permalink / raw)
To: Ricardo Martincoski, buildroot
Hello Ricardo,
Le 05/12/2021 à 11:53, Ricardo Martincoski a écrit :
> So anyone willing to contribute to check-package can run all tests in
> less than 1 second by using:
> $ python3 -m pytest -v utils/checkpackagelib/
>
> Most test cases are in the form:
> @pytest.mark.parametrize('testname,filename,string,expected', function)
> - testname: a short description of the scenario tested, added in order
> to improve readability of the log when some tests fail
> - filename: the filename the check-package function being tested thinks
> it is testing
> - string: the content of the file being sent to the function under test
> - expect: all expected warnings that a given function from
> check-package should generate for a given file named filename and
> with string as its content.
I spend some time to review this patch to find something to say :)
Actually the test_lib_hash tests are not checking with the new spacing
convention we want to use in .hash files.
I applied this patch [1] after your series and some tests failed.
I would recommand to use the new spacing convention by default in this testsuite.
[1]
http://patchwork.ozlabs.org/project/buildroot/patch/20200603081253.14319-1-heiko.thiery@gmail.com/
Best regards,
Romain
>
> Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
> Cc: Arnout Vandecappelle <arnout@mind.be>
> ---
> NOTICE there are 2 tests failing, see the fix in:
> http://patchwork.ozlabs.org/project/buildroot/patch/20211115235336.3814968-1-ricardo.martincoski@gmail.com/
>
> See a sample running in the GitLab CI:
> without the fix:
> https://gitlab.com/RicardoMartincoski/buildroot/-/pipelines/422862195
> with the fix:
> https://gitlab.com/RicardoMartincoski/buildroot/-/pipelines/422862127
>
> Example of a failure, showing enough information to track down the test
> that fails:
> |testname = 'immediate assignment inside conditional and unconditional override outside'
> |filename = 'any.mk'
> |string = 'VAR_1 = VALUE1\nifeq (condition)\nVAR_1 := $(VAR_1), VALUE2\nendif\nVAR_1 := $(VAR_1), VALUE2\n'
> |expected = [['any.mk:3: immediate assignment to append to variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n'], ['any.mk:5: unconditional override of variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n']]
> |
> | @pytest.mark.parametrize('testname,filename,string,expected', overridden_variable)
> | def test_overridden_variable(testname, filename, string, expected):
> | warnings = util.check_file(m.OverriddenVariable, filename, string)
> |> assert warnings == expected
> |E AssertionError: assert [['any.mk:3: ...), VALUE2\n']] == [['any.mk:3: i...), VALUE2\n']]
> |E At index 0 diff: ['any.mk:3: conditional override of variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n'] != ['any.mk:3: immediate assignment to append to variable VAR_1', 'VAR_1 := $(VAR_1), VALUE2\n']
> |E Full diff:
> |E - [['any.mk:3: conditional override of variable VAR_1',
> |E + [['any.mk:3: immediate assignment to append to variable VAR_1',
> |E 'VAR_1 := $(VAR_1), VALUE2\n'],
> |E ['any.mk:5: unconditional override of variable VAR_1',
> |E 'VAR_1 := $(VAR_1), VALUE2\n']]
> |
> |utils/checkpackagelib/test_lib_mk.py:168: AssertionError
> |===================== 2 failed, 180 passed in 0.79 seconds =====================
> ---
> utils/checkpackagelib/test_lib.py | 212 ++++++++
> utils/checkpackagelib/test_lib_config.py | 387 +++++++++++++++
> utils/checkpackagelib/test_lib_hash.py | 137 ++++++
> utils/checkpackagelib/test_lib_mk.py | 590 +++++++++++++++++++++++
> utils/checkpackagelib/test_lib_patch.py | 96 ++++
> utils/checkpackagelib/test_util.py | 8 +
> 6 files changed, 1430 insertions(+)
> create mode 100644 utils/checkpackagelib/test_lib.py
> create mode 100644 utils/checkpackagelib/test_lib_config.py
> create mode 100644 utils/checkpackagelib/test_lib_hash.py
> create mode 100644 utils/checkpackagelib/test_lib_mk.py
> create mode 100644 utils/checkpackagelib/test_lib_patch.py
> create mode 100644 utils/checkpackagelib/test_util.py
>
> diff --git a/utils/checkpackagelib/test_lib.py b/utils/checkpackagelib/test_lib.py
> new file mode 100644
> index 0000000000..976a63d84d
> --- /dev/null
> +++ b/utils/checkpackagelib/test_lib.py
> @@ -0,0 +1,212 @@
> +import pytest
> +import checkpackagelib.test_util as util
> +import checkpackagelib.lib as m
> +
> +
> +ConsecutiveEmptyLines = [
> + ('1 line (no newline)',
> + 'any',
> + '',
> + []),
> + ('1 line',
> + 'any',
> + '\n',
> + []),
> + ('2 lines',
> + 'any',
> + '\n'
> + '\n',
> + [['any:2: consecutive empty lines']]),
> + ('more than 2 consecutive',
> + 'any',
> + '\n'
> + '\n'
> + '\n',
> + [['any:2: consecutive empty lines'],
> + ['any:3: consecutive empty lines']]),
> + ('ignore whitespace 1',
> + 'any',
> + '\n'
> + ' ',
> + [['any:2: consecutive empty lines']]),
> + ('ignore whitespace 2',
> + 'any',
> + ' \n'
> + '\t\n',
> + [['any:2: consecutive empty lines']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', ConsecutiveEmptyLines)
> +def test_ConsecutiveEmptyLines(testname, filename, string, expected):
> + warnings = util.check_file(m.ConsecutiveEmptyLines, filename, string)
> + assert warnings == expected
> +
> +
> +EmptyLastLine = [
> + ('ignore empty file',
> + 'any',
> + '',
> + []),
> + ('empty line (newline)',
> + 'any',
> + '\n',
> + [['any:1: empty line at end of file']]),
> + ('empty line (space, newline)',
> + 'any',
> + ' \n',
> + [['any:1: empty line at end of file']]),
> + ('empty line (space, no newline)',
> + 'any',
> + ' ',
> + [['any:1: empty line at end of file']]),
> + ('warn for the last of 2',
> + 'any',
> + '\n'
> + '\n',
> + [['any:2: empty line at end of file']]),
> + ('warn for the last of 3',
> + 'any',
> + '\n'
> + '\n'
> + '\n',
> + [['any:3: empty line at end of file']]),
> + ('ignore whitespace',
> + 'any',
> + ' \n'
> + '\t\n',
> + [['any:2: empty line at end of file']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', EmptyLastLine)
> +def test_EmptyLastLine(testname, filename, string, expected):
> + warnings = util.check_file(m.EmptyLastLine, filename, string)
> + assert warnings == expected
> +
> +
> +NewlineAtEof = [
> + ('good',
> + 'any',
> + 'text\n',
> + []),
> + ('text (bad)',
> + 'any',
> + '\n'
> + 'text',
> + [['any:2: missing newline at end of file',
> + 'text']]),
> + ('space (bad)',
> + 'any',
> + '\n'
> + ' ',
> + [['any:2: missing newline at end of file',
> + ' ']]),
> + ('tab (bad)',
> + 'any',
> + '\n'
> + '\t',
> + [['any:2: missing newline at end of file',
> + '\t']]),
> + ('even for file with one line',
> + 'any',
> + ' ',
> + [['any:1: missing newline at end of file',
> + ' ']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', NewlineAtEof)
> +def test_NewlineAtEof(testname, filename, string, expected):
> + warnings = util.check_file(m.NewlineAtEof, filename, string)
> + assert warnings == expected
> +
> +
> +TrailingSpace = [
> + ('good',
> + 'any',
> + 'text\n',
> + []),
> + ('ignore missing newline',
> + 'any',
> + '\n'
> + 'text',
> + []),
> + ('spaces',
> + 'any',
> + 'text \n',
> + [['any:1: line contains trailing whitespace',
> + 'text \n']]),
> + ('tabs after text',
> + 'any',
> + 'text\t\t\n',
> + [['any:1: line contains trailing whitespace',
> + 'text\t\t\n']]),
> + ('mix of tabs and spaces',
> + 'any',
> + ' \n'
> + ' ',
> + [['any:1: line contains trailing whitespace',
> + ' \n'],
> + ['any:2: line contains trailing whitespace',
> + ' ']]),
> + ('blank line with tabs',
> + 'any',
> + '\n'
> + '\t',
> + [['any:2: line contains trailing whitespace',
> + '\t']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', TrailingSpace)
> +def test_TrailingSpace(testname, filename, string, expected):
> + warnings = util.check_file(m.TrailingSpace, filename, string)
> + assert warnings == expected
> +
> +
> +Utf8Characters = [
> + ('usual',
> + 'any',
> + 'text\n',
> + []),
> + ('acceptable character',
> + 'any',
> + '\x60',
> + []),
> + ('unacceptable character',
> + 'any',
> + '\x81',
> + [['any:1: line contains UTF-8 characters',
> + '\x81']]),
> + ('2 warnings',
> + 'any',
> + 'text\n'
> + 'text \xc8 text\n'
> + '\xc9\n',
> + [['any:2: line contains UTF-8 characters',
> + 'text \xc8 text\n'],
> + ['any:3: line contains UTF-8 characters',
> + '\xc9\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', Utf8Characters)
> +def test_Utf8Characters(testname, filename, string, expected):
> + warnings = util.check_file(m.Utf8Characters, filename, string)
> + assert warnings == expected
> +
> +
> +def test_all_check_functions_are_used():
> + import inspect
> + import checkpackagelib.lib_config as lib_config
> + import checkpackagelib.lib_hash as lib_hash
> + import checkpackagelib.lib_mk as lib_mk
> + import checkpackagelib.lib_patch as lib_patch
> + c_config = [c[0] for c in inspect.getmembers(lib_config, inspect.isclass)]
> + c_hash = [c[0] for c in inspect.getmembers(lib_hash, inspect.isclass)]
> + c_mk = [c[0] for c in inspect.getmembers(lib_mk, inspect.isclass)]
> + c_patch = [c[0] for c in inspect.getmembers(lib_patch, inspect.isclass)]
> + c_all = c_config + c_hash + c_mk + c_patch
> + c_common = [c[0] for c in inspect.getmembers(m, inspect.isclass)]
> + assert set(c_common) <= set(c_all)
> diff --git a/utils/checkpackagelib/test_lib_config.py b/utils/checkpackagelib/test_lib_config.py
> new file mode 100644
> index 0000000000..91a549adf2
> --- /dev/null
> +++ b/utils/checkpackagelib/test_lib_config.py
> @@ -0,0 +1,387 @@
> +import pytest
> +import checkpackagelib.test_util as util
> +import checkpackagelib.lib_config as m
> +
> +
> +AttributesOrder = [
> + ('good example',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'default y\n'
> + 'depends on BR2_USE_BAR # runtime\n'
> + 'select BR2_PACKAGE_BAZ\n'
> + 'help\n'
> + '\t help text\n',
> + []),
> + ('depends before default',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'depends on BR2_USE_BAR\n'
> + 'default y\n',
> + [['any:4: attributes order: type, default, depends on, select, help (url#_config_files)',
> + 'default y\n']]),
> + ('select after help',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'help\n'
> + '\t help text\n'
> + 'select BR2_PACKAGE_BAZ\n',
> + [['any:5: attributes order: type, default, depends on, select, help (url#_config_files)',
> + 'select BR2_PACKAGE_BAZ\n']]),
> + ('string',
> + 'any',
> + 'config BR2_PACKAGE_FOO_PLUGINS\n'
> + 'string "foo plugins"\n'
> + 'default "all"\n',
> + []),
> + ('ignore tabs',
> + 'any',
> + 'config\tBR2_PACKAGE_FOO_PLUGINS\n'
> + 'default\t"all"\n'
> + 'string\t"foo plugins"\n',
> + [['any:3: attributes order: type, default, depends on, select, help (url#_config_files)',
> + 'string\t"foo plugins"\n']]),
> + ('choice',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'if BR2_PACKAGE_FOO\n'
> + '\n'
> + 'choice\n'
> + 'prompt "type of foo"\n'
> + 'default BR2_PACKAGE_FOO_STRING\n'
> + '\n'
> + 'config BR2_PACKAGE_FOO_NONE\n'
> + 'bool "none"\n'
> + '\n'
> + 'config BR2_PACKAGE_FOO_STRING\n'
> + 'bool "string"\n'
> + '\n'
> + 'endchoice\n'
> + '\n'
> + 'endif\n'
> + '\n',
> + []),
> + ('type after default',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'if BR2_PACKAGE_FOO\n'
> + '\n'
> + 'choice\n'
> + 'default BR2_PACKAGE_FOO_STRING\n'
> + 'prompt "type of foo"\n',
> + [['any:7: attributes order: type, default, depends on, select, help (url#_config_files)',
> + 'prompt "type of foo"\n']]),
> + ('menu',
> + 'any',
> + 'menuconfig BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'help\n'
> + '\t help text\n'
> + '\t help text\n'
> + '\n'
> + 'if BR2_PACKAGE_FOO\n'
> + '\n'
> + 'menu "foo plugins"\n'
> + 'config BR2_PACKAGE_FOO_COUNTER\n'
> + 'bool "counter"\n'
> + '\n'
> + 'endmenu\n'
> + '\n'
> + 'endif\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', AttributesOrder)
> +def test_AttributesOrder(testname, filename, string, expected):
> + warnings = util.check_file(m.AttributesOrder, filename, string)
> + assert warnings == expected
> +
> +
> +CommentsMenusPackagesOrder = [
> + ('top menu (good)',
> + 'package/Config.in',
> + 'menu "Target packages"\n'
> + 'source "package/busybox/Config.in"\n'
> + 'source "package/skeleton/Config.in"\n',
> + []),
> + ('top menu (bad)',
> + 'package/Config.in',
> + 'source "package/skeleton/Config.in"\n'
> + 'source "package/busybox/Config.in"\n',
> + [['package/Config.in:2: Packages in: The top level menu,\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: busybox',
> + 'source "package/busybox/Config.in"\n']]),
> + ('menu (bad)',
> + 'package/Config.in',
> + 'menu "Target packages"\n'
> + 'source "package/skeleton/Config.in"\n'
> + 'source "package/busybox/Config.in"\n',
> + [['package/Config.in:3: Packages in: menu "Target packages",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: busybox',
> + 'source "package/busybox/Config.in"\n']]),
> + ('underscore (good)',
> + 'package/Config.in.host',
> + 'menu "Hardware handling"\n'
> + 'menu "Firmware"\n'
> + 'endmenu\n'
> + 'source "package/usb_modeswitch/Config.in"\n'
> + 'source "package/usbmount/Config.in"\n',
> + []),
> + ('underscore (bad)',
> + 'package/Config.in.host',
> + 'menu "Hardware handling"\n'
> + 'menu "Firmware"\n'
> + 'endmenu\n'
> + 'source "package/usbmount/Config.in"\n'
> + 'source "package/usb_modeswitch/Config.in"\n',
> + [['package/Config.in.host:5: Packages in: menu "Hardware handling",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: usb_modeswitch',
> + 'source "package/usb_modeswitch/Config.in"\n']]),
> + ('ignore other files',
> + 'any other file',
> + 'menu "Hardware handling"\n'
> + 'source "package/bbb/Config.in"\n'
> + 'source "package/aaa/Config.in"\n',
> + []),
> + ('dash (bad)',
> + 'package/Config.in',
> + 'menu "packages"\n'
> + 'source "package/a_a/Config.in"\n'
> + 'source "package/a-a/Config.in"\n'
> + 'source "package/a1a/Config.in"\n'
> + 'source "package/aAa/Config.in"\n'
> + 'source "package/aaa/Config.in"\n',
> + [['package/Config.in:3: Packages in: menu "packages",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: a-a',
> + 'source "package/a-a/Config.in"\n']]),
> + ('underscore (bad)',
> + 'package/Config.in',
> + 'menu "packages"\n'
> + 'source "package/a-a/Config.in"\n'
> + 'source "package/a1a/Config.in"\n'
> + 'source "package/a_a/Config.in"\n'
> + 'source "package/aAa/Config.in"\n'
> + 'source "package/aaa/Config.in"\n',
> + [['package/Config.in:4: Packages in: menu "packages",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: a_a',
> + 'source "package/a_a/Config.in"\n']]),
> + ('digit (bad)',
> + 'package/Config.in',
> + 'menu "packages"\n'
> + 'source "package/a-a/Config.in"\n'
> + 'source "package/a_a/Config.in"\n'
> + 'source "package/aAa/Config.in"\n'
> + 'source "package/a1a/Config.in"\n'
> + 'source "package/aaa/Config.in"\n',
> + [['package/Config.in:5: Packages in: menu "packages",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: a1a',
> + 'source "package/a1a/Config.in"\n']]),
> + ('capitals (bad)',
> + 'package/Config.in',
> + 'menu "packages"\n'
> + 'source "package/a-a/Config.in"\n'
> + 'source "package/a_a/Config.in"\n'
> + 'source "package/a1a/Config.in"\n'
> + 'source "package/aaa/Config.in"\n'
> + 'source "package/aAa/Config.in"\n',
> + [['package/Config.in:6: Packages in: menu "packages",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: aAa',
> + 'source "package/aAa/Config.in"\n']]),
> + ('digits, capitals, underscore (good)',
> + 'package/Config.in',
> + 'menu "packages"\n'
> + 'source "package/a-a/Config.in"\n'
> + 'source "package/a_a/Config.in"\n'
> + 'source "package/a1a/Config.in"\n'
> + 'source "package/aAa/Config.in"\n'
> + 'source "package/aaa/Config.in"\n',
> + []),
> + ('conditional menu (good)',
> + 'package/Config.in',
> + 'menu "Other"\n'
> + 'source "package/linux-pam/Config.in"\n'
> + 'if BR2_PACKAGE_LINUX_PAM\n'
> + 'comment "linux-pam plugins"\n'
> + 'source "package/libpam-radius-auth/Config.in"\n'
> + 'source "package/libpam-tacplus/Config.in"\n'
> + 'endif\n'
> + 'source "package/liquid-dsp/Config.in"\n',
> + []),
> + ('conditional menu (bad)',
> + 'package/Config.in',
> + 'menu "Other"\n'
> + 'source "package/linux-pam/Config.in"\n'
> + 'if BR2_PACKAGE_LINUX_PAM\n'
> + 'comment "linux-pam plugins"\n'
> + 'source "package/libpam-tacplus/Config.in"\n'
> + 'source "package/libpam-radius-auth/Config.in"\n'
> + 'endif\n'
> + 'source "package/liquid-dsp/Config.in"\n',
> + [['package/Config.in:6: Packages in: comment "linux-pam plugins",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: libpam-radius-auth',
> + 'source "package/libpam-radius-auth/Config.in"\n']]),
> + ('no conditional (bad)',
> + 'package/Config.in',
> + 'menu "Other"\n'
> + 'source "package/linux-pam/Config.in"\n'
> + 'source "package/libpam-radius-auth/Config.in"\n'
> + 'source "package/libpam-tacplus/Config.in"\n'
> + 'source "package/liquid-dsp/Config.in"\n',
> + [['package/Config.in:3: Packages in: menu "Other",\n'
> + ' are not alphabetically ordered;\n'
> + " correct order: '-', '_', digits, capitals, lowercase;\n"
> + ' first incorrect package: libpam-radius-auth',
> + 'source "package/libpam-radius-auth/Config.in"\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', CommentsMenusPackagesOrder)
> +def test_CommentsMenusPackagesOrder(testname, filename, string, expected):
> + warnings = util.check_file(m.CommentsMenusPackagesOrder, filename, string)
> + assert warnings == expected
> +
> +
> +HelpText = [
> + ('single line',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'bool "foo"\n'
> + 'default y\n'
> + 'depends on BR2_USE_BAR # runtime\n'
> + 'select BR2_PACKAGE_BAZ\n'
> + 'help\n'
> + '\t help text\n',
> + []),
> + ('larger than 72',
> + 'any',
> + 'help\n'
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 123\n'
> + '\t help text\n',
> + [['any:3: help text: <tab><2 spaces><62 chars> (url#writing-rules-config-in)',
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 123\n',
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12']]),
> + ('long url at beginning of line',
> + 'any',
> + 'help\n'
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
> + '\t http://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
> + '\t https://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
> + '\t git://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
> + []),
> + ('long url not at beginning of line',
> + 'any',
> + 'help\n'
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
> + '\t refer to http://url.that.is.longer.than.seventy.two.characthers/folder_name\n'
> + '\n'
> + '\t http://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
> + [['any:3: help text: <tab><2 spaces><62 chars> (url#writing-rules-config-in)',
> + '\t refer to http://url.that.is.longer.than.seventy.two.characthers/folder_name\n',
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12']]),
> + ('allow beautified items',
> + 'any',
> + 'help\n'
> + '\t 123456789 123456789 123456789 123456789 123456789 123456789 12\n'
> + '\t summary:\n'
> + '\t - enable that config\n'
> + '\t - built it\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', HelpText)
> +def test_HelpText(testname, filename, string, expected):
> + warnings = util.check_file(m.HelpText, filename, string)
> + assert warnings == expected
> +
> +
> +Indent = [
> + ('good example',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + '\tbool "foo"\n'
> + '\tdefault y\n'
> + '\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n'
> + '\tdepends on BR2_INSTALL_LIBSTDCPP\n'
> + '# very useful comment\n'
> + '\tselect BR2_PACKAGE_BAZ\n'
> + '\thelp\n'
> + '\t help text\n'
> + '\n'
> + 'comment "foo needs toolchain w/ C++, threads"\n'
> + '\tdepends on !BR2_INSTALL_LIBSTDCPP || \\\n'
> + '\t\t!BR2_TOOLCHAIN_HAS_THREADS\n'
> + '\n'
> + 'source "package/foo/bar/Config.in"\n',
> + []),
> + ('spaces',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + ' bool "foo"\n',
> + [['any:2: should be indented with one tab (url#_config_files)',
> + ' bool "foo"\n']]),
> + ('without indent',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + 'default y\n',
> + [['any:2: should be indented with one tab (url#_config_files)',
> + 'default y\n']]),
> + ('too much tabs',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + '\t\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n',
> + [['any:2: should be indented with one tab (url#_config_files)',
> + '\t\tdepends on BR2_TOOLCHAIN_HAS_THREADS\n']]),
> + ('help',
> + 'any',
> + 'config BR2_PACKAGE_FOO\n'
> + ' help\n',
> + [['any:2: should be indented with one tab (url#_config_files)',
> + ' help\n']]),
> + ('continuation line',
> + 'any',
> + 'comment "foo needs toolchain w/ C++, threads"\n'
> + '\tdepends on !BR2_INSTALL_LIBSTDCPP || \\\n'
> + ' !BR2_TOOLCHAIN_HAS_THREADS\n',
> + [['any:3: continuation line should be indented using tabs',
> + ' !BR2_TOOLCHAIN_HAS_THREADS\n']]),
> + ('comment with tabs',
> + 'any',
> + '\tcomment "foo needs toolchain w/ C++, threads"\n',
> + [['any:1: should not be indented',
> + '\tcomment "foo needs toolchain w/ C++, threads"\n']]),
> + ('comment with spaces',
> + 'any',
> + ' comment "foo needs toolchain w/ C++, threads"\n',
> + [['any:1: should not be indented',
> + ' comment "foo needs toolchain w/ C++, threads"\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', Indent)
> +def test_Indent(testname, filename, string, expected):
> + warnings = util.check_file(m.Indent, filename, string)
> + assert warnings == expected
> diff --git a/utils/checkpackagelib/test_lib_hash.py b/utils/checkpackagelib/test_lib_hash.py
> new file mode 100644
> index 0000000000..c160a394e9
> --- /dev/null
> +++ b/utils/checkpackagelib/test_lib_hash.py
> @@ -0,0 +1,137 @@
> +import pytest
> +import checkpackagelib.test_util as util
> +import checkpackagelib.lib_hash as m
> +
> +
> +HashNumberOfFields = [
> + ('empty file',
> + 'any',
> + '',
> + []),
> + ('empty line',
> + 'any',
> + '\n',
> + []),
> + ('ignore whitespace',
> + 'any',
> + '\t\n',
> + []),
> + ('ignore comments',
> + 'any',
> + '# text\n',
> + []),
> + ('1 field',
> + 'any',
> + 'field1\n',
> + [['any:1: expected three fields (url#adding-packages-hash)',
> + 'field1\n']]),
> + ('2 fields',
> + 'any',
> + 'field1 field2\n',
> + [['any:1: expected three fields (url#adding-packages-hash)',
> + 'field1 field2\n']]),
> + ('4 fields',
> + 'any',
> + 'field1 field2 field3 field4\n',
> + [['any:1: expected three fields (url#adding-packages-hash)',
> + 'field1 field2 field3 field4\n']]),
> + ('with 1 space',
> + 'any',
> + 'field1 field2 field3\n',
> + []),
> + ('many spaces',
> + 'any',
> + ' field1 field2 field3\n',
> + []),
> + ('tabs',
> + 'any',
> + 'field1\tfield2\tfield3\n',
> + []),
> + ('mix of tabs and spaces',
> + 'any',
> + '\tfield1\t field2\t field3 \n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', HashNumberOfFields)
> +def test_HashNumberOfFields(testname, filename, string, expected):
> + warnings = util.check_file(m.HashNumberOfFields, filename, string)
> + assert warnings == expected
> +
> +
> +HashType = [
> + ('ignore empty files',
> + 'any',
> + '',
> + []),
> + ('ignore 1 field',
> + 'any',
> + 'text\n',
> + []),
> + ('wrong type',
> + 'any',
> + 'text text\n',
> + [['any:1: unexpected type of hash (url#adding-packages-hash)',
> + 'text text\n']]),
> + ('none',
> + 'any',
> + 'none text\n',
> + []),
> + ('md5 (good)',
> + 'any',
> + 'md5 12345678901234567890123456789012\n',
> + []),
> + ('md5 (short)',
> + 'any',
> + 'md5 123456\n',
> + [['any:1: hash size does not match type (url#adding-packages-hash)',
> + 'md5 123456\n',
> + 'expected 32 hex digits']]),
> + ('ignore space before',
> + 'any',
> + ' md5 12345678901234567890123456789012\n',
> + []),
> + ('2 spaces',
> + 'any',
> + 'md5 12345678901234567890123456789012\n',
> + []),
> + ('ignore tabs',
> + 'any',
> + 'md5\t12345678901234567890123456789012\n',
> + []),
> + ('common typo',
> + 'any',
> + 'md5sum 12345678901234567890123456789012\n',
> + [['any:1: unexpected type of hash (url#adding-packages-hash)',
> + 'md5sum 12345678901234567890123456789012\n']]),
> + ('md5 (too long)',
> + 'any',
> + 'md5 123456789012345678901234567890123\n',
> + [['any:1: hash size does not match type (url#adding-packages-hash)',
> + 'md5 123456789012345678901234567890123\n',
> + 'expected 32 hex digits']]),
> + ('sha1 (good)',
> + 'any',
> + 'sha1 1234567890123456789012345678901234567890\n',
> + []),
> + ('sha256',
> + 'any',
> + 'sha256 1234567890123456789012345678901234567890123456789012345678901234\n',
> + []),
> + ('sha384',
> + 'any',
> + 'sha384 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\n',
> + []),
> + ('sha512',
> + 'any',
> + 'sha512 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'
> + '9012345678\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', HashType)
> +def test_HashType(testname, filename, string, expected):
> + warnings = util.check_file(m.HashType, filename, string)
> + assert warnings == expected
> diff --git a/utils/checkpackagelib/test_lib_mk.py b/utils/checkpackagelib/test_lib_mk.py
> new file mode 100644
> index 0000000000..49fa216fcd
> --- /dev/null
> +++ b/utils/checkpackagelib/test_lib_mk.py
> @@ -0,0 +1,590 @@
> +import pytest
> +import checkpackagelib.test_util as util
> +import checkpackagelib.lib_mk as m
> +
> +
> +Indent = [
> + ('ignore comment at beginning of line',
> + 'any',
> + '# very useful comment\n',
> + []),
> + ('ignore comment at end of line',
> + 'any',
> + ' # very useful comment\n',
> + []),
> + ('do not indent on conditional (good)',
> + 'any',
> + 'ifeq ($(BR2_TOOLCHAIN_HAS_THREADS),y)\n'
> + 'FOO_CONF_OPTS += something\n'
> + 'endef\n',
> + []),
> + ('do not indent on conditional (bad)',
> + 'any',
> + 'ifeq ($(BR2_TOOLCHAIN_HAS_THREADS),y)\n'
> + '\tFOO_CONF_OPTS += something\n'
> + 'endef\n',
> + [['any:2: unexpected indent with tabs',
> + '\tFOO_CONF_OPTS += something\n']]),
> + ('indent after line that ends in backslash (good)',
> + 'any',
> + 'FOO_CONF_OPTS += \\\n'
> + '\tsomething\n',
> + []),
> + ('indent after line that ends in backslash (bad)',
> + 'any',
> + 'FOO_CONF_OPTS += \\\n'
> + 'something\n',
> + [['any:2: expected indent with tabs',
> + 'something\n']]),
> + ('indent after 2 lines that ends in backslash (good)',
> + 'any',
> + 'FOO_CONF_OPTS += \\\n'
> + '\tsomething \\\n'
> + '\tsomething_else\n',
> + []),
> + ('indent after 2 lines that ends in backslash (bad)',
> + 'any',
> + 'FOO_CONF_OPTS += \\\n'
> + '\tsomething \\\n'
> + '\tsomething_else \\\n'
> + 'FOO_CONF_OPTS += another_thing\n',
> + [['any:4: expected indent with tabs',
> + 'FOO_CONF_OPTS += another_thing\n']]),
> + ('indent inside define (good)',
> + 'any',
> + 'define FOO_SOMETHING\n'
> + '\tcommand\n'
> + '\tcommand \\\n'
> + '\t\targuments\n'
> + 'endef\n'
> + 'FOO_POST_PATCH_HOOKS += FOO_SOMETHING\n',
> + []),
> + ('indent inside define (bad, no indent)',
> + 'any',
> + 'define FOO_SOMETHING\n'
> + 'command\n'
> + 'endef\n',
> + [['any:2: expected indent with tabs',
> + 'command\n']]),
> + ('indent inside define (bad, spaces)',
> + 'any',
> + 'define FOO_SOMETHING\n'
> + ' command\n'
> + 'endef\n',
> + [['any:2: expected indent with tabs',
> + ' command\n']]),
> + ('indent make target (good)',
> + 'any',
> + 'make_target:\n'
> + '\tcommand\n'
> + '\n',
> + []),
> + ('indent make target (bad)',
> + 'any',
> + 'make_target:\n'
> + ' command\n'
> + '\n',
> + [['any:2: expected indent with tabs',
> + ' command\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', Indent)
> +def test_Indent(testname, filename, string, expected):
> + warnings = util.check_file(m.Indent, filename, string)
> + assert warnings == expected
> +
> +
> +OverriddenVariable = [
> + ('simple assignment',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n',
> + []),
> + ('unconditional override (variable without underscore)',
> + 'any.mk',
> + 'VAR1 = VALUE1\n'
> + 'VAR1 = VALUE1\n',
> + [['any.mk:2: unconditional override of variable VAR1',
> + 'VAR1 = VALUE1\n']]),
> + ('unconditional override (variable with underscore, same value)',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'VAR_1 = VALUE1\n',
> + [['any.mk:2: unconditional override of variable VAR_1',
> + 'VAR_1 = VALUE1\n']]),
> + ('unconditional override (variable with underscore, different value)',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'VAR_1 = VALUE2\n',
> + [['any.mk:2: unconditional override of variable VAR_1',
> + 'VAR_1 = VALUE2\n']]),
> + ('warn for unconditional override even with wrong number of spaces',
> + 'any.mk',
> + 'VAR_1= VALUE1\n'
> + 'VAR_1 =VALUE2\n',
> + [['any.mk:2: unconditional override of variable VAR_1',
> + 'VAR_1 =VALUE2\n']]),
> + ('warn for := override',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'VAR_1 := VALUE2\n',
> + [['any.mk:2: unconditional override of variable VAR_1',
> + 'VAR_1 := VALUE2\n']]),
> + ('append values outside conditional (good)',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'VAR_1 += VALUE2\n',
> + []),
> + ('append values outside conditional (bad)',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'VAR_1 := $(VAR_1), VALUE2\n',
> + [['any.mk:2: unconditional override of variable VAR_1',
> + 'VAR_1 := $(VAR_1), VALUE2\n']]),
> + ('immediate assignment inside conditional',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'ifeq (condition)\n'
> + 'VAR_1 := $(VAR_1), VALUE2\n',
> + [['any.mk:3: immediate assignment to append to variable VAR_1',
> + 'VAR_1 := $(VAR_1), VALUE2\n']]),
> + ('immediate assignment inside conditional and unconditional override outside',
> + 'any.mk',
> + 'VAR_1 = VALUE1\n'
> + 'ifeq (condition)\n'
> + 'VAR_1 := $(VAR_1), VALUE2\n'
> + 'endif\n'
> + 'VAR_1 := $(VAR_1), VALUE2\n',
> + [['any.mk:3: immediate assignment to append to variable VAR_1',
> + 'VAR_1 := $(VAR_1), VALUE2\n'],
> + ['any.mk:5: unconditional override of variable VAR_1',
> + 'VAR_1 := $(VAR_1), VALUE2\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', OverriddenVariable)
> +def test_OverriddenVariable(testname, filename, string, expected):
> + warnings = util.check_file(m.OverriddenVariable, filename, string)
> + assert warnings == expected
> +
> +
> +PackageHeader = [
> + ('first line (good)',
> + 'any',
> + 80 * '#' + '\n',
> + []),
> + ('first line (bad)',
> + 'any',
> + '# very useful comment\n',
> + [['any:1: should be 80 hashes (url#writing-rules-mk)',
> + '# very useful comment\n',
> + 80 * '#']]),
> + ('second line (bad)',
> + 'any',
> + 80 * '#' + '\n'
> + '# package\n',
> + [['any:2: should be 1 hash (url#writing-rules-mk)',
> + '# package\n']]),
> + ('full header (good)',
> + 'any',
> + 80 * '#' + '\n'
> + '#\n'
> + '# package\n'
> + '#\n' +
> + 80 * '#' + '\n'
> + '\n',
> + []),
> + ('blank line after header (good)',
> + 'any',
> + 80 * '#' + '\n'
> + '#\n'
> + '# package\n'
> + '#\n' +
> + 80 * '#' + '\n'
> + '\n'
> + 'FOO_VERSION = 1\n',
> + []),
> + ('blank line after header (bad)',
> + 'any',
> + 80 * '#' + '\n'
> + '#\n'
> + '# package\n'
> + '#\n' +
> + 80 * '#' + '\n'
> + 'FOO_VERSION = 1\n',
> + [['any:6: should be a blank line (url#writing-rules-mk)',
> + 'FOO_VERSION = 1\n']]),
> + ('wrong number of hashes',
> + 'any',
> + 79 * '#' + '\n'
> + '#\n'
> + '# package\n'
> + '#\n' +
> + 81 * '#' + '\n'
> + '\n',
> + [['any:1: should be 80 hashes (url#writing-rules-mk)',
> + 79 * '#' + '\n',
> + 80 * '#'],
> + ['any:5: should be 80 hashes (url#writing-rules-mk)',
> + 81 * '#' + '\n',
> + 80 * '#']]),
> + ('allow include without header',
> + 'any',
> + 'include $(sort $(wildcard package/foo/*/*.mk))\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', PackageHeader)
> +def test_PackageHeader(testname, filename, string, expected):
> + warnings = util.check_file(m.PackageHeader, filename, string)
> + assert warnings == expected
> +
> +
> +RemoveDefaultPackageSourceVariable = [
> + ('bad',
> + 'any.mk',
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
> + [['any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
> + ('bad with path',
> + './any.mk',
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
> + [['./any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
> + ('warn for correct line',
> + './any.mk',
> + '\n'
> + '\n'
> + '\n'
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n',
> + [['./any.mk:4: remove default value of _SOURCE variable (url#generic-package-reference)',
> + 'ANY_SOURCE = any-$(ANY_VERSION).tar.gz\n']]),
> + ('warn ignoring missing spaces',
> + './any.mk',
> + 'ANY_SOURCE=any-$(ANY_VERSION).tar.gz\n',
> + [['./any.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
> + 'ANY_SOURCE=any-$(ANY_VERSION).tar.gz\n']]),
> + ('good',
> + './any.mk',
> + 'ANY_SOURCE = aNy-$(ANY_VERSION).tar.gz\n',
> + []),
> + ('gcc exception',
> + 'gcc.mk',
> + 'GCC_SOURCE = gcc-$(GCC_VERSION).tar.gz\n',
> + []),
> + ('binutils exception',
> + './binutils.mk',
> + 'BINUTILS_SOURCE = binutils-$(BINUTILS_VERSION).tar.gz\n',
> + []),
> + ('gdb exception',
> + 'gdb/gdb.mk',
> + 'GDB_SOURCE = gdb-$(GDB_VERSION).tar.gz\n',
> + []),
> + ('package name with dash',
> + 'python-subprocess32.mk',
> + 'PYTHON_SUBPROCESS32_SOURCE = python-subprocess32-$(PYTHON_SUBPROCESS32_VERSION).tar.gz\n',
> + [['python-subprocess32.mk:1: remove default value of _SOURCE variable (url#generic-package-reference)',
> + 'PYTHON_SUBPROCESS32_SOURCE = python-subprocess32-$(PYTHON_SUBPROCESS32_VERSION).tar.gz\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', RemoveDefaultPackageSourceVariable)
> +def test_RemoveDefaultPackageSourceVariable(testname, filename, string, expected):
> + warnings = util.check_file(m.RemoveDefaultPackageSourceVariable, filename, string)
> + assert warnings == expected
> +
> +
> +SpaceBeforeBackslash = [
> + ('no backslash',
> + 'any.mk',
> + '\n',
> + []),
> + ('ignore missing indent',
> + 'any.mk',
> + 'define ANY_SOME_FIXUP\n'
> + 'for i in $$(find $(STAGING_DIR)/usr/lib* -name "any*.la"); do \\\n',
> + []),
> + ('ignore missing space',
> + 'any.mk',
> + 'ANY_CONF_ENV= \\\n'
> + '\tap_cv_void_ptr_lt_long=no \\\n',
> + []),
> + ('variable',
> + 'any.mk',
> + '\n'
> + 'ANY = \\\n',
> + []),
> + ('2 spaces',
> + 'any.mk',
> + 'ANY = \\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY = \\\n']]),
> + ('warn about correct line',
> + 'any.mk',
> + '\n'
> + 'ANY = \\\n',
> + [['any.mk:2: use only one space before backslash',
> + 'ANY = \\\n']]),
> + ('tab',
> + 'any.mk',
> + 'ANY =\t\\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY =\t\\\n']]),
> + ('tabs',
> + 'any.mk',
> + 'ANY =\t\t\\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY =\t\t\\\n']]),
> + ('spaces and tabs',
> + 'any.mk',
> + 'ANY = \t\t\\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY = \t\t\\\n']]),
> + ('mixed spaces and tabs 1',
> + 'any.mk',
> + 'ANY = \t \t\\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY = \t \t\\\n']]),
> + ('mixed spaces and tabs 2',
> + 'any.mk',
> + 'ANY = \t \\\n',
> + [['any.mk:1: use only one space before backslash',
> + 'ANY = \t \\\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', SpaceBeforeBackslash)
> +def test_SpaceBeforeBackslash(testname, filename, string, expected):
> + warnings = util.check_file(m.SpaceBeforeBackslash, filename, string)
> + assert warnings == expected
> +
> +
> +TrailingBackslash = [
> + ('no backslash',
> + 'any.mk',
> + 'ANY = \n',
> + []),
> + ('one line',
> + 'any.mk',
> + 'ANY = \\\n',
> + []),
> + ('2 lines',
> + 'any.mk',
> + 'ANY = \\\n'
> + '\\\n',
> + []),
> + ('empty line after',
> + 'any.mk',
> + 'ANY = \\\n'
> + '\n',
> + [['any.mk:1: remove trailing backslash',
> + 'ANY = \\\n']]),
> + ('line with spaces after',
> + 'any.mk',
> + 'ANY = \\\n'
> + ' \n',
> + [['any.mk:1: remove trailing backslash',
> + 'ANY = \\\n']]),
> + ('line with tabs after',
> + 'any.mk',
> + 'ANY = \\\n'
> + '\t\n',
> + [['any.mk:1: remove trailing backslash',
> + 'ANY = \\\n']]),
> + ('ignore if commented',
> + 'any.mk',
> + '# ANY = \\\n'
> + '\n',
> + []),
> + ('real example',
> + 'any.mk',
> + 'ANY_CONF_ENV= \t\\\n'
> + '\tap_cv_void_ptr_lt_long=no \\\n'
> + '\n',
> + [['any.mk:2: remove trailing backslash',
> + '\tap_cv_void_ptr_lt_long=no \\\n']]),
> + ('ignore whitespace 1',
> + 'any.mk',
> + 'ANY = \t\t\\\n',
> + []),
> + ('ignore whitespace 2',
> + 'any.mk',
> + 'ANY = \t \t\\\n',
> + []),
> + ('ignore whitespace 3',
> + 'any.mk',
> + 'ANY = \t \\\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', TrailingBackslash)
> +def test_TrailingBackslash(testname, filename, string, expected):
> + warnings = util.check_file(m.TrailingBackslash, filename, string)
> + assert warnings == expected
> +
> +
> +TypoInPackageVariable = [
> + ('good',
> + 'any.mk',
> + 'ANY_VAR = \n',
> + []),
> + ('good with path 1',
> + './any.mk',
> + 'ANY_VAR += \n',
> + []),
> + ('good with path 2',
> + 'any/any.mk',
> + 'ANY_VAR = \n',
> + []),
> + ('bad =',
> + 'any.mk',
> + 'OTHER_VAR = \n',
> + [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
> + 'OTHER_VAR = \n']]),
> + ('bad +=',
> + 'any.mk',
> + 'OTHER_VAR += \n',
> + [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
> + 'OTHER_VAR += \n']]),
> + ('ignore missing space',
> + 'any.mk',
> + 'OTHER_VAR= \n',
> + [['any.mk:1: possible typo: OTHER_VAR -> *ANY*',
> + 'OTHER_VAR= \n']]),
> + ('use path in the warning',
> + './any.mk',
> + 'OTHER_VAR = \n',
> + [['./any.mk:1: possible typo: OTHER_VAR -> *ANY*',
> + 'OTHER_VAR = \n']]),
> + ('another name',
> + 'other.mk',
> + 'ANY_VAR = \n',
> + [['other.mk:1: possible typo: ANY_VAR -> *OTHER*',
> + 'ANY_VAR = \n']]),
> + ('libc exception',
> + './any.mk',
> + 'BR_LIBC = \n',
> + []),
> + ('rootfs exception',
> + 'any.mk',
> + 'ROOTFS_ANY_VAR += \n',
> + []),
> + ('host (good)',
> + 'any.mk',
> + 'HOST_ANY_VAR += \n',
> + []),
> + ('host (bad)',
> + 'any.mk',
> + 'HOST_OTHER_VAR = \n',
> + [['any.mk:1: possible typo: HOST_OTHER_VAR -> *ANY*',
> + 'HOST_OTHER_VAR = \n']]),
> + ('provides',
> + 'any.mk',
> + 'ANY_PROVIDES = other thing\n'
> + 'OTHER_VAR = \n',
> + []),
> + ('ignore space',
> + 'any.mk',
> + 'ANY_PROVIDES = thing other \n'
> + 'OTHER_VAR = \n',
> + []),
> + ('wrong provides',
> + 'any.mk',
> + 'ANY_PROVIDES = other\n'
> + 'OTHERS_VAR = \n',
> + [['any.mk:2: possible typo: OTHERS_VAR -> *ANY*',
> + 'OTHERS_VAR = \n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', TypoInPackageVariable)
> +def test_TypoInPackageVariable(testname, filename, string, expected):
> + warnings = util.check_file(m.TypoInPackageVariable, filename, string)
> + assert warnings == expected
> +
> +
> +UselessFlag = [
> + ('autoreconf no',
> + 'any.mk',
> + 'ANY_AUTORECONF=NO\n',
> + [['any.mk:1: useless default value (url#_infrastructure_for_autotools_based_packages)',
> + 'ANY_AUTORECONF=NO\n']]),
> + ('host autoreconf no',
> + 'any.mk',
> + 'HOST_ANY_AUTORECONF\n',
> + []),
> + ('autoreconf yes',
> + 'any.mk',
> + 'ANY_AUTORECONF=YES\n',
> + []),
> + ('libtool_patch yes',
> + 'any.mk',
> + 'ANY_LIBTOOL_PATCH\t= YES\n',
> + [['any.mk:1: useless default value (url#_infrastructure_for_autotools_based_packages)',
> + 'ANY_LIBTOOL_PATCH\t= YES\n']]),
> + ('libtool_patch no',
> + 'any.mk',
> + 'ANY_LIBTOOL_PATCH= \t NO\n',
> + []),
> + ('generic',
> + 'any.mk',
> + 'ANY_INSTALL_IMAGES = NO\n'
> + 'ANY_INSTALL_REDISTRIBUTE = YES\n'
> + 'ANY_INSTALL_STAGING = NO\n'
> + 'ANY_INSTALL_TARGET = YES\n',
> + [['any.mk:1: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
> + 'ANY_INSTALL_IMAGES = NO\n'],
> + ['any.mk:2: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
> + 'ANY_INSTALL_REDISTRIBUTE = YES\n'],
> + ['any.mk:3: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
> + 'ANY_INSTALL_STAGING = NO\n'],
> + ['any.mk:4: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
> + 'ANY_INSTALL_TARGET = YES\n']]),
> + ('conditional',
> + 'any.mk',
> + 'ifneq (condition)\n'
> + 'ANY_INSTALL_IMAGES = NO\n'
> + 'endif\n'
> + 'ANY_INSTALL_REDISTRIBUTE = YES\n',
> + [['any.mk:4: useless default value (url#_infrastructure_for_packages_with_specific_build_systems)',
> + 'ANY_INSTALL_REDISTRIBUTE = YES\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', UselessFlag)
> +def test_UselessFlag(testname, filename, string, expected):
> + warnings = util.check_file(m.UselessFlag, filename, string)
> + assert warnings == expected
> +
> +
> +VariableWithBraces = [
> + ('good',
> + 'xmlstarlet.mk',
> + 'XMLSTARLET_CONF_OPTS += \\\n'
> + '\t--with-libxml-prefix=$(STAGING_DIR)/usr \\\n',
> + []),
> + ('bad',
> + 'xmlstarlet.mk',
> + 'XMLSTARLET_CONF_OPTS += \\\n'
> + '\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n',
> + [['xmlstarlet.mk:2: use $() to delimit variables, not ${}',
> + '\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n']]),
> + ('expanded by the shell',
> + 'sg3_utils.mk',
> + '\tfor prog in xcopy zone; do \\\n'
> + '\t\t$(RM) $(TARGET_DIR)/usr/bin/sg_$${prog} ; \\\n'
> + '\tdone\n',
> + []),
> + ('comments',
> + 'any.mk',
> + '#\t--with-libxml-prefix=${STAGING_DIR}/usr \\\n',
> + []),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', VariableWithBraces)
> +def test_VariableWithBraces(testname, filename, string, expected):
> + warnings = util.check_file(m.VariableWithBraces, filename, string)
> + assert warnings == expected
> diff --git a/utils/checkpackagelib/test_lib_patch.py b/utils/checkpackagelib/test_lib_patch.py
> new file mode 100644
> index 0000000000..3b6fadf38c
> --- /dev/null
> +++ b/utils/checkpackagelib/test_lib_patch.py
> @@ -0,0 +1,96 @@
> +import pytest
> +import checkpackagelib.test_util as util
> +import checkpackagelib.lib_patch as m
> +
> +
> +ApplyOrder = [
> + ('standard', # catches https://bugs.busybox.net/show_bug.cgi?id=11271
> + '0001-description.patch',
> + '',
> + []),
> + ('standard with path',
> + 'path/0001-description.patch',
> + '',
> + []),
> + ('acceptable format',
> + '1-description.patch',
> + '',
> + []),
> + ('acceptable format with path',
> + 'path/1-description.patch',
> + '',
> + []),
> + ('old format',
> + 'package-0001-description.patch',
> + '',
> + [['package-0001-description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
> + ('old format with path',
> + 'path/package-0001-description.patch',
> + '',
> + [['path/package-0001-description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
> + ('missing number',
> + 'description.patch',
> + '',
> + [['description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
> + ('missing number with path',
> + 'path/description.patch',
> + '',
> + [['path/description.patch:0: use name <number>-<description>.patch (url#_providing_patches)']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', ApplyOrder)
> +def test_ApplyOrder(testname, filename, string, expected):
> + warnings = util.check_file(m.ApplyOrder, filename, string)
> + assert warnings == expected
> +
> +
> +NumberedSubject = [
> + ('no subject',
> + 'patch',
> + '',
> + []),
> + ('acceptable because it is not a git patch',
> + 'patch',
> + 'Subject: [PATCH 24/105] text\n',
> + []),
> + ('good',
> + 'patch',
> + 'Subject: [PATCH] text\n'
> + 'diff --git a/configure.ac b/configure.ac\n',
> + []),
> + ('bad',
> + 'patch',
> + 'Subject: [PATCH 24/105] text\n'
> + 'diff --git a/configure.ac b/configure.ac\n',
> + [["patch:1: generate your patches with 'git format-patch -N'",
> + 'Subject: [PATCH 24/105] text\n']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', NumberedSubject)
> +def test_NumberedSubject(testname, filename, string, expected):
> + warnings = util.check_file(m.NumberedSubject, filename, string)
> + assert warnings == expected
> +
> +
> +Sob = [
> + ('good',
> + 'patch',
> + 'Signed-off-by: John Doe <johndoe@example.com>\n',
> + []),
> + ('empty',
> + 'patch',
> + '',
> + [['patch:0: missing Signed-off-by in the header (url#_format_and_licensing_of_the_package_patches)']]),
> + ('bad',
> + 'patch',
> + 'Subject: [PATCH 24/105] text\n',
> + [['patch:0: missing Signed-off-by in the header (url#_format_and_licensing_of_the_package_patches)']]),
> + ]
> +
> +
> +@pytest.mark.parametrize('testname,filename,string,expected', Sob)
> +def test_Sob(testname, filename, string, expected):
> + warnings = util.check_file(m.Sob, filename, string)
> + assert warnings == expected
> diff --git a/utils/checkpackagelib/test_util.py b/utils/checkpackagelib/test_util.py
> new file mode 100644
> index 0000000000..23f2995e27
> --- /dev/null
> +++ b/utils/checkpackagelib/test_util.py
> @@ -0,0 +1,8 @@
> +def check_file(check_function, filename, string):
> + obj = check_function(filename, 'url')
> + result = []
> + result.append(obj.before())
> + for i, line in enumerate(string.splitlines(True)):
> + result.append(obj.check_line(i + 1, line))
> + result.append(obj.after())
> + return [r for r in result if r is not None]
>
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest
2021-12-05 10:53 ` [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest Ricardo Martincoski
@ 2022-01-09 10:51 ` Romain Naour
0 siblings, 0 replies; 7+ messages in thread
From: Romain Naour @ 2022-01-09 10:51 UTC (permalink / raw)
To: Ricardo Martincoski, buildroot
Hello Ricardo,
In order to be ready for merging your series, add python3-pytest to the docker
image now.
Acked-by: Romain Naour <romain.naour@smile.fr>
Best regards,
Romain
Le 05/12/2021 à 11:53, Ricardo Martincoski a écrit :
> ... so the unit tests for check-package can run in the GitLab CI.
>
> Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
> ---
> support/docker/Dockerfile | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/support/docker/Dockerfile b/support/docker/Dockerfile
> index 2aee129668..a5d54b6e9d 100644
> --- a/support/docker/Dockerfile
> +++ b/support/docker/Dockerfile
> @@ -40,6 +40,7 @@ RUN apt-get install -y --no-install-recommends \
> python3-flake8 \
> python3-nose2 \
> python3-pexpect \
> + python3-pytest \
> qemu-system-arm \
> qemu-system-x86 \
> rsync \
>
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests
2022-01-08 22:37 ` [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Romain Naour
@ 2022-01-10 22:42 ` ricardo.martincoski
0 siblings, 0 replies; 7+ messages in thread
From: ricardo.martincoski @ 2022-01-10 22:42 UTC (permalink / raw)
To: romain.naour; +Cc: buildroot
[-- Attachment #1: Type: text/plain, Size: 1469 bytes --]
Hello Romain,
On Sat, Jan 08, 2022 at 07:37 PM, Romain Naour wrote:
> Hello Ricardo,
>
> Le 05/12/2021 à 11:53, Ricardo Martincoski a écrit :
>> So anyone willing to contribute to check-package can run all tests in
>> less than 1 second by using:
>> $ python3 -m pytest -v utils/checkpackagelib/
>>
>> Most test cases are in the form:
>> @pytest.mark.parametrize('testname,filename,string,expected', function)
>> - testname: a short description of the scenario tested, added in order
>> to improve readability of the log when some tests fail
>> - filename: the filename the check-package function being tested thinks
>> it is testing
>> - string: the content of the file being sent to the function under test
>> - expect: all expected warnings that a given function from
>> check-package should generate for a given file named filename and
>> with string as its content.
>
> I spend some time to review this patch to find something to say :)
Thank you for your time.
I imagine how boring was to review this patch :)
>
> Actually the test_lib_hash tests are not checking with the new spacing
> convention we want to use in .hash files.
>
> I applied this patch [1] after your series and some tests failed.
Now it landed on master.
>
> I would recommand to use the new spacing convention by default in this testsuite.
Sure. I will send v2.
Regards,
Ricardo
[-- Attachment #2: Type: text/plain, Size: 150 bytes --]
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2022-01-10 22:42 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-05 10:53 [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 2/4] support/docker: add python3-pytest Ricardo Martincoski
2022-01-09 10:51 ` Romain Naour
2021-12-05 10:53 ` [Buildroot] [PATCH-next 3/4] utils/checkpackagelib: run unit tests on GitLab CI Ricardo Martincoski
2021-12-05 10:53 ` [Buildroot] [PATCH-next 4/4] utils/docker-run: new script Ricardo Martincoski
2022-01-08 22:37 ` [Buildroot] [PATCH-next 1/4] utils/checkpackagelib: add unit tests Romain Naour
2022-01-10 22:42 ` ricardo.martincoski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).