diff --git a/addons/l10n_be_edi/tests/test_ubl.py b/addons/l10n_be_edi/tests/test_ubl.py index e62988da8a4..59312df6325 100644 --- a/addons/l10n_be_edi/tests/test_ubl.py +++ b/addons/l10n_be_edi/tests/test_ubl.py @@ -4,7 +4,7 @@ from odoo.tests import tagged from odoo import Command -@tagged('post_install', '-at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class TestL10nBeEdi(AccountEdiTestCommon): @classmethod diff --git a/addons/l10n_ch/tests/test_ch_qr_code.py b/addons/l10n_ch/tests/test_ch_qr_code.py index 8bc77d8f2c8..ec5be5f7ac8 100644 --- a/addons/l10n_ch/tests/test_ch_qr_code.py +++ b/addons/l10n_ch/tests/test_ch_qr_code.py @@ -1,9 +1,11 @@ # -*- coding:utf-8 -*- +from odoo.tests import tagged from odoo.exceptions import UserError from odoo.addons.account.tests.common import AccountTestInvoicingCommon +@tagged('post_install_l10n', 'post_install', '-at_install') class TestSwissQRCode(AccountTestInvoicingCommon): """ Tests the generation of Swiss QR-codes on invoices """ diff --git a/addons/l10n_ch/tests/test_gen_isr_reference.py b/addons/l10n_ch/tests/test_gen_isr_reference.py index 0ee498f4dc0..3862a93392a 100644 --- a/addons/l10n_ch/tests/test_gen_isr_reference.py +++ b/addons/l10n_ch/tests/test_gen_isr_reference.py @@ -2,12 +2,13 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.account.tests.common import AccountTestInvoicingCommon -from odoo.tests import common, Form +from odoo.tests import tagged QR_IBAN = 'CH21 3080 8001 2345 6782 7' ISR_SUBS_NUMBER = "01-162-8" +@tagged('post_install_l10n', 'post_install', '-at_install') class TestGenISRReference(AccountTestInvoicingCommon): """Check condition of generation of and content of the structured ref""" diff --git a/addons/l10n_ch/tests/test_l10n_ch_isr_print.py b/addons/l10n_ch/tests/test_l10n_ch_isr_print.py index 9bdba9b7d0a..7d5d1762194 100644 --- a/addons/l10n_ch/tests/test_l10n_ch_isr_print.py +++ b/addons/l10n_ch/tests/test_l10n_ch_isr_print.py @@ -5,7 +5,7 @@ from odoo.tests import tagged from odoo.exceptions import ValidationError -@tagged('post_install', '-at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class ISRTest(AccountTestInvoicingCommon): @classmethod diff --git a/addons/l10n_ch/tests/test_onchange_l10n_ch_postal.py b/addons/l10n_ch/tests/test_onchange_l10n_ch_postal.py index 73e1bcbf4c3..3206a1abebb 100644 --- a/addons/l10n_ch/tests/test_onchange_l10n_ch_postal.py +++ b/addons/l10n_ch/tests/test_onchange_l10n_ch_postal.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import common +from odoo.tests import tagged from odoo.tests.common import Form, TransactionCase @@ -11,6 +11,7 @@ CH_POST_IBAN = 'CH09 0900 0000 1000 8060 7' CH_POSTAL_ACC = '10-8060-7' +@tagged('post_install_l10n', 'post_install', '-at_install') class TestOnchangePostal(TransactionCase): @classmethod diff --git a/addons/l10n_ch/tests/test_swissqr.py b/addons/l10n_ch/tests/test_swissqr.py index 57208286241..125a7816655 100644 --- a/addons/l10n_ch/tests/test_swissqr.py +++ b/addons/l10n_ch/tests/test_swissqr.py @@ -9,7 +9,7 @@ CH_IBAN = 'CH15 3881 5158 3845 3843 7' QR_IBAN = 'CH21 3080 8001 2345 6782 7' -@tagged('post_install', '-at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class TestSwissQR(AccountTestInvoicingCommon): @classmethod diff --git a/addons/l10n_ch/tests/test_vendor_bill_isr.py b/addons/l10n_ch/tests/test_vendor_bill_isr.py index c56174440c2..b7209756f6e 100644 --- a/addons/l10n_ch/tests/test_vendor_bill_isr.py +++ b/addons/l10n_ch/tests/test_vendor_bill_isr.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import Form, common +from odoo.tests import Form, common, tagged from odoo.exceptions import ValidationError @@ -13,6 +13,7 @@ ISR_REFERENCE_NO_ZEROS = "1 23456 78903" ISR_REFERENCE_BAD = "11 11111 11111 11111 11111 11111" +@tagged('post_install_l10n', 'post_install', '-at_install') class TestVendorBillISR(common.TransactionCase): """Check we can encode Vendor bills with ISR references @@ -116,4 +117,4 @@ class TestVendorBillISR(common.TransactionCase): form.payment_reference = ISR_REFERENCE_BAD invoice = form.save() - self.assertTrue(invoice.l10n_ch_isr_needs_fixing) \ No newline at end of file + self.assertTrue(invoice.l10n_ch_isr_needs_fixing) diff --git a/addons/l10n_fi/tests/test_get_reference.py b/addons/l10n_fi/tests/test_get_reference.py index ea41528abc5..1f45f8341ae 100644 --- a/addons/l10n_fi/tests/test_get_reference.py +++ b/addons/l10n_fi/tests/test_get_reference.py @@ -3,7 +3,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests import tagged -@tagged('post_install', '-at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class InvoiceGetReferenceTest(AccountTestInvoicingCommon): @classmethod diff --git a/addons/l10n_fi/tests/test_references.py b/addons/l10n_fi/tests/test_references.py index 38cf8a7b411..5a101b760b7 100644 --- a/addons/l10n_fi/tests/test_references.py +++ b/addons/l10n_fi/tests/test_references.py @@ -4,7 +4,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.exceptions import UserError -@tagged('standard', 'at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class PaymentReferenceTest(AccountTestInvoicingCommon): """ All references validated with the reference calculator by Nordea Bank diff --git a/addons/l10n_it_edi/tests/test_ir_mail_server.py b/addons/l10n_it_edi/tests/test_ir_mail_server.py index 734c7246f3b..8d3487ccda1 100644 --- a/addons/l10n_it_edi/tests/test_ir_mail_server.py +++ b/addons/l10n_it_edi/tests/test_ir_mail_server.py @@ -8,19 +8,21 @@ from unittest.mock import patch import freezegun from odoo import tools +from odoo.tests import tagged from odoo.addons.account_edi.tests.common import AccountEdiTestCommon from odoo.addons.l10n_it_edi.tools.remove_signature import remove_signature _logger = logging.getLogger(__name__) +@tagged('post_install_l10n', 'post_install', '-at_install') class PecMailServerTests(AccountEdiTestCommon): """ Main test class for the l10n_it_edi vendor bills XML import from a PEC mail account""" fake_test_content = """ - diff --git a/addons/l10n_it_stock_ddt/tests/test_ddt.py b/addons/l10n_it_stock_ddt/tests/test_ddt.py index d9125888d51..db88d772ffa 100644 --- a/addons/l10n_it_stock_ddt/tests/test_ddt.py +++ b/addons/l10n_it_stock_ddt/tests/test_ddt.py @@ -4,7 +4,7 @@ from odoo.addons.sale.tests.common import TestSaleCommon from odoo.tests import tagged, Form -@tagged('post_install', '-at_install') +@tagged('post_install_l10n', 'post_install', '-at_install') class TestDDT(TestSaleCommon): @classmethod diff --git a/addons/l10n_nl_edi/tests/test_nlcius.py b/addons/l10n_nl_edi/tests/test_nlcius.py index 229b06d9b10..caac00d9642 100644 --- a/addons/l10n_nl_edi/tests/test_nlcius.py +++ b/addons/l10n_nl_edi/tests/test_nlcius.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- from odoo.addons.account_edi.tests.common import AccountEdiTestCommon +from odoo.tests import tagged + from freezegun import freeze_time +@tagged('post_install_l10n', 'post_install', '-at_install') class TestUBL(AccountEdiTestCommon): @classmethod diff --git a/odoo/addons/test_lint/tests/__init__.py b/odoo/addons/test_lint/tests/__init__.py index a7e2c1d6aa7..c68f224ea98 100644 --- a/odoo/addons/test_lint/tests/__init__.py +++ b/odoo/addons/test_lint/tests/__init__.py @@ -6,3 +6,4 @@ from . import test_markers from . import test_onchange_domains from . import test_dunderinit from . import test_jstranslate +from . import test_l10n diff --git a/odoo/addons/test_lint/tests/lint_case.py b/odoo/addons/test_lint/tests/lint_case.py index 8e41625c5a8..c9db995e5dc 100644 --- a/odoo/addons/test_lint/tests/lint_case.py +++ b/odoo/addons/test_lint/tests/lint_case.py @@ -1,3 +1,4 @@ +import ast import fnmatch import os j = os.path.join @@ -20,3 +21,16 @@ class LintCase(BaseCase): for glob in globs: fnames = fnmatch.filter(fnames, glob) yield from fnames + + +class NodeVisitor(): + """Simple NodeVisitor.""" + + def visit(self, node): + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + for child in ast.iter_child_nodes(node): + yield from self.visit(child) diff --git a/odoo/addons/test_lint/tests/test_l10n.py b/odoo/addons/test_lint/tests/test_l10n.py new file mode 100644 index 00000000000..43c445ef659 --- /dev/null +++ b/odoo/addons/test_lint/tests/test_l10n.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import ast +import itertools +import os + +from . import lint_case + + +class L10nChecker(lint_case.NodeVisitor): + def matches_tagged(self, node): + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + return node.func.attr == 'tagged' + if isinstance(node.func, ast.Name): + return node.func.id == 'tagged' + return False + + def visit_ClassDef(self, node): + tags = { + arg.value + for deco in node.decorator_list + for arg in deco.args + if self.matches_tagged(deco) + } + if ( + (len({'post_install_l10n', 'external_l10n'} & tags) != 1) + or ('post_install_l10n' in tags and 'post_install' not in tags) + # or ('post_install_l10n' not in tags and 'post_install' in tags) + or ('external_l10n' in tags and 'external' not in tags) + or ('external_l10n' not in tags and 'external' in tags) + ): + return [node] + return [] + + +class L10nLinter(lint_case.LintCase): + def test_l10n_test_tags(self): + checker = L10nChecker() + rs = [] + for path in self.iter_module_files('**/l10n_*/tests/*.py'): + with open(path, 'rb') as f: + t = ast.parse(f.read(), path) + rs.extend(zip(itertools.repeat(os.path.relpath(path)), checker.visit(t))) + + rs.sort(key=lambda t: t[0]) + assert not rs, "missing `post_install_l10n` tag at\n" + '\n'.join( + "- %s:%d" % (path, node.lineno) + for path, node in rs + ) diff --git a/odoo/addons/test_lint/tests/test_onchange_domains.py b/odoo/addons/test_lint/tests/test_onchange_domains.py index 1e6c561a5f0..b67472e7541 100644 --- a/odoo/addons/test_lint/tests/test_onchange_domains.py +++ b/odoo/addons/test_lint/tests/test_onchange_domains.py @@ -4,21 +4,8 @@ import os from . import lint_case -class OnchangeChecker(ast.NodeVisitor): - def visit(self, node): - method = 'visit_' + node.__class__.__name__ - visitor = getattr(self, method, self.generic_visit) - return visitor(node) - - def generic_visit(self, node): - for field, value in ast.iter_fields(node): - if isinstance(value, list): - for item in value: - if isinstance(item, ast.AST): - yield from self.visit(item) - elif isinstance(value, ast.AST): - yield from self.visit(value) +class OnchangeChecker(lint_case.NodeVisitor): def matches_onchange(self, node): if isinstance(node, ast.Call): if isinstance(node.func, ast.Attribute): @@ -37,6 +24,7 @@ class OnchangeChecker(ast.NodeVisitor): or isinstance(n, getattr(ast, 'Constant', type(None))) and n.value == 'domain' ), 1) + class TestOnchangeDomains(lint_case.LintCase): """ Would ideally have been a pylint module but that's slow as molasses (takes minutes to run, and can blow up entirely depending on the pylint