Strengthen account_do tests and publishing checks
Add static coverage for module configuration, XML inventory, tax views, translations, migration metadata, and the Gitea publishing workflow. Make Gitea Actions run install, compileall, unittest, build, and twine check before publishing packages from series branches. Fix packaging documentation and RST rendering issues so package validation passes before upload.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import unittest
|
||||
import datetime
|
||||
from collections import Counter
|
||||
from configparser import ConfigParser
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
@@ -237,6 +238,21 @@ def _iter_xml_records(*filenames):
|
||||
yield filename, record.get('id'), record.get('model'), values
|
||||
|
||||
|
||||
def _po_entries(filename):
|
||||
entries = []
|
||||
context = msgid = msgstr = None
|
||||
for line in (MODULE_DIR / filename).read_text(encoding='utf-8').splitlines():
|
||||
if line.startswith('msgctxt '):
|
||||
context = line.split(' ', 1)[1].strip().strip('"')
|
||||
elif line.startswith('msgid '):
|
||||
msgid = line.split(' ', 1)[1].strip().strip('"')
|
||||
elif line.startswith('msgstr '):
|
||||
msgstr = line.split(' ', 1)[1].strip().strip('"')
|
||||
entries.append((context, msgid, msgstr))
|
||||
context = msgid = msgstr = None
|
||||
return entries
|
||||
|
||||
|
||||
class AccountDoTestCase(ModuleTestCase):
|
||||
"Test account_do module"
|
||||
module = 'account_do'
|
||||
@@ -448,6 +464,229 @@ class AccountDoTestCase(ModuleTestCase):
|
||||
|
||||
class AccountDoUnitTestCase(unittest.TestCase):
|
||||
|
||||
def test_static_project_configuration_is_complete(self):
|
||||
config = ConfigParser()
|
||||
config.read(MODULE_DIR / 'tryton.cfg', encoding='utf-8')
|
||||
|
||||
def lines(section, option):
|
||||
return [
|
||||
line.strip()
|
||||
for line in config.get(section, option).splitlines()
|
||||
if line.strip()
|
||||
]
|
||||
|
||||
self.assertEqual(config.get('tryton', 'version'), '8.0.0')
|
||||
self.assertEqual(
|
||||
set(lines('tryton', 'depends')),
|
||||
{'account', 'company', 'currency'})
|
||||
self.assertEqual(
|
||||
lines('tryton', 'xml'),
|
||||
[
|
||||
'account_chart_do.xml',
|
||||
'tax_do.xml',
|
||||
'tax_view.xml',
|
||||
'tax_code_do.xml',
|
||||
'tax_rule_do.xml',
|
||||
])
|
||||
self.assertEqual(
|
||||
lines('register', 'model'),
|
||||
[
|
||||
'tax.TaxTemplate',
|
||||
'tax.Tax',
|
||||
'tax.TaxCode',
|
||||
'tax.TaxCodeLine',
|
||||
])
|
||||
for filename in lines('tryton', 'xml'):
|
||||
self.assertTrue((MODULE_DIR / filename).is_file())
|
||||
|
||||
pyproject = (MODULE_DIR / 'pyproject.toml').read_text(encoding='utf-8')
|
||||
self.assertIn("name = 'trytond_account_do'", pyproject)
|
||||
self.assertIn(
|
||||
"account_do = 'trytond.modules.account_do'", pyproject)
|
||||
for package_file in [
|
||||
'README.rst',
|
||||
'IMPUESTOS_RD.md',
|
||||
'doc/**/*.rst',
|
||||
'locale/**/*.po',
|
||||
'tests/**/*.rst',
|
||||
]:
|
||||
self.assertIn(package_file, pyproject)
|
||||
self.assertEqual(
|
||||
(MODULE_DIR / '__init__.py').read_text(encoding='utf-8'), '')
|
||||
|
||||
def test_xml_record_inventory_is_explicit(self):
|
||||
expected = {
|
||||
'account_chart_do.xml': {
|
||||
'account.account.type.template': 36,
|
||||
'account.account.template': 281,
|
||||
},
|
||||
'tax_do.xml': {
|
||||
'account.tax.group': 7,
|
||||
'account.tax.template': 55,
|
||||
},
|
||||
'tax_code_do.xml': {
|
||||
'account.tax.code.template': 49,
|
||||
'account.tax.code.line.template': 103,
|
||||
},
|
||||
'tax_rule_do.xml': {
|
||||
'account.tax.rule.template': 28,
|
||||
'account.tax.rule.line.template': 35,
|
||||
},
|
||||
'tax_view.xml': {
|
||||
'ir.ui.view': 4,
|
||||
},
|
||||
}
|
||||
for filename, expected_counts in expected.items():
|
||||
records = list(_iter_xml_records(filename))
|
||||
with self.subTest(filename=filename):
|
||||
self.assertEqual(
|
||||
dict(Counter(model for _, _, model, _ in records)),
|
||||
expected_counts)
|
||||
self.assertFalse([
|
||||
(record_id, model)
|
||||
for _, record_id, model, _ in records
|
||||
if not record_id or not model])
|
||||
duplicate_ids = [
|
||||
record_id
|
||||
for record_id, count in Counter(
|
||||
record_id for _, record_id, _, _ in records).items()
|
||||
if count > 1]
|
||||
self.assertEqual(duplicate_ids, [])
|
||||
|
||||
def test_gitea_workflow_tests_before_publish(self):
|
||||
workflow = (
|
||||
MODULE_DIR / '.gitea' / 'workflows' / 'publish.yml'
|
||||
).read_text(encoding='utf-8')
|
||||
|
||||
self.assertIn('test:', workflow)
|
||||
self.assertIn('publish:', workflow)
|
||||
self.assertIn('needs: test', workflow)
|
||||
self.assertIn("python -m pip install -e '.[test]'", workflow)
|
||||
self.assertIn('python -m compileall .', workflow)
|
||||
self.assertIn(
|
||||
"python -m unittest discover -s tests -p 'test*.py'", workflow)
|
||||
self.assertIn('python -m build', workflow)
|
||||
self.assertLess(
|
||||
workflow.index('test:'),
|
||||
workflow.index('publish:'))
|
||||
self.assertLess(
|
||||
workflow.index("python -m unittest discover -s tests -p 'test*.py'"),
|
||||
workflow.index('Set CI package version'))
|
||||
|
||||
def test_tax_views_expose_all_localization_fields(self):
|
||||
localization_fields = [
|
||||
'tax_kind',
|
||||
'tax_fiscal_type',
|
||||
'tax_application',
|
||||
'dgii_fiscal_status',
|
||||
'dgii_form_hint',
|
||||
'dgii_legal_reference',
|
||||
'dgii_legal_article',
|
||||
]
|
||||
form = ET.parse(MODULE_DIR / 'view/tax_form.xml').getroot()
|
||||
list_ = ET.parse(MODULE_DIR / 'view/tax_list.xml').getroot()
|
||||
form_fields = [
|
||||
element.get('name')
|
||||
for element in form.findall('.//field')
|
||||
if element.get('name') in localization_fields
|
||||
]
|
||||
list_fields = [
|
||||
element.get('name')
|
||||
for element in list_.findall('.//field')
|
||||
if element.get('name') in localization_fields
|
||||
]
|
||||
self.assertEqual(form_fields, localization_fields)
|
||||
self.assertEqual(list_fields, localization_fields[:3])
|
||||
|
||||
view_records = {
|
||||
(values['model'], values['name'], values['inherit'])
|
||||
for _, _, model, values in _iter_xml_records('tax_view.xml')
|
||||
if model == 'ir.ui.view'
|
||||
}
|
||||
self.assertEqual(view_records, {
|
||||
('account.tax.template', 'tax_form',
|
||||
'account.tax_template_view_form'),
|
||||
('account.tax', 'tax_form', 'account.tax_view_form'),
|
||||
('account.tax.template', 'tax_list',
|
||||
'account.tax_template_view_list'),
|
||||
('account.tax', 'tax_list', 'account.tax_view_list'),
|
||||
})
|
||||
|
||||
def test_translation_catalogs_cover_module_terms(self):
|
||||
type_templates = {
|
||||
record_id: values['name']
|
||||
for _, record_id, model, values in _iter_xml_records(
|
||||
'account_chart_do.xml')
|
||||
if model == 'account.account.type.template'
|
||||
}
|
||||
account_templates = {
|
||||
record_id: values['name']
|
||||
for _, record_id, model, values in _iter_xml_records(
|
||||
'account_chart_do.xml')
|
||||
if model == 'account.account.template'
|
||||
}
|
||||
required_field_contexts = {
|
||||
'field:account.tax,tax_kind:',
|
||||
'field:account.tax.template,tax_kind:',
|
||||
'field:account.tax,tax_fiscal_type:',
|
||||
'field:account.tax.template,tax_fiscal_type:',
|
||||
'field:account.tax,tax_application:',
|
||||
'field:account.tax.template,tax_application:',
|
||||
'field:account.tax,dgii_fiscal_status:',
|
||||
'field:account.tax.template,dgii_fiscal_status:',
|
||||
'field:account.tax,dgii_form_hint:',
|
||||
'field:account.tax.template,dgii_form_hint:',
|
||||
'field:account.tax,dgii_legal_article:',
|
||||
'field:account.tax.template,dgii_legal_article:',
|
||||
'field:account.tax,dgii_legal_reference:',
|
||||
'field:account.tax.template,dgii_legal_reference:',
|
||||
}
|
||||
for filename in ['locale/es.po', 'locale/es_419.po']:
|
||||
entries = _po_entries(filename)
|
||||
contexts = {context for context, _msgid, _msgstr in entries}
|
||||
entry_keys = [(context, msgid) for context, msgid, _ in entries]
|
||||
with self.subTest(filename=filename):
|
||||
self.assertEqual(
|
||||
[key for key, count in Counter(entry_keys).items()
|
||||
if count > 1],
|
||||
[])
|
||||
self.assertLessEqual(required_field_contexts, contexts)
|
||||
for record_id in type_templates:
|
||||
self.assertIn(
|
||||
'model:account.account.type.template,name:%s'
|
||||
% record_id,
|
||||
contexts)
|
||||
for record_id in [
|
||||
'do_account_110201',
|
||||
'do_account_210101',
|
||||
'do_account_21021901',
|
||||
'do_account_21021902',
|
||||
]:
|
||||
self.assertIn(
|
||||
'model:account.account.template,name:%s' % record_id,
|
||||
contexts)
|
||||
|
||||
def test_migration_metadata_is_explicit(self):
|
||||
from trytond.modules.account_do.tax import (
|
||||
MODEL_DATA_RENAMES, ROOT_TAX_CODE_CHILDREN)
|
||||
|
||||
self.assertEqual(MODEL_DATA_RENAMES, {
|
||||
'do_tax_group_otros': 'do_tax_group_others',
|
||||
'do_tc_otros': 'do_tc_others',
|
||||
'do_tc_otros_propina': 'do_tc_others_tip',
|
||||
'do_tc_otros_cheques': 'do_tc_others_checks',
|
||||
'do_tc_otros_activos': 'do_tc_others_assets',
|
||||
'do_tc_otros_iti': 'do_tc_others_iti',
|
||||
})
|
||||
self.assertEqual(ROOT_TAX_CODE_CHILDREN, [
|
||||
'ITBIS — Balance Neto (Débito − Crédito)',
|
||||
'ISR - Retenciones',
|
||||
'ISR - Retenciones en la Fuente',
|
||||
'ISC - Impuesto Selectivo al Consumo',
|
||||
'CDT INDOTEL 2% (Ley 153-98)',
|
||||
'Otros Impuestos y Contribuciones',
|
||||
])
|
||||
|
||||
def test_xml_references_are_resolved_inside_module(self):
|
||||
records = list(_iter_xml_records(
|
||||
'account_chart_do.xml',
|
||||
|
||||
Reference in New Issue
Block a user