summaryrefslogtreecommitdiff
path: root/addons/base_module_quality/object_test
diff options
context:
space:
mode:
authormra (Open ERP) <mra@tinyerp.com>2009-07-03 10:50:40 +0530
committermra (Open ERP) <mra@tinyerp.com>2009-07-03 10:50:40 +0530
commit484d021700986e73aa15534cb7303b0457e1a4df (patch)
treeb2f6a99093affd36b2e26cd66f4ffd13a62ad24f /addons/base_module_quality/object_test
parenta3b98e29d585bc1fca4df4613bb8b54306740822 (diff)
[ADD] add base_module_quality module
bzr revid: mra@tinyerp.com-20090703052040-3rokridr4h3z33xj
Diffstat (limited to 'addons/base_module_quality/object_test')
-rw-r--r--addons/base_module_quality/object_test/__init__.py24
-rw-r--r--addons/base_module_quality/object_test/object_test.py209
2 files changed, 233 insertions, 0 deletions
diff --git a/addons/base_module_quality/object_test/__init__.py b/addons/base_module_quality/object_test/__init__.py
new file mode 100644
index 00000000000..cfc1f614751
--- /dev/null
+++ b/addons/base_module_quality/object_test/__init__.py
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_module_quality/object_test/object_test.py b/addons/base_module_quality/object_test/object_test.py
new file mode 100644
index 00000000000..49677c79c1f
--- /dev/null
+++ b/addons/base_module_quality/object_test/object_test.py
@@ -0,0 +1,209 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import os
+import re
+
+from tools.translate import _
+from base_module_quality import base_module_quality
+import pooler
+
+class quality_test(base_module_quality.abstract_quality_check):
+
+ def __init__(self):
+ super(quality_test, self).__init__()
+ self.name = _("Object Test")
+ self.note = _("""
+Test checks for fields, views, security rules, dependancy level
+""")
+ self.bool_installed_only = True
+ return None
+
+ def run_test(self, cr, uid, module_path):
+
+ pool = pooler.get_pool(cr.dbname)
+ module_name = module_path.split('/')[-1]
+ obj_list = self.get_objects(cr, uid, module_name)
+ ids_model = self.get_model_ids(cr, uid, obj_list)
+ result_security = {}
+
+ if obj_list: # if module has no new created classes skipp fields, views, security tests
+ field_obj = pool.get('ir.model.fields')
+ view_obj = pool.get('ir.ui.view')
+ access_obj = pool.get('ir.model.access')
+
+ field_ids = field_obj.search(cr, uid, [('model', 'in', obj_list)])
+ view_ids = view_obj.search(cr, uid, [('model', 'in', obj_list), ('type', 'in', ['tree', 'form'])])
+ access_ids = access_obj.search(cr, uid, [('model_id', 'in', ids_model)])
+
+ field_data = field_obj.browse(cr, uid, field_ids)
+ view_data = view_obj.browse(cr, uid, view_ids)
+ access_data = access_obj.browse(cr, uid, access_ids)
+
+ result_dict = {}
+ result_view = {}
+ good_field = 0
+ total_field = 0
+
+ # field test .....
+ for field in field_data:
+ result_dict[field.model] = []
+ for field in field_data:
+ ttype = field.ttype
+ name = field.name
+ total_field += 1
+ check_str = re.compile('[a-z]+[\w_]*$') #re.compile('[a-z]+[_]?[a-z]+$')
+ if ttype == 'many2one':
+ if name.split('_')[-1] == 'id':
+ good_field += 1
+ else:
+ data = 'many2one field should end with _id'
+ result_dict[field.model].append([field.model, name, data])
+ elif ttype in ['many2many', 'one2many']:
+ if name.split('_')[-1] == 'ids':
+ good_field += 1
+ else:
+ data = '%s field should end with _ids'% (ttype)
+ result_dict[field.model].append([field.model, name, data])
+ elif check_str.match(name):
+ good_field += 1
+ else:
+ data = 'Field name should be in lower case or it should follow python standard'
+ result_dict[field.model].append([field.model, name, data])
+
+ #views tests
+ for res in result_dict.keys():
+ if not result_dict[res]:
+ del result_dict[res]
+ view_dict = {}
+ total_views = len(obj_list) * 2
+ model_views = 0
+ for view in view_data:
+ view_dict[view.model] = []
+ model_views += 1
+ for view in view_data:
+ ttype = view.type
+ view_dict[view.model].append(ttype)
+ for view in view_dict:
+ if len(view_dict[view]) < 2:
+ model_views -= 1
+ result_view[view] = [view, 'You should have atleast form/tree view of an object']
+ if model_views > total_views:
+ model_views = total_views
+
+ #security rules test...
+ list_files = os.listdir(module_path)
+ security_folder = False
+ for file_sec in list_files:
+ if file_sec == 'security':
+ path = os.path.join(module_path, file_sec)
+ if os.path.isdir(path):
+ security_folder = True
+ if not security_folder:
+ result_security[module_name] = [module_name, 'Security folder is not available (All security rules and groups should define in security folder)']
+ access_list = []
+ good_sec = len(obj_list)
+ bad_sec = 0
+ for access in access_data:
+ access_list.append(access.model_id.model)
+ if not access.group_id:
+ result_security[access.model_id.model] = [access.model_id.model, 'Specified object has no related group define on access rules']
+ bad_sec += 1 # to be check
+ not_avail_access = filter(lambda x: not x in access_list, obj_list)
+ for obj in not_avail_access:
+ bad_sec += 1
+ result_security[obj] = [obj, 'Object should have at least one security rule defined on it']
+
+ # Dependacy test of module
+ module_obj = pool.get('ir.module.module')
+ module_ids = module_obj.search(cr, uid, [('name', '=', module_name)])
+ module_data = module_obj.browse(cr, uid, module_ids)
+ depend_list = []
+ depend_check = []
+ remove_list = []
+ for depend in module_data[0].dependencies_id:
+ depend_list.append(depend.name)
+ module_ids = module_obj.search(cr, uid, [('name', 'in', depend_list)])
+ module_data = module_obj.browse(cr, uid, module_ids)
+ for data in module_data:
+ for check in data.dependencies_id:
+ depend_check.append(check.name)
+ for dep in depend_list:
+ if dep in depend_check and not dep in remove_list:
+ remove_list.append(str(dep))
+ if remove_list:
+ result_security[module_name] = [remove_list, 'Unnecessary dependacy should be removed please Provide only highest requirement level']
+ bad_depend = len(remove_list)
+
+ if not obj_list:
+ score_depend = (100 - (bad_depend * 5)) / 100.0 # note : score is calculated based on if you have for e.g. two module extra in dependancy it will score -10 out of 100
+ self.score = score_depend
+ self.result = self.get_result({ module_name: ['No object found', 'No object found', 'No object found', int(score_depend * 100)]})
+ self.result_details += self.get_result_general(result_security, name="General")
+ return None
+
+ score_view = total_views and float(model_views) / float(total_views)
+ score_field = total_field and float(good_field) / float(total_field)
+ score_depend = (100 - (bad_depend * 5)) / 100.0 # note : score is calculated based on if you have for e.g. two module extra in dependancy it will score -10 out of 100
+ score_security = good_sec and float(good_sec - bad_sec) / float(good_sec)
+ self.score = (score_view + score_field + score_security + score_depend) / 4
+ self.result = self.get_result({ module_name: [int(score_field * 100), int(score_view * 100), int(score_security * 100), int(score_depend * 100)]})
+ self.result_details += self.get_result_details(result_dict)
+ self.result_details += self.get_result_general(result_view, name="View")
+ self.result_details += self.get_result_general(result_security, name="General")
+ return None
+
+ def get_result(self, dict_obj):
+ header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-40s \n! %-40s \n! %-10s \n', [_('Result of fields in %'), _('Result of views in %'), _('Result of Security in %'), _('Result of dependancy in %')])
+ if not self.error:
+ return self.format_table(header, data_list=dict_obj)
+ return ""
+
+ def get_result_details(self, dict_obj):
+ res = ""
+ if dict_obj != {}:
+ str_html = '''<html><strong> Fields Result</strong><head></head><body>'''
+ res += str_html
+ header = ('<tr><th width="200">%s</th><th width="200">%s</th><th width="300">%s</th></tr>', [_('Object Name'), _('Field name'), _('Suggestion')])
+ if not self.error:
+ for key in dict_obj.keys():
+ data_list = []
+ final_dict = {}
+ data_list = dict_obj[key]
+ count = 0
+ for i in data_list:
+ count = count + 1
+ final_dict[key + str(count)] = i
+ res += '<table>' + self.format_html_table(header, data_list=final_dict) + '</table><br>'
+ return res + '</body></html>'
+ return ""
+
+ def get_result_general(self, dict_obj, name=''):
+ str_html = '''<html><strong> %s Result</strong><head></head><body><table>'''% (name)
+ header = ('<tr><th>%s</th><th>%s</th></tr>', [_('Object Name'), _('Suggestion')])
+ if not self.error:
+ res = str_html + self.format_html_table(header, data_list=dict_obj) + '</table></body></html>'
+ return res
+ return ""
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+