From eab2e225a223d0919ee4dde65f4dfe7e269fa01c Mon Sep 17 00:00:00 2001 From: "Nimesh (Open ERP)" Date: Fri, 6 Jul 2012 14:46:08 +0530 Subject: [PATCH 001/188] [FIX]: add date validation. bzr revid: nco@tinyerp.com-20120706091608-f5o08ke6z84oilui --- addons/membership/membership.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/membership/membership.py b/addons/membership/membership.py index dc4eadbada9..f7007ac28e7 100644 --- a/addons/membership/membership.py +++ b/addons/membership/membership.py @@ -478,7 +478,14 @@ class Product(osv.osv): 'membership_date_from': fields.date('Date from', help='Date from which membership becomes active.'), 'membership_date_to': fields.date('Date to', help='Date until which membership remains active.'), } - + def _check_end_date(self, cr, uid, ids, context=None): + for membership in self.browse(cr, uid, ids, context=context): + if membership.membership_date_to < membership.membership_date_from: + return False + return True + _constraints = [ + (_check_end_date, 'Error ! Ending Date cannot be set before Beginning Date.', ['membership_date_to']), + ] _defaults = { 'membership': False, } From 1cf9b2a60da502de27aa67e8318f41ad6692e5a9 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 24 Oct 2012 13:01:46 +0200 Subject: [PATCH 002/188] [REM] test_support controller bzr revid: xmo@openerp.com-20121024110146-bzuf19sfptew0dn0 --- addons/web/test_support/__init__.py | 37 ----------------------- addons/web/test_support/controllers.py | 42 -------------------------- 2 files changed, 79 deletions(-) delete mode 100644 addons/web/test_support/__init__.py delete mode 100644 addons/web/test_support/controllers.py diff --git a/addons/web/test_support/__init__.py b/addons/web/test_support/__init__.py deleted file mode 100644 index 59f6cc67ca2..00000000000 --- a/addons/web/test_support/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -import xmlrpclib -from ..common.openerplib.main import Connector - -execute_map = {} - -class TestConnector(Connector): - def db_list_lang(self): - return [('en_US', u'Test Language')] - - def common_authenticate(self, db, login, password, environment): - return 87539319 - - def common_login(self, db, login, password): - return self.common_authenticate(db, login, password, {}) - - def object_execute_kw(self, db, uid, password, model, method, args, kwargs): - if model in execute_map and hasattr(execute_map[model], method): - return getattr(execute_map[model], method)(*args, **kwargs) - - raise xmlrpclib.Fault({ - 'model': model, - 'method': method, - 'args': args, - 'kwargs': kwargs - }, '') - - def send(self, service_name, method, *args): - method_name = '%s_%s' % (service_name, method) - if hasattr(self, method_name): - return getattr(self, method_name)(*args) - - raise xmlrpclib.Fault({ - 'service': service_name, - 'method': method, - 'args': args - }, '') diff --git a/addons/web/test_support/controllers.py b/addons/web/test_support/controllers.py deleted file mode 100644 index f1013fbaaf8..00000000000 --- a/addons/web/test_support/controllers.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -from ..common import http, nonliterals -from ..controllers.main import Session - -UID = 87539319 -DB = 'test_db' -LOGIN = 'test_login' -PASSWORD = 'test_password' -CONTEXT = {'lang': 'en_US', 'tz': 'UTC', 'uid': UID} - -def bind(session): - session.bind(DB, UID, LOGIN, PASSWORD) - session.context = CONTEXT - session.build_connection().set_login_info(DB, LOGIN, PASSWORD, UID) - -class TestController(http.Controller): - _cp_path = '/tests' - - @http.jsonrequest - def add_nonliterals(self, req, domains, contexts): - return { - 'domains': [nonliterals.Domain(req.session, domain) - for domain in domains], - 'contexts': [nonliterals.Context(req.session, context) - for context in contexts] - } - -class TestSession(Session): - _cp_path = '/web/session' - - def session_info(self, req): - if not req.session._uid: - bind(req.session) - - return { - "session_id": req.session_id, - "uid": req.session._uid, - "context": CONTEXT, - "db": req.session._db, - "login": req.session._login, - } From 99a2dd3938c7d7d4b7e9c724ec8acbb5eeedf35f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Oct 2012 17:47:45 +0200 Subject: [PATCH 003/188] [ADD] first 90% of non-sucky testing API, last 90% left also all existing tests shoud now be completely broken and need to be fixed bzr revid: xmo@openerp.com-20121025154745-rw2gktfd6tp68k2m --- .bzrignore | 31 +- addons/web/__openerp__.py | 13 + addons/web/controllers/__init__.py | 1 + addons/web/controllers/main.py | 8 +- addons/web/controllers/testing.py | 155 ++++++ addons/web/doc/images/runner.png | Bin 0 -> 3963 bytes addons/web/doc/images/runner2.png | Bin 0 -> 6807 bytes addons/web/doc/images/tests.png | Bin 0 -> 65388 bytes addons/web/doc/images/tests2.png | Bin 0 -> 37769 bytes addons/web/doc/images/tests3.png | Bin 0 -> 37827 bytes addons/web/doc/index.rst | 2 + addons/web/doc/testing.rst | 479 ++++++++++++++++++ addons/web/http.py | 2 +- addons/web/static/src/js/chrome.js | 4 +- addons/web/static/src/js/testing.js | 179 +++++++ addons/web/static/src/js/views.js | 4 +- addons/web/static/test/test.html | 62 --- addons/web/static/test/testing.js | 97 ---- .../web_graph/static/lib/flotr2/lib/bean.js | 4 +- addons/web_tests_demo/__init__.py | 0 addons/web_tests_demo/__openerp__.py | 8 + addons/web_tests_demo/static/src/js/demo.js | 11 + addons/web_tests_demo/static/src/xml/demo.xml | 7 + addons/web_tests_demo/static/test/demo.js | 87 ++++ 24 files changed, 963 insertions(+), 191 deletions(-) create mode 100644 addons/web/controllers/testing.py create mode 100644 addons/web/doc/images/runner.png create mode 100644 addons/web/doc/images/runner2.png create mode 100644 addons/web/doc/images/tests.png create mode 100644 addons/web/doc/images/tests2.png create mode 100644 addons/web/doc/images/tests3.png create mode 100644 addons/web/doc/testing.rst create mode 100644 addons/web/static/src/js/testing.js delete mode 100644 addons/web/static/test/test.html delete mode 100644 addons/web/static/test/testing.js create mode 100644 addons/web_tests_demo/__init__.py create mode 100644 addons/web_tests_demo/__openerp__.py create mode 100644 addons/web_tests_demo/static/src/js/demo.js create mode 100644 addons/web_tests_demo/static/src/xml/demo.xml create mode 100644 addons/web_tests_demo/static/test/demo.js diff --git a/.bzrignore b/.bzrignore index 8531ad42bbb..1e0564801ab 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,19 +1,14 @@ -.*.swp -.bzrignore -.idea -.project -.pydevproject -.ropeproject -.settings -.DS_Store -openerp/addons/* -openerp/filestore* -.Python -*.pyc -*.pyo -bin/* +.* +*.egg-info +*.orig +*.vim build/ -include/ -lib/ -share/ -doc/_build/* +RE:^bin/ +RE:^dist/ +RE:^include/ + +RE:^share/ +RE:^man/ +RE:^lib/ + +RE:^addons/\w+/doc/_build/ diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index fcfdca60a2a..7bdfa8b55dd 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -40,6 +40,7 @@ This module provides the core of the OpenERP Web Client. "static/lib/cleditor/jquery.cleditor.js", "static/lib/py.js/lib/py.js", "static/src/js/boot.js", + "static/src/js/testing.js", "static/src/js/corelib.js", "static/src/js/coresetup.js", "static/src/js/dates.js", @@ -67,4 +68,16 @@ This module provides the core of the OpenERP Web Client. 'qweb' : [ "static/src/xml/*.xml", ], + 'test': [ + "static/test/class.js", + "static/test/registry.js", + "static/test/form.js", + "static/test/list-utils.js", + "static/test/formats.js", + "static/test/rpc.js", + "static/test/evals.js", + "static/test/search.js", + "static/test/Widget.js", + "static/test/list-editable.js" + ], } diff --git a/addons/web/controllers/__init__.py b/addons/web/controllers/__init__.py index 12a7e529b67..74c27518ece 100644 --- a/addons/web/controllers/__init__.py +++ b/addons/web/controllers/__init__.py @@ -1 +1,2 @@ from . import main +from . import testing diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 72ffd9567f6..114a896e77a 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -800,8 +800,7 @@ class Database(openerpweb.Controller): @openerpweb.jsonrequest def get_list(self, req): - dbs = db_list(req) - return {"db_list": dbs} + return db_list(req) @openerpweb.jsonrequest def create(self, req, fields): @@ -922,10 +921,7 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def get_lang_list(self, req): try: - return { - 'lang_list': (req.session.proxy("db").list_lang() or []), - 'error': "" - } + return req.session.proxy("db").list_lang() or [] except Exception, e: return {"error": e, "title": "Languages"} diff --git a/addons/web/controllers/testing.py b/addons/web/controllers/testing.py new file mode 100644 index 00000000000..0cfc633a492 --- /dev/null +++ b/addons/web/controllers/testing.py @@ -0,0 +1,155 @@ +# coding=utf-8 +# -*- encoding: utf-8 -*- + +import glob +import itertools +import json +import operator +import os + +from mako.template import Template +from openerp.modules import module + +from .main import module_topological_sort +from ..http import Controller, httprequest + +NOMODULE_TEMPLATE = Template(u""" + + + + + OpenERP Testing + + +
+ +
    + % for name, module in modules: +
  • ${name}
  • + % endfor +
+
+ + +""") +NOTFOUND = Template(u""" +

Unable to find the module [${module}], please check that the module + name is correct and the module is on OpenERP's path.

+<< Back to tests +""") +TESTING = Template(u""" + +<%def name="to_path(module, p)">/${module}/${p} + + + + OpenERP Web Tests + + + + + + + + +
+
+ +% for module, jss, tests, templates in files: + % for js in jss: + + % endfor + % if tests or templates: + + % endif + % if tests: + % for test in tests: + + % endfor + % endif +% endfor + +""") + +class TestRunnerController(Controller): + _cp_path = '/web/tests' + + @httprequest + def index(self, req, mod=None, **kwargs): + ms = module.get_modules() + manifests = dict( + (name, desc) + for name, desc in zip(ms, map(self.load_manifest, ms)) + if desc # remove not-actually-openerp-modules + ) + + if not mod: + return NOMODULE_TEMPLATE.render(modules=( + (manifest['name'], name) + for name, manifest in manifests.iteritems() + if any(testfile.endswith('.js') + for testfile in manifest['test']) + )) + sorted_mods = module_topological_sort(dict( + (name, manifest.get('depends', [])) + for name, manifest in manifests.iteritems() + )) + # to_load and to_test should be zippable lists of the same length. + # A falsy value in to_test indicate nothing to test at that index (just + # load the corresponding part of to_load) + to_test = sorted_mods + if mod != '*': + if mod not in manifests: + return req.not_found(NOTFOUND.render(module=mod)) + idx = sorted_mods.index(mod) + to_test = [None] * len(sorted_mods) + to_test[idx] = mod + + tests_candicates = [ + filter(lambda path: path.endswith('.js'), + manifests[mod]['test'] if mod else []) + for mod in to_test] + # remove trailing test-less modules + tests = reversed(list( + itertools.dropwhile( + operator.not_, + reversed(tests_candicates)))) + + files = [ + (mod, manifests[mod]['js'], tests, manifests[mod]['qweb']) + for mod, tests in itertools.izip(sorted_mods, tests) + ] + + return TESTING.render(files=files, dependencies=json.dumps( + [name for name in sorted_mods + if module.get_module_resource(name, 'static') + if manifests[name]['js']])) + + def load_manifest(self, name): + manifest = module.load_information_from_description_file(name) + if manifest: + path = module.get_module_path(name) + manifest['js'] = list( + self.expand_patterns(path, manifest.get('js', []))) + manifest['test'] = list( + self.expand_patterns(path, manifest.get('test', []))) + manifest['qweb'] = list( + self.expand_patterns(path, manifest.get('qweb', []))) + return manifest + + def expand_patterns(self, root, patterns): + for pattern in patterns: + normalized_pattern = os.path.normpath(os.path.join(root, pattern)) + for path in glob.glob(normalized_pattern): + # replace OS path separators (from join & normpath) by URI ones + yield path[len(root):].replace(os.path.sep, '/') diff --git a/addons/web/doc/images/runner.png b/addons/web/doc/images/runner.png new file mode 100644 index 0000000000000000000000000000000000000000..bd48e9d29221767295afe05d2722ff332c93ab00 GIT binary patch literal 3963 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 C-5}fm literal 0 HcmV?d00001 diff --git a/addons/web/doc/images/tests.png b/addons/web/doc/images/tests.png new file mode 100644 index 0000000000000000000000000000000000000000..84083d9e5ed7583da33261259fb1f4e84d46a650 GIT binary patch literal 65388 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%0DZOjvNOog+{rl3Xfb#C5*7QgCjgOz z%Zbpa_Nz)05D-h?zmd!w-<_{EemZ~u8iZ`^=Huo?+q2~6)|N57b7M@MqnW$mKZEn3 z=$jd8R99|YeNKuwNUY-mg3L`JB`Y%6uNDr@aN8y9p$z1kCfKTY= zji*_9`vyv>VN8=lM3OTXVMCyzx|Qr|7Dnj@0|FS&H|5J*J0h0Zf_pjmq z$02RPFWlKVHO1{WYHpey@9fpwl7&_$bxO=!aNO)Kpwo>7dgR=74#&TK$qC>EoF~Q4 zE<6tMsvJ$vEM=wEL$ygU)^YX|6`?A9_B@-VSyx2jvsZ}0q^UTv`|o4FQx z^*mx$h%j;sFqFb*|1B!Pe*P{;ukbilMXf5&w0-Nnz3gh=t7KH_k zo2_wS^8I%QI}Rk{AM_5+2vf+h4MkaGCG@K&vP3U zLQ{1SJk%_%itP(UWvI(0+Z?nDh$m!E8AffPiUW$6MgEYTI&)QY8IgMkd1&0+Z)f%T zx822JW7O=Z){gKAIv+6<22 zm)+|DFUa#hHYn{D7sFQdRZ}(eBSdL5=Kvt=EDHy7b@C>WvT#;Z^H*b*D2Fro8Xx8= zGlzV|t57ZH4xRn}T3I6qa7z>HnC}&JOCLBUC_GgCte|Mm0_haBIZ`6$Djyj6V7^LI zisq*%Ndzx?>sb(;h8a>0n2c3fzj%^P?{U?r^J5SQ$>+j4G`o8nMQ0d004y8k1SiqQxE*YCkRxz59}So5)@$lQSWS z0uvsptlm>*$#sI&#o^DnT_pDJu~Y3KZy-5jc-Y|3v>8@C6Pc;Uhd~257pZM_)KYB$ zg}%iXJNuJwfVAsg@iP9^jv{@rD80LsJ*)}o=6K1mgTThDSaNy*Q*yPSnZoq&jpu6P zrh*LPq_-^1Thy-AG@!jFX&;WW0{z@3n*5eUCAhLR%6+7i?w}WNm=GF+%#%HF0`rt^mnd6+y zW@|Y#5VBq}&C00)nnMcm!F=2ejgsi&D>}3FaJV)&&jT;9RqBQNjExSrofwa+fanO9 zJ69cdPhR_hHD?Ix1mlheI6Jh#(ze*dFO-+LV2Pze9o!skv>Zccpnyo4^uT>O; z)c3jd+nJU;BCZ;R=R{#032Lg#g9)L=PCUz~zx0FX^7P-#XbZ-I%fBYTeR^ttaulw& zPGG5nmVj(~7Ux>Wxh{ZCWj(dY;BvDu)0>r$QDgHs-Hk`p_3wYDJmE0MVPFrX;-@SD zbWEa6?`K(pGSZfUx%J%)HsO05W-No9lX!5H(45P&us9uo#HvuvV%dh*tmO0)zEjTP zM{ww) zP;7r!5sHY3pPYyx=bS{?Teh1>k4FV#L=%&-tb1zdp7yyASxTBoWl+Lwp4PsD`El_jv) z1gJ8D)4q;>c=Eaw!`?bn&~PxNaGYau(aA}tMm;ca&_Z)EU)XB%N-N?Ju;F>4bAD<@ z(E`$|58u3D9g?cHN$kAG>!o>}OYSJ3`Ujer+G8il{zPeUT2n>)o@>*3K@_jjv=B zQrBt|FAg3_QG5aqoyW`~z(&XU5P{t1TrYh8`)Bi6(q#7DnvajY)EwF-^{2_Y*k2#c z`Jz@E46Ty`w{hm;`(c7lEXksW_S*!h6?>zrtwqT5@^Qlwwb8DJvpQFF1d)RAcFBCO zc9-R5s^jfN37A5tVP^YJ=Ap9X@i?*Pu{%9^1=HKq>L>g9a9umi-vkm4Pa$?9Hv$S0 zLLzulh4GS*nuiD62P-8*t~2XK%y~)LX*NCuM4*L0eF8@|xb67YqaUH2W@508*idPm+VP{IAY%G{ zj5Q#q@w0wI%A+{7nAT{%22Ld~TFPZ=nlKTK=W9u5=$9M_y_%kQ!NtiQx$QFRY}Sp6m~=y7pF=uEht9P%mK?Km9Jaj zK{jsJ-D#7>axN0bQA-*HvFEUzmzH^^tS&B)n#;#VZkpCa-3rplA#7Xkr};~&xhq22 z@@m?$Yu;H#I=J4L6k<-6vkegvknWo)3c*M$W}4wtKCz}pp%coD8>UG6d-!+JNM%zn zYTdVAPr4@GXz4oXWsSIuCxrbPC63pcHE=x0Ld=l`J#855qD;OM3W#`wyUCeO13YYTUwx4DkOFd9eN+@J{jAemOmim1wmw5N*_;skL zzfa(VIE%vL6-hHYWA@N1}ZOYgqDv5miDVe6gqz%#8+qwQjW_q2w~*^Vm$r zZ%5>mfJw$;y?mZr8+(E6f_aRVf|9bwtNp6s)m0D&UPHr_PQ8mOHpwIpI}(JZ7mxc6 zVHQDFStsSx9%XPd)e_G6V?cIFe{dhGd z;=Rp+N~G^6$8TyzO9Dn7D@jhNPuf!i@94p4LP{ zV3E72MRpbX?!>wti2@rOweD;5dFGe#%Qq8pLvPVtSuN~`2vt3Xw-w}OAy$5z?<)x; z%wYwxLNkiH3GvzkyL{I^cn9^Mj1Dd0l-xgeq{d{bA7@|aoq%WcMNoBQswceI#!`>yz7SRs#6HOy433_>-*8CGyTgnSKtDq@YKaC5b8)?CF z?=(NY@^;#a8+cr?=1hxA5#aTvf~?8ed*x5@2vd>-MRLffJtM8{n*^lV#L3Kf+*%pu zsD0BXbQrJmO=h&RGxwDOEbhcqrTL+>8^G$c6%A7$JSb6{RV$&uveh0tQamcs>3#T8 zvqo$}|kfw#lt*Y|8uL`+cw0<>&n61b;AiF*_%Lh&Sy+jcPU;%f@rw z_a0>5olxdp{`&$bc(!_hwRaepc_B%DlwI{GQj%TUWQ|KOV)D~X{N@*h7Iaid0u_fK zG~5b;(ZVCgdO7N*ZEAJw0d>%ZHeL&J6*H{@qzBXe6gU<=HKC-lo8HroU#Xv7{G&1Qsb)nP6FC_K_ z+c(`Ti(Kl;6$Oyj)q+;uS+US+GSF3RDn#7G427Y|0BDpCncubTaY;Q_tmSC$NPKFJ$`Azf!O`h9mPo?Wl;0WwvLS7`&zE3Ux| z+htlbykBSp^^FYMfptZr*4M0Rxwc zsHbB?Xl{Tc z2T(+&_^rDDm>u1K_g?RyPAAiS9P$bnh8b8aB>X9n1?u`st?cXf5AM zE4wUEN3knUwdpAbF1x*-^RiZvC+UNXA+?tNc4;I>LX>Eay39C8`$>awQ1>HID<6y+vA7Z7!h9tNyK-q zR(g!z=k79mZb6iBT5)NskkIpwFo&Esin$Ns=x3~!E-71qW-6mb!z6)a^BZ0GCr3S= zx??yGE{}RNbhNgx-{s#@SF$N7q&yiD;5U*fFX;$ru10Hvm)`e$P9&eF?vqLo+=L7H z`EkfE5Ia*PDrGpd_MYAi)1gfLTtvO-RQ9@oOA&z}TEw&2Nh7zlrQc;nc$#ruVXobU z07yR*dOtVS>?@Kj>H~kCr`6d@NpHyWj2H5WfwDmqa7lnAzsJw784qfhDFihp0sqbz z2O3<-?m*M1V#GRa{@IEY2!d0=N#yQlATDT9L$8rZb%6OJ-)IUHXEL1H=GVHiw|RUh z9%U{~uw08%?4=l4?|c@!I?0XfQ}k^!BccZ^DEelJ$wN0P3{I}}1DH7X+P}A6HN{g= zG!DjdE~@mp9NkeW7;oDzCMe{gvH#99e=uCKxz@FI1mO`rdXbS2^Z!wS!%6-E{=}dp zX*5mmDW@nV0SBi}PVOakwAc3&^Xl5plWEcW*$fHK?h7Hn*sf=5GI{(_*A+a`jHEVB z2e}G4h`=^qS0Va&STo8=S{Yh;RK*HV#nTkVl^n^=f0io5^thijx~Mp6#3~Yd-H=H< zgZ%r8JpIhd^9M>Nqp^tA>)&v%_x@pynz6Z!xvhF;Y`$ME2Wh3YH=fr5-&zv^EO8YN zFq$#qiM2lpVS{lez|LfW}Q%dFJ^q{BD$g9Bjypi%(e$RGmrt25v?QDBq-4v{; zXNq+brc&b{*Jn{htwt-265U}E#{|KY0?l!y=!nf?gM!>SjW`;AtTZd*#SJQ&!^KS5 z3diYpytxOdG`~OeP?mGH8~PdU8LiEnZ`#cqs>&m9B~PoJ*mX3YUV!?aRe5Iq^Xha6S7w||;xF*^s7)K8>O-?BOp z@_HGhf6bR%jiwId#CEb)g~R@6h%;?^?k>+3Xl?Y*$n11M(Rnvjt&TtNT>c#F;^i62 zE0m794{~&uV#AXjoOY6Up+3^6M(VI1!SjiPA4bT{jO9B#|sU9;A9**LV$8Ft_ zcQ-T^3owd7VYu3LJ9a6`E(wO(yj;Y~0n)kx19^pX!m#3T6a8yjVw&(wP|(< z^V}bpDTB|PZ6x+=A&nq{a0_?JmtF48Hx6BqdLWnen*&R&+O_)67WV| zUwGggF`-d?G?u)Uc@daC&_{?6 zWt!t#=8#B_>iPFl8s;U1@GOGTBdf#8Wb=9(kqJ1Yl|m@(AE@**v+i;GRQx11AQFMBGFSLoiD-LcB6{*ho@n=# zD=ygqr@znom^_b)h+v(XZ?VS`QNPphtDof8R zbTbN4E-S$Mo18LQ$tSv8)mHYW#AN_BY}JLB&%W1o0*)O2@ej$u5p1`#EaDb{?u)}h z+nzIxwoM>O_kIZz0eyGh5X{#TO~-ujZl=+T0~Fbsay(*-A#RpEU$uZfS4-}<8<5ge=%TI%fU4%1E|igO#pE_7Mz$C)8`s24_C0@Q9pGiSC-Cw^% zUhyZ+NF7+uW7No=+hq^^z9~g3zP|fN6(F$t`u3Vu;{PiV*=(^Z2O-kGduwNCcF~9{ z{@5Zlm0d#yUz%E*8}51?9Ai1jDQ!Seh^GLuL)1|)ch1^mR}?^T*|K-o)owH>Jw1cq zM&PKWhx2;Y#GBo%ox5S3=Y8JvWI1%`jZtlw-UorAFOa{Of@IAo`_xWSYQJe^8W|q+ zZK|uU!QIfyJKD&cs{fi$dYZ&soMm|tq>VYiFCY=9bGR4SZIg7|<3dyisFX990Roq5 z-kH=xu=ohJVHy{>A$!+xKXR{Xsw_6+^GGzJrWI4ZeB@n^Vu+q zcqa6yr>7woI)xn1s-UIEx~HdlX}|q>jtd~diD7nJB$M8Oqw1RGW}8aykN2d3KP@#Tv8q2llj zR2<-}^XD|8Z`AX|d@OP!^E2)6ci@q!iHjnE?R`D%lFJ`_7)%sh>m z?YmgDJ@b5l+a{xR+hE>P<6OoL=2{ z&fORFIo55ywQedu>jnB1c3q*|U%Fm&AvF|<(5As|_v;-)wpp{XT;;X85+~rHUzX#& z&#l6idMxZ{U?vk<{E6O|(r_4CXBpBwznw@6SEZ##+h`xCYSPbD(v8t>bDh-+^M$zL zuZ!;R;5|0B0MZfhuUyEp2QfQY)%leIoX6lxcL%X@grYZ-8~p_n#05#fdzWN#(Uw38 z{&HmzRUuZ=ZI9^B9H=&LZ0UNfV>g)0a?jtCZ($o7q9X}-Qy$VEV$UVRqd>%KIvV#% zk+yLJ4*n4Cn(X9x2=_giqx865`5xw9k2FcN14_n%K-}N0ow=dIN`BY`<)ZB&c#f5~ zfm@VvDy33r5@193Bx2^7d{Aq=-{29tU@pP{OHNm2559*a%f0-*dr$hCaDo5F540Vv z+$d&~L%$B+G~>W<~(ni2BIF}lX$Ewf&~T^;#cXDbcVu& zuG7Z^9Q#f9BK0~kqa3%43ue5KKkx-ygD%JIS`g@Uc1w+ zue~3F(BQNCWT)uk+OBx7NmIVR*gz4y`C$SX_42qxVtoWK@t8a}eruBQX6gQbXYKv| zhm+GgGs}xEObf3(c*pezDFq9-=XE(X1^thgn!!dHnH6X01rILVi0Ch1x z=36dO&ul|4a>wh6{N*I_{RT8Zus_dJnn4j5sx-r|1NrowF~2Fq{ep7;at}m-Io-1y zcFcTyLv1>6AxuZ#@yMLBd?FV!eU!+!mqQSPT~)ue{4HXR)P)W4L!%#tSo?v+>U9;~ z_hc{S-yit~&HGSs=$J)!?W?<~0;$Wyd?1higCBucfbg%F3Cs#OBNO=sF_yhE?jIpz zrxOf`EdrW+!X~F3sBe1mOJc|v&+z=P(uCsRb{{S-KkTGn21L-H{VSht0aw!YeiZO@ zw(We$Kd7JB!3SlYXuqL+Kw_j1C=$;T@=dfxfhTlfIXg0^;ZL}j{}S$ji~H;6OCm&! ziYp3UQz}Xb`+<26;T6TrCPV@;=K~4FX4J<8J*6PHE6)H*Kyn?6K7fwou}vgPd-9v3 zdi!pL0>KmvT7W>3Ysdvv

^5KA=I|S1zjn*5gCdI#f5h?Hh}KLTC;YCMG48`aU%u zJcbq&Il9pF1hM-hhP}OO8<-CmepmUEA9)L*u6*@j?`tM78~z6YriqrgZ+Qpbp(0!= zzx)qr=5JuqM)^Fb{LU~HWY+iyTB`zJP{0|8MZ6^Lc6vgo5G@n(7c4#^U=l)NHey8J z5+o^I&XH9WIc6)gg(87pF`{2M$s0^KG3Fot=xgsiVzoVi=ugqrtkyb+H?W}TjJ60- z_&~TXr4UR3v?K`SfYnhh zgQ6mX>Nd=u^gEaz_>V}gU@j7*nFVX__Y!UxL$(=-%2u2f({62< zgt@Bx_grs_Auv!d^Xd=;Q-2mt%7OxXjeg?%h{)zZmm!*)&15P7-N)g!2BfCBq_$RJX49=Wq2V6AkOhRz5BRF%!?!8?F33MN1~vGiz@zP4M8V&} z9V7Qhina(bJgs$xvPOOLJ3+T9&Gh_4urw{3R~HoDhUlim&zt{_^~0RB!g^sYC47(pW_wHeWYjw6v8Px@Vg@1#1roVZ~w;mqG3JR?bWtNAvpN|;8RUuT2p5Jz77pk4%@3c5aVQe^Z+#vd(F zQHAu$_E+OC$KbxrFea=wJb1%l=IZeuI)i)Hxl z!C&zY|90{Jzk(P*{-3c7f9IZ<*2EY#*~fV@4pt9^-pj6zth9L!w2XLEea|N>RzBpl zEI5k8cm~Cc)2Lv|BI8FDpB)cMxSPuEYQA<+2878h2n{#Q1hh1&?G0DOU#B&UZ?Bfq zYh_2`rS(hm;q#Cq-(fm`e3wOs>(B=S>FSn%nS3o!W3#ZHr9-N*EvO3TldkvKYYabj zDbY%E_jr=rbrSnnUs@C^5l=K|f9;-0*lVb6FLR1kCQ_47b}Pj2$~}8xCv-Zu(k447 z?tHwaDPtZ06H|@|p#;d%%n>!CPMTaxzLVweYk6g%5O_8?lPOnvAMzyQhe2*ugMw^r zFEPcc zjOL{I>y05UI$Jymi8J?M?X#L$$!?(=yqD@zcdU?`fzUd#LacANFu&aauo&kBnsegdc z1ql7RiOh)p{OH2eFU71+6|n!pd$`4mNi^Y>0?uVRX>Hl|^R6ozRb9RfHlM@lo^H+*`TH>(4tu8T*Y*;txVpMh6Y&{}3aR&EXmthh#o^WlIuAh(O3L^(~yBWp432debLo`uBOzM@#rI@+|KB$!S}p9jIU>$)qh z8;a7g7}@_;kYyOfw`EqBz3s^vhyqnT7!wxehkKl?IK}Cdx&h*Un*j`a#(VV$rYRw0 zupD*KWXL&mP}1T4IsayDJ6F-f$Wy9ETc(PP@|^JFf$UZlccM36&@B;^YB!^ytzO6k zTV14hqO+%zh9uWnd{G5*>`0?vI$Azk4RSGfxW4m50~oXpn})27HX2BXJg?Oh2dE&a9iIxq4-$s3^oFIQqHSkcGwlP+-8hY%5S*Z8acAE60O%v z>V`HGGk8$|#zbd->{bb21@r%g)xT4)xzhX!+`A!WyX9NZ2cyJF@S^mFI_1xmb#E*S>hl?+E?h zUFNZ#gyY$Jn#&Z0xlzUk6y3P;YnDR2_G`D;U}=^{zdtH{aA&kf8Z$xUZ##Fth}65} zNIOPh`V0l-4{Q=j-KPFOZe}^2yUN!e2#AL3sPUd3I7r7n)2oR+I8%(IkmO_gZuW1P zk_Zsh1cit+=9K1Bn=meYD{T@o2eht8*0 z#I7BdD<{oZ(yr;t=a)2roJCae%vQ&2x|6Lt5zFr1dkrJ;j#_Y)q@MavK@o<&>+dc06M!OKbQ~f2fARK~ zQE@F@w{Xr08Y~2FEVw(3OK^Ah5J-T=CAb84cX#Q=-61#x3(~l|yX)I0$@O>l{ly%WqPkS z{P4+reK?t*9W8>p?=i=LZmQYwUS6`awxd5z!3=fP`F_&{xU*Wq6IdeKQ9e&XaKUi_ zl1!6)ADp=$js4CTU!pi`$YPtN?5^t;CPe&+5ziuZB2VgJ;DX7O7FEp8;j!7s(>`cO zw$etZPRnHzJOk3U+B%k>Z*FKJ{;ulzhG3s=$}49$H7$L1aGYn}JCf^ml#=^KYRPVc z=V(=OgB77z=uYvUA>Hbqo%^r$?`6DdU`%1S>pcN%c>Iru59Ze{3# zomR``l5J;~%UaSR)3Igg>QI>jq>3*ekT8fX$Vv*zSp=wTb@Z zu%i0sKc)Ld)SE{m3gJhH*>W_yK_JXAD4ZwVT1=p`yhz2DQ!{Lpctq zM)rh+?%O)<8iV>FFwJh%fArS;kw@gJHr)z2E%52HWmuy$kI}6b;rlN_NIT~h`K2_q zm$r(3Dt7M8K_qn|W1%d+mV?N}o$~Xv&{A$|aD0s*KTmle7Q#S%_F?{@PS3BtMe&uy z7A*Ij7j+w16}!&q`-4tUjVG5H%cza8k34r7vfkwu4i%_lf&|mK(M7vH{MBkBwX5llpbB1r2ew))yx>1Zxj;7fT@b0CT6z3O@D*0p@WugK7|Pq{fiW}N0i19~T)lk3iZ&5dRP zsBc;91gMAVNcG(6O<7A}lCK!Rp(-7>IBzrBvv`(VGQ`QEv27oZnO1h^xE)i^jF>z6 zmwK@4I9EMnA`$r>!XT?FVLes$vU1P8{w2*OPOw$|tC3qC`fQT}2ciJv;JY($nN#;fpN-aN}#43LiQi6 zs&phU6_@4Ip|5qRnR+gKnZKNa+B{vX@`9&u_p^g=akDQrmU}_eEcLJOysu6Vzc%Yu z91bRQ1~BMBYH^E_5M&oF8*SODQMCUi#~kVP@%(&>$R`IjKY4GH0P zH}YHRdzRF})1{P>ZOIySaW#J1$1=%kGe^};UE{dA$+3%4Dt{dq?1qg1B6Z7Q64Hol zdqNzRGQ$~@rb#2fNOFK2*%cPXEXCl#^B2}|eYvcguk~lFXxpL_HPQ@D=GI>(0{9=} z-2EDR8E{)CE_{XgVxVn&vh;_KS0V0Xh9M`cbV=$e`>#mhS5xHVv)C?K3NMZF;+y@w z1XsAv7fTrD!U5Umzu zN9X-iLra>utD3jtdphMn@vT$&7ronz`7}O{s`ZvfPj|4X z55|MCH=9-hPk8x-VRI`Ci@=iqX8+2=|2LHCGhzV(IuVcE+E3rN1Fgg<|B9w@mH#RH z|0gQ^xX zq#YlG;2-;Wi(%mN4^D(`GNY}{7*~0ubWte;piBHvnv9e22|&+amA1!;&c zUp!ZKk$%9$cz-U4JyC(fFRTVnA_|&Ghio;Xcl5y>&Of6o1<^mS&G4|AdFFJbkOsFA z>^EYtTi4Zuimi%u7Q3)Vj`=heyb}#bR^=P_z*b$&u(aYadzW*$(LXY{rj%(wAv}jW zi}CbyPq(w~r8gTh%!RXwAx}c;ai?H5n|W%zNtQK?D8vu7d-&BOUH)Xv7Pme>a`?_O zVO25v&XyK7y8&0;+9ca`eP?8FPe^2b`dH_lAZFxYto$W<7fkWjj#4>=?K=MWQ<2Ed zpoU|qRCBN;YR8jH*l){E80Oh)(JyTpPbNXItEknx0{^l4-2VoHb4*dP&;{w&^NH}& z@wY?|`6C0aOZ%Ra&CBZgT!y<|?78XA0(D&(EAjg;N7vs_pShEbWK5IP+^S$>_Y)93 z+Cvl6h-5C&dB95o4Uu&{qZ4q2IHg#!Xcz3Uf%{9{YCsF49a|%%TOm*d>&*(EL+%K* zIo*i!@S$>wWw8Oz07>s?=^b>d&m4MEK8BGBQ#7tarx*#^vrJ#`ceB|?l+3EEmmb_( zW&$lcoiTgv%tKO%9$qLsSLSglVu`X&$o(c<&8#lQiX-o?)Mq0OaUZUoXw>9@-G{d9 ztrUG54t{b8iVw-yZ{Fkpg3bC_bauXm%e5VN7lRTKvZOXN!g-SVg`@cTW{mAaj+*cA zotUp;tfS0zUv4lz;Ef0ivg=I*YPL?B(VUA+sG1a0chL#*AUgKY-QR_QP)(p`@P&ju z2d51}aZ7hxzf4G~uMzpmesfe7z&(E^XS(I-C5g`Xt%X*s6=}8H7NpT5t=_}mXgBn^ z@M6N#!(D(n7cRYTDuO)3@+Q54lEjnA3EX494Cvb(x*N6OZ{JdVZR2jerGUyQpLVg5 zf;}Xc*L<<4y1Q`w+eZOy!fT&ae#m0SYS$fejaC~r2B;*8?t-<{tch=^AM(4ry*S%X z-69ipbXy3N5QJIM_Tswi-F`IBD-77DJl{XRwqE*vYrF6{&!bf^yr-B9KP6$zcjY^K zZz;7|j+2l-u*6~(Yv^e~kykZTXMD`Ve_a$LxhkkuA0{vrU?#xP!S1G;*-`{5aFJ?g zYwt|B;{ID@qeT;74zJa)FOuqJs}KD9X{M%_zWX-$crra=H?n#2XRng@N=A^Y76gX00v&^9{SNDj^`a!>ox?ysdx-YE}D|c{?mG=lETA`|u)f=j&sSyT^oy zEi28@p078j?kiUM>Dw)Q;f_T)-Vn+Gx1mqPj&4J{IhYs%y~ED~J0VpT{J{(a4aw>1 zA}6u$g1LhyosgL3UcPdSZx7xJl-oURYKaK*o{h|`SU8&vHiv8Spn8)*z29YKxa@+! z2-%|O)dtjq)saUIe&S*2b2KX<1i2YoZd;`1lZq{82>iVdhpvXw?dw|XR0_bE84gP~ zUW38>0H_sRdt}@>(!?mc%SPwLn>Re65X`R_nrK|&xJObKr3L!ch;%XWdZD(dP99ECut zyXj24-8c&S=(4EXIB7lNw+Y%mrdgWH0@AduN&%167{P(!?AGb1 zQFl$^B4+|OzXN@iMA3c%kK`2P;iY!+I4t#abvEW{*?yc9BF%r?J9g%Dk@rA>?zg!k zk0(tJC&L;f|DOf{)vx*l;$0JzzFidav16;P$Jfr;4lXVm6BLL0dW#Tt)23AJnpAZ1 z@m?MN()wxN!1*gQz_K9KKbku})*?Gta;uP_{D#!~nv%*Y>H`!XBQXSY2L|0aARcwf z^Hfe6MxO4dA==D5E!|4I<+W*2bv@l765_^eo*%#AD%UeNcc|*%m9yEjoN^5l~y;;Rh@ryc=fla#k7EBIF4Ro3Cczp^c&%&M-X7 zF+>{>Pm+Yw>&#@F%oXRdK5{mH$!$=>u5nRl^_$IT02;qe^1m-{)+$WSG3d~}jmR*p zS_y6Orvo7n^F3Ep1gr>_454F8z%TDYpNi(=3Xn%JHk?wq0fY6A8Yb^=18(4Xd>dn5 zA~1K>AP7{6-%gw+vwmOB{O%Xo=0j+A5RJNgMpc|q-y{t3k<#$*p+d7lWvjc5Wi+h< zSskgxob_{YA-AlHYWOeCs8fil``-=Bki5S60|3-Fe+pu^OtQSk$U%*{2`7jSaZxI= zJAac%y5v3IJ;LJ=R0j`)#iPKH{U}9G?j#kY39K3jc}16QMZwovzL2#D{tC^Z zp^au5Lh*E?0;B#WtQ}T!7jfd~DA^F(j?{&8O@$Odf_w=m68)19*SE`wzw33KZS3pM zarKRv1#Z`yR))&T*cG;1@eOi`r!;t7ZEztCNXtV2KMcF0r&y-{mTc!h$l8aqx5&*3 z)h)9~+pJ#8kehK8RsIk-dOo!FJYalyws@;D9a(8;xF)x(=E4x~vfxD6`w&~fxOuusulPRMGx7t}@@c}d zp=S!MM*)3W1*Y$95it35!#AQheo7zyvX(KdMt64HxKU@{4%Nd6lo@vmt`EPtl*<%m z%bHw#?e6W9DtbqY?(L0AMsr@CSI&RRDi&D_-Pkl{zEE}OCP{0ykRsscgBNa8yd>KL z@Dhgy4zuhROWS@|+M4tq#_>_*2O_B$ICBVtJ2M=GcCOb3K}rv05W%?<+T&hx5vl z-G?DDEdb%3{lUn-S|n+fsId3W&fK_tNnd8=d}-`TYhjJ(f~d?aJRZY_FkWi;eZmOvOe-9fMnXEsa$5D4!F@DCH8(X3!$YQq?3oe;-kTn3Bp*-m+LJbh^ZBQd z|5Rct>g}Czzj}=XW8gSx4ID zF>d7ms5rH%^6%_$aW1K}PaI8Cj`<0g(t75=P9ix+9$(I|ib9?|fNi(F#c4%YcjjFs zELhhXDYY;?qtUlZ+des-ELvhpK~I80=tH@=y$`F#lCg!puq$?gv@=RM+oKtybSbCd zBLrGTO#sA-;>pJqm=*`P#%LJwosmSbh6`dWhK)K+oT9dK#|Dd z>UqU4j&8LbUgTHG1yL7eL2`<=$(B^6vJMb9b{NSnL3r~t8!ALrh@__7XyVd>(x|rg zl%6FeUj$7^+P%kmy@&A^$X}4Zo>sAt?v`2Ro4j-L3P^>&IK=vlv5srGo%H&^VqyIN z{g(#(6AJ3jbN^gKB?$ldl=E+Nt0xu+0+HR%zYzZ<1J%UJ|B{+FT>r9~f2O!U1^@H) zzmcTgDF0(~6@iW2HKvgsB)aOiG_rx(wOl14_Ec)Gf{eTpC z(h;#;qtjeETGa6Kh`4-7ua3zd%JFQt`z7+#c=sqRZE*6T7Qj!(KQ&%5*P8hAb zSY=N$E0 zqT$D}+1bptGg_;JPKuy-qD)V{pm00>P?J}9*al=tf2?Yq5N;Zx1PawNj~~GCNs5GA zRBqH?G+m01hID&)U zgen(33^L~MJAMGDjWj#ua;r!dqwJdZ7Om8uIYwcDNG(w@8vb;-eih8{{Q9MyK zj(aVY6AgjazmVgad_ zxH76#p*{X9VEPvwKALk39?+mllqc-J-t47Ep z5cfd$6`x?@Xqy2!zm(YEMv`4WxZO)2_q*v8b-u#)@(ixi3(oJndaaq|&&=23N$9)& zIX^pAxqJ12B(%7zN5_rvTS?x(;?;knqJ8VYSeXsbe6cm$D%eNy(YW3y4z>gdta}91 z<*z@qbRjyduNG^x-^~O`kjWWHEZDp6WO~;;-hjh2&eSOY=hIscS3{G(gCMbUg!4m| zkgl`T9Nn!?1$hKIk(3-dd3djklVuyY&&fCTHwZ}PuXxxrE z$Nn_R9EQ@z1bZg9`cbD?<84QAY@#o_(saK4 zEuSbi!!$k~hh9B$s4&NR2;uU}S!`@b$^id%+NXYdIr&5EW0#JsI9jQ>K@wkZ)lwO5 z@|9n#>g_=!el#?9s5i?WMU^qXN>l>))DahZ6;*kYc0_r1gh9hh=}OY1+0hY!yLm(4 zt-?~G=DnArY5%q{vz)jfVMBK$8LQ*gDLq4hip&md=~kG(V*0e8K5UV-Ki@xmlVo#+ zfZX2UdH3A0I(`K}#g?^>11Om^wzh|B2Rbs>5^|;RGN{j835pIs@9tE^)Mtt$qAm_I zs>HN5byug%yhgxlS_v&}dN5J+Y3HGUi@yKah;oo|%XUpy8>o!nMgOUcavZCU4 z<&9m31}H;f=2YS*h{@;4J&rmj{?z|(-*s##M;a+jsb<-Ihf#ePt??g;&cM#U`fra)`$-OKWO+}>s8!Y2KlRijon`a@ z^g86CgippFrD4LZ{1dWH1*uM`sD5SNZWA8^J=Kj&FO}VUt)=sM8rZX$pYEW7(yNx# zYiq?0Z~)Z@9J-9>_ThGf*a#FS!xGf2w|(7 zawG^hd17Okmtp{YY$Wze5YJloy*A)v?S?lwg7a?;3ds9xI0iGIdQz3D{snEpq_X72 zi23b26b3iV6$z^H1Kw%U#i@-%33id$lN*|T_g@e!)#&ln8l49+rI=NI=hbalikFel za}ooK+Y0}hhWUu7HY#}dC1*CE`9jeErIJ%U3N_j{&N=XlwMsxZM?7Q@aU^wqB|x5Y zPW(fQmT0el(*ppt031Z6`VbS5pR6$Bs_n7^g|G#T1)$$)`_`^s66C8NLlAsrlpEa# zQ-9Z*_#Okoh;qkfu||13vPFl|KubAIZy^9idW(-HA=LBruGFFGCatm}evABrl!HMi zDrnA9YLTp(Xh)>?UN0~d0$V*Kaj+CA;j*p}siOJm8J^$Wyzzr4?M%50F~2oMz`>Zl z@Ly!mqq~P^iuKfOeXEI<#KLS%4`&3>5+9601%uXhzr1Y6-{7(`H*a5eGb<$fk#q`F z(^uN{T{nFp!>S$Tfb}kRIn1wghNci)2%4~t{h~qWg#`|GlzFLl;g5+6)~2LYw0l}2 z&vPd-^Yq+gweAJUCzAPyy<5R4}$i$b(d>-8+Gz}B_{O_D;5mBIkxY)@XDd8K` z2&v-A^-oIG!N3)aI0>iTfE#7q0W9O?)I$y6L5FJ{_(j%-ryL^rYR$5soeBgWkEs>0 zb_%{ua+7|>&oCkr^uWR6=pe3!zueAIad2qB)axHQwX$`fECEaUQz_r&)B?;`x0w8+ z-c=ti^6O@-JErTv<1x`gs{2jj3*p=-iolY8{Q*_VXksg6VSCbWox@ws6rL)DPBoKM zLeu8Vl(lMp>Lm zGWFEOmg*Y)(7vv-08vk*&f*8J)>XxqKH)+)7v$ z%$D3|{VIxlUG%J!ER7|$2gVW~-?#M;YM;yRcnW@O_P#g^4B~TuX7lN+p2@U7T(qSZ zvg9d;r*jLG#?EyX)4B@;1|%$Q*H3ZYj7X z#?0;wU+AgeWZ1Mnx6@=dv)?zE@LQJfVEh`YWmbYEaF(lM0a_B9Q5Su5rEGXbo>b1T zVS0syC1Pwj>BDvz4_KsJQDA}$TT9ZEvj@@v@lCon2QF7_4C^-I z@e0?}9{K_0G4(4Ng85;%w|<7~U_*5yrV1^tt6Ku5<{d0rQQ9O_v)=y>~fJGiJ$U^n{tloYnAslUCO+PrjI zX4zMG7L^bYei5eLZQ8}Y7U-=Wcu9usMZq``Ecu5&{mK5rZvH3#4;eb!RYz-D^Fv|& zlT=W&=KQCSRnDI>|9!^)(X-w_&a3H|AHEJpaGq%Gbq{pL^ci~-L>9C%>& z<~dbq-)qe3 zm=IYkWdchMFmhZkJ=K=mx-Oj48!)7rd6NQNZmyQy_grHWv{zg@I!?9%rHu2Rh}kl> z_O=$;^#c}Vh#o6p|KW#lH3*wYGuKVIPI)q#qJ(Y0XN!!yZd!o0&MiUg)|w=4FW>Fa znDkm_anH;e#w#Qh`4tr~m!#xT2_I{o2{+NrE2m!V zj~7?VmOl3&jG50fth`c2Ws5GUh7LV=c0FdlOO>^wt)-guudKNsFR44TCPTm=#6?(S zxhj_iB?W!UH@lX*FQmlntNZfT@kT^ucayP?>+}sh)3S?)qdXyXez*h_#HzB6fob|b z?ZkW&q~T(L_@5(vtF|JoYThTeS>G@{5xb1@rf(POR3lNSWo54J4fQyV$%s<#a*y+t zzB!v!j}+IRx$0)wTQIH-&s@JCE0x6F7oEaZMbqSwUJXa*br*-6yQ7!>SR6QwR})SV z9q+uO38d4~4>?B}BB%M)fXg|-k?-lSwN;*-OVyc*r zwpBTy%4auM+VWf;e*;2IpEQHRDY>1-M{P}7W`>vYI?56GUY<`U{Hax zq^yJ(aL$Uk42SnUVRc5H#ALHTJmv>mSEi=4A$Ef5NtMVVt~_2~;xOCcy>wbn`{alu zo!3U^pS_Eya8L~UTb-=^0zO3<-N2r7HU$!A6XYCqMfJ+f`lrbfKM>j68!P$L?F2b- z>?Kvl&a9uG4L-)%FXy&)50aVMB_=_%@>9Ux%4Afe?<>C|D~o#gmSTpg^OCL?TCAKJKky%E_`ZM>XR21h9`>?8H)BenaLEz z@&@Kn)sB{Ub)~bZp=Cjd^3?ljtFI#q;i9lF25Gno>$DXw+IC3ojTsUb#nG#8sIze9 z6})+w@FCSLNrt2JV0}$F?fLhrR7?bs??;oHv0gJ_c67UulTUOdndti;be7$wIH?2h zj{e&It_q&>mp4n0T(UQuOUsN?9x_(X<@l;=v`l5IO`TdPzF{?YXf>o!~}R7#YIsjp7vKc`c4_ zsbb~P1d;ik^~q@-yf615#_SVEXS881jFM*!gZ}6)2E%nd&1N_4i=SeXxvcA7?~FFf zQb_wDY`7n)KyWa#Ni1SYt&Eo*Z|QlD8US&0NEsGk@Oz(3etY`m){g*{Rh2bV>yc3cZzP zDWMZgmKGdG3bH;_@UTDb<2OdM%qFj){Ev}#IfFI@=Vv!MXlTNkVbs~O^k_Jys|jpl zNxs#--DjX=IrfX|w?y#JofXVFIf@~6EueWsb2eyNFe2U`{Wz&{K%xxY!!G(gbPuV9 z)~y(nyYXD@m^PvZ;@BF;oU&f|?G?cU|cm~K@E zZfTK$9I_<&sU_~A43AoaT+9NiWm!Zyw6~PRlG$jytk$nhLD(El(7UXSRaNMkvdmio zF~(6QDo2X~z@Y~=Wt*WWwFsAf2*{2~3`njGtn$Hjxkvo7?fCOt1ua|33O%85l!E!N z6?MmhwqI5_TJXp3;T(~yd&)Ww_P{Vi-TN*=Wuk-&zgQU|lZYQ0{=-Sn_KBa&>?8t? z24f%y7x?>~b#1jjCbl$^0-1s){5x{kYf45gx3>!x*dE)~p1?_xpyV(;22KeF*l>)! z7-~LYjlv^ca<(`pb%%^}#4PGTOYVW(*8vUU=dvD@ohN8|s2wP%B){?$|#bG=Tub@G=hKamZRcyi)h~QPDh-7c2CmeU0^c%X&)Z>~X&bsrpapl~O<- zBCh93_lC`_ow(XTnWM?eZ!{DzCVDUpYNCR()W1DWk2iU??EAv81|Qs|F|wzGMx-ztBkt8mz;Xnw>umTL1N7 z+F1S9PVrw81FSggQh)oeCE^E#^8ZCdZ!g~VEn$9S9V1$5V%Ts=l z_c*;O4-T&k3uaSqJnf2~4t_wb=4I<1KFaOjIQEy{@CyFYDeTj-)0Q~15O{5-_*iM} zk|~VAR5o-v-QFa`#=*%oe)QUMb{9>G!AnEHC1=E|q2_U|(#u#&DKRM!@2%z=eNi|a z`U-$8wd$K8L$r84xGZiMJ}S}dHCzt)O0ahccTVL^(<06VD*-aIIa{dj!~h4DpzR*d zpk74W3sLmLOt+}j)ZNp2hrcP3($dl#Z~xXOyUCs+1^SrU-N-okET%YRJ#Wmcc9_>z zboA(-q?>{24ikWkzr3_mret?ZX;8Wyz6k!p`(k^+c04Zc%o}U?rS>!7p9Uc!{;Jm* z67cx|Nu46hDHl0<tNoyosSHt$d3PWyiZ`%_f_l@iQE(-5^6t zVPNjP3p71{?jO<<7L)VlW@63Kw8F>pE-o<||F~%0&ij0GvVPy1X7-WKs@luaA>PGu z@EXjNCwNr{8eQP}B@gVjOyAFp6*Z>oq6&zA`E#lZ%x1yHPhsFRv_iLUt$`+TOcaww zG%5W~kccD^@K`8RR963-FoVl~&LzcJxJ2-~4E{V*$(X+7_g-A9K99|-u!q^~bbmGV zXB(yCS00>f{atmc=8gVs`sIQ={jy{=x_8;1K{`wlKRsAwSihz+sz>nttggewq+%>H zSw}VkprB9;|G<}#mQEA7(9Rx7z9Z&e76iP{s%G_dIKEI6OavINob1~aPAj!|gzWt+ zT%qct>!C%QI8OBQGyoRGg5W4rxo^nS7b%9K(^S&)dv6{Kbd6mVhLHNZ)HO+NLV6N1 z*tH_nIVZneIz>!9i!py7Lcu`=$V?u|8F=v=7rF51^Fe+EsZ&(7tbC(LRF0r>|cB_ed&&;k3 zRdj80>$lnF z-M{_6`$|hTia7>0yI=%jCn&1!QdDcnVZCKj0CEwO$Hn4U^issEePGHX4Bpd@cc-aZ zvYPgj>Ch+D;T=2%Wg+b(5cdkmb^n}6F>EB5U1 zaI026MQ@LnJ77AU)IBj^&H^>Xtp{I!4VoO$sEcE}%oE4n zVm4f76(;OeT9$}olkl)HfmvA*-n~v~TxDeM2&{gFhU9%Ny2ZKBh}+WK+8>k$7@^LpA|0xna#$uQurst7(5*5QL}d&! zAL?QVzO1j}Y7KuW5ob5r98eJaFz78Cq(;OL=ieWYkcd-;WJBjW)xZ3uRZRB_CvZ&DWyFmdO^7Rbed$3Z_|%91i>en}px^w{s_dxsJc(R5iR|rVTb(KXvL!!CF#71zkn(yQ2NX zTVc)oHzsHu`74+u!G({dAPdCYk;5l zEk=w?3>sb@V9B=vU|$B96Q)P|k0An~Xy+m{wo1SYMbV`lYBs~Oj( z2u+}FhkFV(dUEHhszzikKN&Dfzb3yHU^KTG_?(Eho;WJMxvT2%bX&Z-@^V#4KgfYJ zqcOuX{{l@+QmS}TDU|3edl68HWY|oHs%1hyJyP5L?!t~*ToL}gnJUVwqk5Lt7Ynlb zDqEKHaX_^Nq%QKu%>!yK8uOt-?Op2ruIEO<#QNy5f&$CJgl0I*?{?@Uv;!&k;w@FA zn?#N6MGZ;YNs{EjAzH=NP+Ihu+uby$YWWp;ZYjb_+PUu1zqCkp-=q+pm@(Z6*zWH=y3*@6*afx^z@+Q3~LHSP!+=<^MU+arFe8 zU$DF7nK_McA8f7BLmOw8MzRnYpX*Kw6nL)xaRo123f&>NvhRmi;Jb603?yvk#4)ag3 zrXi##OdLK`V=AnIrLopas`LE=qUT@~n?`*#f2+cl@-*>k5ukQL%qj(PZGw8E3w+g%$`iTc&)t}6T|kNh&-|KaUdXPAb2)HDZomq zP_g}}?vB!6%E#HjbndW zLI7NqIGH)(R|1NM_EtFZgkcnnUZyrTh+)Bcxo8aN8yntA^2&1MOq1pARnhLhxFRA% zMBO_PS6u{lezQ+9+7pAy9hxG>1K+E#md)4sOT4U9qhSxfAzmX~Szdm3$TVQP)K+2F zy&qIM@&rG6JG*n~TDz}x)xofSa!eyr|6y4|UW39@Pb;!$DDaH?J9O}9q|W@d*z>K# zoJ_U-)r|vF;xNo6!N|AYZ1ff0lktkSvmt$3`EMawz_6V*a7D5iv| z8kn+^7&s`0)`cO%lkAsDE<3ZhRIpwA?S<>1R(E;)=I}x#vevWaBh+W9@io0g**EZK z1_x#3lON?S;gij=4v#WB4zGtYhur5srDggh-UcubNeB`I`ufx^nw|};i|LcGC|MA26=SSFB{Wt#~ zr>)3KsxG==`OK0JJLAnSFqnBBriQrMRU*oOdY;tsg#$7Ke`TgtzafZ z-3i1>tF5oAt6M>~-(K!Cx)(bob?VTU=4^~K8)NA_eoeNuT{J0nP1=2A(VafT@=%W{ zvdPi&Xfn;vFSjYa!SZywRj|-{HtVR${L;t{|3^Loz556}VtRu9k_CmZlV@pYqA@2`;D>nvUK6#jBxR*0!{5RK!4P>{jF_ z31mH_f*8YI7i0S1SDgFU%vb-eHappy%HIjXfC}~wy*bv3=lG)6bNHG_y;YX>PFJUA zDJaK#F_YHOtm}vQXr`?PPsWOuz1G4NZ|8I_waC2{y&Km8{S{ez@WI#DUkETa28>*Y z(<+|-c8_{)5`=4r$eYrcua~#&i0u$(vAB<}sAvVz;@S|ue~~D(?5T(1dn(+yQNqad z_uOTs$R>MFQKvQ4)3}WU;{^Y`8(EPK*s-h9KtD{dhwh{GYzd|x`c zycs5de_N8ef>g0&!J1Nh+D9O~Cpzax{d$^}To_2`qk6ruJH!OcLK7BWu-~5HlI0*% zy8Sr*bIBT}8eU#d?W`b&uHE1YO_5kb0P{giiD4ChR8h9HFOBb;m-EUb=e~pvX{p(| z0`Z6OQreVRN+@fZ#Z`uI!$-X7#vGckhqut@&6EHmVP$FzE5BG1$_G%F)WQthHE_qmGs{m`DXIYyd?3vpqNQyd>@XuED2euxF6 zddNI6qD-2C#1}5v9CMjRd?0O_-*@|4J}&1w>bi{&CKZ4!664E;`HZ_2ypjy_-E&SO zEw2l^A{+xCxp5jCq8T^BvCXLPT^&v`i1^Iqy_Ci6)Q~wtYRr*3V%CtZ6yePR$N!E7 zVdW}iUZSF$q&Tsj&4tgJlpuCoN2NFI^oh3fUnw$!8{6b8n_Ze+A?sm;XcD~zpXqVQ z?1y7I-wv#5ptWld_9vz^K!$#NY`Y|T+VoL=8|i;9(!Mr!B|_7KaX5@xm|AL1WwIj? zN;_!K){V((;PPa2Gj>`WX}P%BMzZ{xFKd(SQP7~&CLZew-Vj(?Qpb@Um&x04P?250 zGM7`%$RI3*N4Epn$VbY{(^6xxuBG7Hq4lG3agmIFHrvP^QF@8u_ptT&Y3giEThbo< z)e9Rfy#BVVUB0Hn&;tWAn3O!0jp)qD1bkjfNW0;Z{M)M|{Y<}4l_Dr&X&I#-FWHMX zZTfwr^1UE&zRl^kd^#&SoY*W^2H5^Fu7sEmCBtKCw_X96^9tqVhg;31HHM<;xrOz{ z3s6xEHxXBD;z-td#5ZZ|@9Rr=u+28SWB|BeQYa7ZvZ-o2=Eogh!Boclcm1kth^0k+ z5lMobqV+({=jNJD9)|oRe=W4#E4%uZ;f@qhfmyp@<2$hUjT(=L;~2x(8|s45ag)$B z%@1?st4xjjiM$Q;KrT3I@`9*JOK{u?#$fNBNytu&!6Bd)5+ya=S9j9L4!8wmX#^$L zsf&T_QL^8@kGGx^VghK;3$k|bouP8Xuas!E1{$3;^hsBuxExItO@|b5m~g~SJ#JH|Wj_+kNM&#>Y@i7aQAUVM z(aY|YR%vqyX9n)YE9d1=2bkCU)>C-Vaik6y_HBf&?A=)gs~oRBZt&9J3{+32=vRIQ zW0I>!ji_OguO>D((P5Pl7xTK5}Npp)%#e z&Ew>y#{JL;`MAGG)JaFL4ceOYFt?(%B?DIZr+@+1cj)6g8visJj}b@m>qm{%9f24?`nb=N(A_z zgmg|q-z&?#r3eGDpUCCIR7vGr$tbNz|{VyfFlDBwTOn4=CcwbCvk6@1SHie|~ z%LNa4JCPDw3n9ya-$=%lr>Ka3Y8U=5w%$4{Zmw(lF2&knrTC!5-3O<*yE`oogS$g1 zEfjZmhr!*U*x*_QcXx_AywmHx?&o{u%OA-xNA~O_JIT&E_uA{X$VCaHjqMICWI{NOkw6?M3J2!Jkc-FYt@rT6xBCmcC81!H4G>|ibG2Wkf3Cb03mX~y26AZpCV zVa#O6f#NrPC060|FFg*DzQzha4pk`MxGyv;#1*;@8{h?)nB@y{5@K-21Ey;Mw%1=x zEJOAAji)}Ataq&%q{31xx~U5x*r!?`-orzmp0As=tn-sjPF$FUJT^X#4@n-Ln61AD z0|X;e3b>qZfNwQ`K9w`*O5^cg1fy$y?SI5Wcd}y~__QaOn|?qprM7NGQ>#!ARxOQK zFI{BJV;)P64Y87qkbGN`1h^U$n4xdNYM&gO4cwvl$bYy;Tin$%{<09r^89HC0)Kt5 zSyIr)IBz|}Q=5#^N1^wOkIgUwtE_-E!?x0?)ixKDG95p9TQ#`Ic@ zm|ZXt84fHaw+-oUyY3?mIj?rP^(=cvP$>K`+86Qx_+m&n^}1}z;gxI$y9p+0;pF4L zQA`)@6v;;;NjBtKVB0vegw4>?hIFlE)&3DXoO)fa^ASI$hQ!mhfUe)u&Ui(MRu^?LQxNMv1N$bE+p zT9>l1xyNQNm@v97mMs9&m3r$`FkSiU^Xk}}fxmOzHV_zrE0FK9PZgom=?^fc%I-!P zlGYTrlUJ@22&*P{Y-hDvE4qCh>+Y=z_mbtRZ2SruiGtjb%jRIt%MOw)hh8Ke<8mF( zeWJP5>WJ)>q}gxQP}z(#9`qviXa+Kiu;h}M-#JCOY-WRRC^YPb?t0(y)@r0bMr0mI zc4{7ug)OJv7WaCxrBw1JxgEb)ane_jWjnv#y*m}^vyjN6k>AgRBtSC_>+O*lsFhnQIpxWq--Pm1Gl{Bd@n$7atPwWnu5vV3 zxQar5u6Yf_0ye>7hvNP_;@ z?0X3ln^tG>g)KO9`8?@tQ+en$(Z7dAUXP7*&oc&Rw(sCNU88XJWbMBxI2kdOlj|^qsL?1#K8+vIv3L4DpWGWC)>JDM ztaoM2DC*PR%Prc6E<&=JA0Z2R82;bNfMLA1Svg#J~G}F_UNgC(0 z2|EHdM%RAMCP3=DV^ouk+H%jgd_hQfq*;H*e}$uopX85@@O+1AUxn@Ux=30@69&TH%hzf=0$_K<3x8#eSu^!yi7#j zkL^QZ)7Z&|2j{rOcYtKYl|xr77_?X}Ob0DuLD6M}Msn8H;%H#kfC1U;GNiG5*tsW# zwS#~Ea=vAWTT+w1WvP72jre47lVCVyAB8cBH-)R`TjFL1cY-9rqHgEPcJr~U1J8M; z?pDLfs~+oaHVdqSssSaS_Y3er!WpI7wTa&#CcrPsanAYv=VUS`(SeOt6tT zg~-dtkRVOl#);^e6~zAN@tJjkpEAMl)&eqEG1}%)*M^)gYO}Wn!@-NnXD^4PvFsOj zorLEbr(!BSnQvcyn)dfqazzvV(9g!&M;+;rR1L(aYnV1nik^P&X8x&oC6yk??y5&` zrUr7j6J_j^!kj<;2GYJ2jTzNYwHNPcN*J!?y%3!GkYbaYZT1e)tr340Q6SW!*88!! zQVE7@Sq;sKsd$em{H{$&VIrenaE>PXZLAye!{-a|w|xGp*A7*DG{v(60wi}Q($IiD zr+}Z~{9`aeloRe#LYnDV(fKkst*uET0dQ#J8ry#{WD+GF?hHq8BVf84>*W4EEKNhu z(o9}Gn1Rs%6m2aYe8UIQA(Uq#d7|~4vpsM-UOk+wGnb8!<`E7T+$Z^X+KTuxY zWOUXxI9N_-S>e@&x$V|dEH3J|5x8n)IL;TL1MSbRsSM)h4?b8XWJxQ4E{RM&BCt@9 z2${5*GdtWbe}#=io?G!%>Q(}l8#Nz%=OR7cS6F}HOgF6#k*1x`d)(uCQsZ9TGms1N zFRLdAHAzyYF*$OLk&X^->Zz6%+@V4j5+^s|S=)!GZfbEW_ntE6Jos?0H-{ETq7pQ> z;)Sy?KR9ugd~^y5n)}UmaBatx+MTG1xgXNV&a!W%!g(oGQWPH|87iS{U>Q2?R9Z2XmtPzMi;8DzLsp!*(Oa zJ1RQR)h#bUrb<^^tY*}%IAR$aD&Ahx=;0OAFF&baDSST;TynzqqmOyQR-8z`2<7yOhIR62jo$Ve!m)CT*1yTmy#B^mVe<%-! zvd7=5p5G~|PBl9Uj=(p-WD0X&HYvVCoS_|=jNf&b) zYIXp&Dq@HyvBV7EpYo-HUutX3F@xP^61qBHS45V)xhjyI&+&s@{uHGnSY&AvMd703M5v699 zpY*hA_>r3{72o}+Yek+JSWt>(a}J10gqsa^%%-3#y^h*soS&^$9dTR9l|#Fyln?xS zhn1S)yQPBpT!^>vL^ydRB6C=*4HS>3r+Q0Y>oNLmpy z;qXK$2_Wv3hZgs{dvI00+wBmCd+8s$6RdYM^-iBHfAG)WNZYm1h@~-9t=OP4JMM8E zuv6)^ey9kOt9G)p*?5JMVo-;^V?1Nb#8`1_glLqKWnu&;iqtDDS|bUdjJk@O9QoO4 zQq)=y6LhJ~9z?Ij16HEyS$DbF&#WHTD)L5E-E1!fMCB(ZBIU+jL$gFPu{mS|nd6VV zt1R(<%_bSJ$6|7sPO5o*D9eBTM%x5xQ9s`I3v4@kjDEZkVlZsZqZWs?r8Cf7vAvnb$z`A%^smi@V~pfE`db zN#t|{^9FVi733Dorc71Xg#v ze-k_8lq)HKIJq&?Mc{Q2_YfE~7yslUm;K1mdW%$RnBlgrL4GaDQUIQ8!s;-hyo7Qb zIh5QLG0PC>vH&F~QYJ)%Sl(gX`apPo%WH^vOh~~Tl}9HJ`Cj^){)StqvVg1@3ILv- zP^+?F#bkYYiFCv%!8(%$8c70YwDFwMIsci>2bqXKlMj?04nN}&<{dt&1`18*!!jbH zl?lD$dxC@6N+oBRWu-W;gY~uiA*y+kB<}_<54Dls2hFqNGSl|2Y76(l*FUaZ4{}NR zjmh?ALA`#d29C$KtNd6~+6;X&AM;TIE#E};I8 zXvFVWz$dLbX#f+ok7p$84U2hfDj{ahwHE;ozq=xAm;|CC4zd?i-hHfFbcGu?LnExP zQ>CG0Do3EfovV*;!U|oj=aI&h>LZlh8cObq^vaaazT;Zf^JNG-r-Hj^U$f4P^PXxV> zvqS}<1n%oJj|M^=j;NyhxrEQb>sgvY{Q?!^>DpF<7(8OjEQ$TDS<@SF2GQcjwU{yv zsv7$m6`-M;bRg6#P|&Y!cYzlp=|Hk2!BCvDB%skeJ=R~!7Y;UyOMb}VASF**#(u%Yub z*=b55vZZ@@tT3|sbSg~|ZDOW~8o1&}{u8S_nM;HQ_{A3=tpF)2G&>WhNDhqLN&We~ z!7GT^NkPapig3ApFAVcIAzEt@rhSK$R-c>kK0n%~qj4k-9hMAaNsi4L2;wfx@ori} zBY*77Gl)BzqK<(?5wl^lsH(+@$rK(s*Jc2VDmMe*gyUlv}{{ z#0-KVN%ctvI);$VjddHUT>Ccrp&sp4%gO=|4$yb(yh*uQecB1xNL-Mrm=FOgp#{etM(QR(WZBFSy4aRQ16Q_FmIkCX}TP>@1x&DL?wTb zr@CY+rEY(%CXa46{|%*#vNu=y7tJO;Edl%1zOr{M?(Xi7x?8sqX-Tw!9dh>fz@qZ; z-wL)(?rCo}#2FfzG>BsWRi998fv+Jj2W9WI?ovjhe*5o$6+JiD>o5ni>+mZ`1i|K6 zElBQYyASrt9i2RBkcXhC$%l&Xu>9m9;M(7HKXa!4tWvAy5$uM)U}%(d9V^tSSERw* ztV>~3J$n+DPK*hVVBxsE{9O??x($;Y;LEw+Hz{;jBmdm2p7y}n3cEMJ`5|;e_wH4R zBLF*U&Lw3uT{pN)_^|xv5!$MI)EhJC=$=;0qa#ITKltb|R_deRoH7d2}js2%JEFm09u}ZV3CeylF z-G@mcMPMwXboNng_Hm-NaZ;$%b#q@t!w0)Z=3{CMScpWsLlXr@`#nBP9&dX~Z#}|w z>Un=a$EhHrK_8YxAIu%W5t08Zk1^h!Hy9mS#tYrZ!A;Y?X}{l0q}KcX5HZU3H-K!f zm1Mn-e~$-od-c*s$wF0uO>j8X34-s;pzoP$r3O zpX<{i*8AanO@3cQnAdU9h!o_F+j~8~vfh`Lm!|jQ_a11#+5MA=_KOI9BL{b|R{F!#17njb)m6@N2Ggne%|tE-C9qAz0^{Z>2~W49?iPCZ*fn)K zAY{Kv@ZxE_sgVa9cXS>vdr5A(__ER*W4D#QP7$;eiLV~$<+f2n%%_wX4(PB%F62a=Ik#6?oVsxs+A8LDI4y4#OtE8m$M>1 zo38X6=gju0+y`yLHy9m#cz%JJeH(U1WaL{npLegJFNGYf)m!LEaP@Gnc1_@^m`XjD zGd|e@u|%BK4_?Ot^v@`5S?2Qx2xKCXta;XX1-l2|y&XEM7_nXtLK|oGJl5(%W&Fc{66Jluf9j4B*dtTK;HMra1P##BqZ#Ur_f{YU~_G_D<}X z{O}%~Av~;;bwo%=3bfhU$qWE4d0b1Cu|D(QoiCpF22`B#^1|=#Zmxa_I2$$TTs^S&O!;68@hi2bcEcWo8U0D>IGX?)wdv`?9#^K1wzL;7cb-R`Xe5#2*C6rN{Mu5eHI01?%^aR9r6+YN>1JNBA1~!Yg=f5t zwd(jAT<$b8mQnl?&LnM<5|Ii_1CC>Z{I*kF!Dr&Sl~LFB`^FcKw#1RwenI%&G~C`y z=*Flhj#ze3ui<4YYR|Dz@xXFQVqJj@p1XSV>Z``DVQNI=Ikq2uU47*4aNsc+^c$Af zqjGPVj#sj6vS96k?i0A!UN5 zHy+BvMD}65reRtQA02GJps%thRMu(nH7XUW1~p8F>DjmPD_L!-2C_9#1cW;5JG*Zb z+}2M|tY*WP61ek3v0p9~!_V8QAzQh!eks=HvM@0^8#(If1sE{H?7MN2vntaZ7PUWCVCd@_x zbaXxxuavo@X?%D7L5*CpG1xLP)>rS$W+)EM6KH6dO8~7VVU)(0iPwgCb83ZkYJG=|iHdRZVCzlan#Rz3;R&FXg@I2W>vk1a*wE zR@kf_J2#}@*={Pvn*_Zk9PAGAf11_fm2+$9fe0KVP8^OJSxA(Q69Ut(CTaGnd8NGw zFCe?PuQwTD3Y10C##pWi9?b;5CMnjfhz7c~s3Hv)=&eu%HuwaBp=F=N<&=U5IkcdbsyvJgo+o6-@7<%;{RNOp`-!n3a@==^Y;3>F zOEd!i-u5RIS&tTrhaVcF*Q8I|Z)tX@VGiJBhz#E*g=){kwa}@3@=HY~^!6;Jb8>|t za0uU&!E7n&+OC6gm&*xzw?|C1ablvks}$akCT6$#-Fn~or=%q;N=D$+nbt#OYQec68veS&9DDp8y#&)hUMoeX(%?I`eoW1KRnUFO#faD_L4iDJg6Qa*Hl0 zwfRd$AfiHE*s4~=7evzDYFwd_t67fJzkV5DdPHF8Jk7{aYk|$W@ur_Aek}x9H z_hg0HcotpyL$dHPCLB)el|n=6^qd@(*MqWMu~7x}(fS)JjU?bzw9WEd0JnzUWp-Wu za90pokifHB3)~p z5l5&ZR18@>RZQk$W=dvsH98fd4CWA5AUnuM+D0NSF)od(%dpU`-g%QpRuZN8{TZK< zj_t4jX<^KgSRJdAHDKH#oMTiSm|t$Yv)>~0{abuPgJcC+y`$qc+VXrq>sZlqwpT`y zPZ$MheYCNp1juLnjeQB|PjP+#c8_1|YKTRgG>C{Oj;t$CEdMW&BnI%9Lk;ZK27P%_ znb^mGnPq?0Wg==^#fjc`_J`})D&ZLFdwf&uNEb{XJ`DoMCLX-gWfA2qw&Z?j>K#ga_n)a?B8%C z+2Yb1cnV1I7$88&NQZG_Kt!QJPSoz2mRscWGmwD$AKLvH{K~u9KY&KAQzps;zVFc)A?g--V+dvFavfmBGQ z6mMe~Lj$^Zh>`mvffoe~ZL*X(*SnC*xns3`RCQS0kcVt;Go@D~KfEr5Fp8m{*oo@( zSMnsMw0_kv0apNak$a$6P*ApO+$<+}#yC%p--~}V={FSt4bwFY)0vd)^)-HA53GU+ zg@Ficp|ryX@80wgZkcqe5q`w6m+WzEx4g&=jj(I0EYIANd6Qr$TcGnvgP>}}a&!j3KU3j)mq7)Fddseb?N=EgRi>`%Ix6fEAWm;fE&@JH zpu9Cum(lO=r_^F2C{MnB5a#jvuVaKq-YS2L|$+y}6SGiyW z0b97ln>RCr%QF@MxVD!-xMj67?a_=AZ<0ix>_H43j*Z^9bV9xGn;T+Qnw}9At)|72 z#}Gw4TPH^5BC=jAi&(4lKc#^zc5Zy=vooAGqs!KhFDr@ftu{(NogXyGY<{2-6R2ij zTPlwDNiG96Y7^euT6>2P-mfKakS9TOX)$$)S`U!xiO`K$9%ZFR)bMmTz87q}n8Q@M zXQEw8r*d1%`JhzVVCQ7r)ZP(v{tLkV*6-QC8f!(j!l1G;N52Mgp!BQ3%k#HxM7pC4 zRp_v&BNVY!MY7W~Sr!OR6`#xopuVHE0U_oSF=KC=!JvV+{wfiv9oFsLNsQo~Khhb4^ zc-$vJjh#zCl*f_w&jNWhr;pg!5NKiMFBmgwgsuFHCo zizr-A<@3vHl}LZhakjPXqTdG&5BlGM%Bg^!@mAxG+p%-dL-Ch>0|E3E zW*?BJ&RoH4f0c9gTAW}2d6`8rrB{d6;1){Ln|P6gOg#-EmV-u_5K}pQL&M^eZf$$^_og!amLbZu(7ss z((FZoX$(F!&7>ZCwXYxxK4G70eGC>_L?_J}25&TT?w9WLK@J+{1(Q*W*!2zF2OiE#%v7*tM?;=_fT{A*VbS z;4>|Wm)5vZ3ajgptaob>Ie*TBHNV98c$1b-b1F(`8}}-mFL4*AfBVBNs6}itAY!KB*u@foo(CBs4pHjg#9-rm0W#sm+8_Y z&6%yAYoKum{i4o+=r?w9zKJ11 zQ1>>==X32?Si4)Dm}6mANz?7%O}EjJRjw`3Vidj*NcMGK)^(9w(Bo+%@5FVk$?Gg&*zrWHQhFTBkHu{VO;Oj?}5<$k@ME0 zznR+gFjFnCZ_?Uw^#grOU@6qnoS`p)+c1f1+8@P-vq#*L#OCjCi~44rX-zH|FD$|| zXqnjs8AnY*8meK!$;gs#3evFYXJPTqU*)#bdAl9|-kNWMHZk+ZL5YS5(^n0OKfB-{ z%VQOdp5sy?zf#jX{N;0GQE1aH7gu;x=KYh9p?HJi!!YmfPYiX=Wlv#xU<fA zKCzIN0Fd5lr&s1AW+`Koq)$Jn367uPQ1v+qb5b{8m=HULbirl)iGv!)l0fuzASS&4i$ zqW$^UqcS(k^$+p!Y$|B=f;CM(1^vrY`zgj-Taw_zNR)QyPMcL!Ii9nD;K>XLOG5uL zM6=SRr2@4KkVHst;s%xw6yFXyOr(+9ycRR4HV~{ZCz_esZ{f}4Fb9Y-?Vb2Pnd$hr z9ovHq1xP}QkDDj3@`-otrA8~J8(y3#320!WgfD`ep(4P!Q472SF<2DnSXI92q(@RtasW{mQT^#tx^|{D1U}Yy)UPCLQmpX2(KtDzce&zzY6bT6Tl1{+B9`PUl z+jRLL^#l?A4o@Wzm-0nTe`!$6LX8)VWGZ=`f^5#W520bY51o#iW{u*TY09U6M4*3E zU$2z#_OREJM^wt9==3#xt>G>f{IL>Rv61A)MnT)&P12lD~ZAGDx7HH@@8aV=QN(?0xzi-Xu znYV$XYBtq4y*_=iPQ{ho)CLxIYm@;*6o9zZ$jNH;LS$eh-Z>|$PEdSZ5-uY*^8Ebd zIWAudk&Rt-jDAWVZf@v4(rB48xn_i@8!~a)=38(8e3QPIMO>PEdeR)niy$nS8&4oO zKug%hd+^mNqgM*ABCrh3%1gq@I8NCUTT}8F0nzcc3glsW?02!JtVsb&1{vNi7G#Yj z4Xj%Meezq)W)7)njaiD|Z$$1Jp5s;Rhl2K8MxDyYzF_ct^`;&-?Bf?3e;l3TjYali z*m+<&X&1ATkE9CSs^H;7aEt5#vxS31Nq=Yu5cXUVpbLF0HB#KaDV7Y$2iz8TY6eQs zp_!r*q7n|`666E)kg+Kn>I3CpGc|Fl2QE))P=si}KS=ehk^b|^uuuc~80Ju9@3HKc z{Y?C*s9(B%HJ!xjgUucksS~d?5RYT8T=P({-<+BlpsnU@UJxk;7Acp-Vwhqt60bea z)|-eY|E-J$F2e|&v8=a^R(U2(RFpwV%)A>OShM-ltrgxL90fvX-i3xgeEchq} zQjDz*<_{)Vs~iG>QJ#ehicTeLY`91UP-4Wda}cGj%Rf=M!=Awua^BL(%d@yT zubs|E7*W3CnM_wZr8ZkPA}o=z6WEEJit+nWM!iR1P9Hdi5mZV8h6*22S3)y67zvjb zCKs(b(wPT&tg4Fum@U22@cH7BS`qaBdo4CI^fHj|5G=ewP|1|DCF|)Q;)Cry|L=UJ9< zM#T;Uck{_tmraUG<^=qW)XkOCz2($XTdW*1<&dXo;?5B+E22T7-|B~PD&W=|=ZEr+ z$08&{7%1Jf1BMxPk%smEubE7WRHzyOrdHuBMhblWE=?DXE*M3^lK>XA^*p>XF9?h= zgG-++c@io#^>qVFX8BZ?ZJ2@Pf{k1nX_&lKAgs1O z^ONw&&STzB$w(Iw8mD21775+*H=OQ&pPR#UcPP{4G3cCH|FP#;vznFhT`2wT^O~pDn%nLs zf{eGiL4E^>$Q=^a-O;tfiPU&N)@4C;oDx8-oay3ahwb@xLA3Nt zSAZ${l_j>pCW3N=7G{oR1-Q67<|Uot%{L+i=&Mlv$#4knN{_0FN|<>mBHsHqxh(pS zz3OOzjkHxX*$S`zRu-l>7A{*Rf7dyY6>wWib3OeKWIt@a5AGp+o&1Kv>9`V(N~;UW zrhU3Y-Ys+5{jp({i~d|C{LGk~K}(VQzGE5-hYX?qj<{>wk39AQ&!ge`rmEaYPu5GX z6z3NnPQ_350J1mVz-Iw;pr;+TNlo2#^aXuYozar2)6?=PWzvtAzhJcswWkW5Paqn*X5US{;gj5sT}De??YcFn67fI9gi;PBeh>>2$a08U@Tq?Vs3TnJxZ zF*M}-p~Z@wq@9h&w}(W5#D(r8nB&UT;$HN=scM~&_`bQ;`!dtS&tTSy!Y6PnJn)YGseOBCzW#>h#sx=ECw% z8}-q>xp#E*fhDLwy%)U$yx4@UZy_<@Zm?W9KF!K=rEh69F)sXVEHK1Sv@5m(PcA{Q z<0aDtSPWH1Xea|Tm_f(Em$^&tiWKa&{afutPzvg!l`kZ@LZzcRr6Hv6JhR2P;gjqS z1(}i;Q=`HzO3DMv<4zyKZSLH~`idU__>lR}1UtKNy<8Q({04{J^?1u)@cV5?;*X0q zO_%10OE8I2PLR5aJ9$63UJQG&3(OolfBx++G&wk}8ZmIsuyX0Ht1a_xa6{#V682_g zgO2)kV;1o1K_mfFyNW*+rGVfMtPf@4<|IR9&mi4>FYPgBA0-BrH*ci2WjulIi^>(obAd10wK`+C6q8aTV5Bb>hHNLq`mos4FNL1k_s=P*^0ehWs!3WoOTD2B zQnKahgUHRuPX!G|CAOk(ixTuIrkECT$+5y}wJP{Oc75rTm(Zm0ygU&X3oiX(e5FN0 zr(_abYvz&D-s73t8_re7&k|Ko&b%Zei9253s*99z>UG3=3V36_&a8(XYByow!pz(0 zT*M>jVSA?^d{~n~wW+=#iJ>D~R2`h-sZrdX8e&r%aP;{3sfbL;;I_5`Pw12O1{_Zz=v+Q&$_-$Uj9hn?>t3<8KmNtBP(+q4YH)R!;qKaqA^m+j=l;WnD>r zO?@dqp9^m?j_CWSN2Dcf*02;u-rW@*t>@w1si-40lGnrq$5v~pjEZH+7pSY2TY;q4PF|G%BVt?&IuLhfqL?^G9qjn zX{3n@1C&N&;DlL%#4PqN^y(q+2DE~IseC*5in0Y?Q6n+bg(KTe@gAuJZvoz@PPdf2 zr+_?2IQ=kBZ(%Uf@7^xnK#$AqY1mzm)uAQU$9`2jFb6QZe4l9VxqhH3O!|I-W~@G{ zd+vC3;Y=u%Y!m&y!@FYpL)pBvmas^7e;arifgXZ>64hU&DGiBjpIo?>18=ZzIC7LXBP> z`GJiJIcbh>+rI$k;}16CpGBZqIGi=l?EsY?{9Zg|zftzj3BGd`AM(j*fbV~^MhkY5q= z0tlrEuVqJ3XadQQld_*gif+@a-6)4 z+iH!k*(%H%>oub$M}cW3#$M}F|Ej=F{v&=dWXlOtox-vhVq>0lKO7gLnWwec|Ekfx zdMD|*@?g!<**V|M8EFA1YGi1>+gozhT(__6nC=S~q=DOM*b1B5r|twy+i# z3&a0yg^X<7-YLX7Pp+Z-aqrvV$4X`Y*va+fE%h8}2Wr@tFgSR=AIR#d7&#!5KW zw`9zkVv+9>7Y7;epo1s>kinhZ5gsSpE}7eBl>$7ix~r*=H6lc2JhYzKoEC%&$bK0E zYeA?nnG?^^WFhE#{GBaD0ZD`Xf?-M!8{vnF&A|Y6Wg?dkP8z?GHai)bgZyW(14m#0(C82FeZN5lv#+k z-s45Z^i$Ee629)M%0fe}2%6?pynDQ#M4YO0wW$LgDL;D%(QITHtV{TPqu2LzP_;CA z5U-McR)?V9%nuHk?9atQL7F-dE#s0OymGe})mlK8mq;>3W-U>dp!B0KGww`53_-n} z>xNm=!b)NG%|jz8(?(h~hUBbIXo;}N3Q~7gyI{~X1~cAjiB{mWf}zva=lJ(4f73QK zL=Tik*A;^y?~-=Z5xEfB)t03zCms zG4epK8lX3DYA03}e?c_oQ1mArr>fXIeUNM1K#F=G4P1(AUV!>{$;qFc)5r zze9?XAdpsDf1uQim(@&!I{Pd6N(r`dc6Iz&STE&T_gA~O3^_j_vqKC$a`~#t&OkLV znHNbYAns2v?+c2+>AR&9pY#d5l9rz(hu>PzGL3R4IZOyp=fm2i^1N3>{Dk1UPA_3m zSgBhkyvCt}qo|w#=lQTSO9OHfxVjOu8&&}b!g+fDny;X?&^Hp!8WK4F?J{xzuacnM z1QARfQJ;Rl)VRa4qMGWw+I0oJMA6NA{#7_0)n(^qvO7k^7LBwST`4)*p^ik`VpXOo zu^L~{#I)lA(BMtc8sG|&l7*2(MWtyzW}LiV^l`rr>@<1ERD2TP4_qdW5WMi_z|~C#*Df6#9rrm zuqWQsZTR`|kWX^+Jlg=^augU_+yuhc_a`bMDhKwI4duJ(@c7$@1O+blpe!eTx!gOu zDfS=fKXhLTxx!FGg1fqP^{n4q`DQD}clp8lLf@pP8LrYTQ-M)2{COJ6fA*`Th6zfj z<}kHMF=H6Fe1MAL8fa0}Z|`=s(qW%*_10(Tp|2$9w^qMc{RT?kdm4o1Br^m_+Fqqc zLIl{?om2!!8wDd63_f&wzHXG^M$lL8uk4F;kxwg20d6-g-eO{6YMp80 zK`+o-kzHi(^b89_6T&0u)vV`h-yf|mx4>DDf1CRwlZ`kRrDY3{DV zjS%^+L3;q8E8vIW`*6tO?~6tud&;6BFT7*!x>Y6j$$A)y@F{e0HFnfa{Lb<@zf%gP z^d4b(StglM3~J^LZCvAhy2bEV6g9<-mJQl06Z2fv^T^?b$3yeCV|pzsA={Z!1p@sT z@kHNW`3r-H5s6dcW#XXEV~`ptl#U6ztnGNQxL^gW z#-ckwiiX(>csd_;8wCakm zj?2#syZRcge#*Jo;y7p(D>zGQ)?|oSP-;V6+i>P7dsOp?2);2nCas`UKqlBM1$1X8RM z2)jwh#SCj`3OC=L3ca3;s(UGt5@e#nu!NG2pgXq{U=2)NrmWGzn zx+Lfq2wg=PjyHX7{->xMmzd9nMhq4-nauJTbMO@MyYi=)O=oz%_;teC?zuO(x_;EQ zV9SHA0MX`TYZH+vIsBKY`g3pRChTbkpP{P3*jRi1Fj+Rmr}-HOrt|7urlN@n zN+g(1Q*RfMv47#_G^`n9EJGH|L)PdK32{)ZyTt}+Wa`GjoSj!lvfG8`L2X-~1LbP5 zaiAoYSsU&;hHSi4adIJmQpnbTSCCINE}>4sX?eLrGft(H66HwC$DM`OI^sRn3SOII z%voWdgD(2NnSXISd|c>dCshcWW>K$ai&v@;IsWm!S^1<7Voae{O40f1f=%c5tjyR=#LjcEw z<4CW13<(3tglUUprYE@YLmX=XV$7a)8Vz4%EK%>(Uzvj}H1$W`WW}_g$)I?0_f7FCB zaHSlCKMNA@3e-glZm;`MEsben=^Wc8%2~>{RFjgpiyP{NWNe@p?9qH24N|r~zXTs) zs{6|mG=#LMiVuTD%owfVX~jf21+gLvg>ak92v;m=GbHO-z8>azDt8q`VZwo05?yacsh5geD;R<(q&!!$ zXw@mH6CzBprFGTSO#(+93SN0Kv=jmUS7%=t6jv8zO9DZITWBl+f=iIbB|va@ckkd5 z+}%C6d*e=UcZbF`Sa5fHop0uwdQ-2a>eWzk(Q#j}Amq;{h-AC(`Z7oLh&xg=3A6|Eo1PDePkt+JBXPkhM&q9j z7+H?vgDIuvYHq6z3#xx-OZjeGkh8)Nk~=U;$o*LF6^;B3)MuDy;(HigHMqH2uicN% zY@UzK1ytptH<>1R5+4_oiF!gXN?nW~O(zB-Cfjr0N~(IyFG}A`i{lt42i2(NX`&8- zzLxi&G(;!(fmYfcR5;R~I5FQ(!Jc&ve!ZUgJbgv&dJr(_1Z{>M-F`I9_2= zDhBpQnaO5>p3V|}+z0xjdr73G5|^ab1I`Z^a0LJ%UN1Gz1+UKK-2%FdI(DtWE_@vVVoDt>Bj z9AYJfzDkqKB8!mXB3QVdDb$0KKU0>Xoi2a1aHU}A8I)pU^K&H{2l<36^BHRqOmdcD zE`PV<+AkcYM7&N`8a{MmfF$RLLquZgVDT%KH+s*F>u2rC?UN)cHNkJrow!d*;8WlS z*m^uG7o5@LGA&aVN<0h70Y zqDKdx({}EaI;-IP*KX_O@x@j5nhNrf{&IkVI>wF`9_H=l&`FI%adojrkk~tRDL3Xt z^2m;pcp2G}`l~4e8x9Ez2dYLIahnAxq~mR&edkt30y%yvP~?>Mm~O3(nRv!-{5K8$ zi%+s4`S}+nh8qqHgl~l8(;5-Ieq@P{o1Ix6FU!j>q!Td}*S~FQ9oGX422jGRDSMOlNhl+1zmbG0;Ma!OP$6QuV7 zJbRC`y&3SfYd;>m9j{L6$Ll=%2#Z+T_Y>UhGBeU5RL_Q)(NweoqPPn=?bWse0OKwO zx#FOsw+f0zoj8~NpVR0UkA$=@zt;-f^H_IG1O+5UzTq19b#dg;zsT!)v-mFHdGykg z{jVw4yZm@e31L`N>wf zT5)EhAv6k>D6icY-#G2EH9&Ax-xoFwwasT?r{y5n$P4fe#~;!RSt#rP&Zq7LnZ`~E zQp-bNSDXjXoQWI;MxTe>%Ybnx~>+ay!I~hxF0+Hrh`QTsI6KO*ScNR6LQHdGx zpJ|3FSPeg4)}%APGT_A1XKjR;6GCrDF@OPyU-gl1n{iEMpTWP}Ah{V7F>w7(wCE?q z+QpSD`}kOrR+QeRH{hoqi)@9MM$B3%s5JzmfRj{WSH7j20B{KON0wWar-#BnS%~18SGkUSE*O(?=t{uNDznfu2W3&*+uP*ShfS}y*%3%Sg3(mNOvPEa1Gi4_LU4B17ZUKL#BTF?br zVx3)83z0c1_j_fPTv_7+7UB%UDk#RC`8=MELxGiEp!o5W}s zOLXbATuROhiWc}CUTOu;Km1KVYGYZ8e z#mJ5cPtUb^iKP$m1CJhNMHfe)r)}3)4W^!=8{2N z957~%t`lyGbe}iV+n_bbF?eK8Ud+78i=$;h$hvuIokzmC1CqyBe5r*A?LCWNLe+z`CKM_Z5QPHy1@~ z{rrOQS&kq=3GZbH7lwE0nvENw)!i(JOXw!OFhn)rEo~ z>6C;#Bcf$u_@|$?KiYs$4n*$TgB7qk0ZFf8MHcvx3n29bK)>~Bl>r)8WR(?p;L+D9 zqQqsEH9G=$y0ui-u)5ifX@QG?)1%?T_k0Y4H%TpbLe#Qnc(hT}$jDAzpq z7CsBm+uHDAWxHtx!O;->z_HOT%KWZ0vLrNK#gxq^cVIB6HDuzlub{E`!S61iY6$7! zE}ffXN<$3tC*^g_BSixq_Do=50S9~^UlF9ZpxmRmoBa_@5>sO2p`kw7^l7ieA{X<7 z)5D2y&kb6P{o)~1aYbGCcd1mhhyy9IHIpIvvt@7VviH^Xd#a?OuRxOC&+?JQ1pv7& zSWR-*3NCPvL(SvD4+ymu)9Oc#N~Kc4_3oh02;UEd$n-Efh2RzkZJ)xRjjnL)f%cZ| zf3g8FA9oK0$=mv8L}WP6yfL9?mpqV2*@z-{jCa0OAB(cb4t9G3m@tGy_)WawjjR!!p;{y}3pO_qw(&XRsF`%ovLo;);Wigw zLIv?jDsKV2wSa=?!80K;wcnwjvW~)!CD#CEBz4=8(jfWo#i9UZ*rz;IifbZ^o>s0@0%T3v|XnF;4MGrY5QwafkJy>2#_!Cd8?D zG7xcFllIK)@)}e~jQrowx;#)i!u`z-o)srw{?ZW#Vx&{N&z!l-dxe8Rwh#TusW?D< zxU>ZoBT8y5Mti1;$h(8NX_tlT-T)S&sZWbHj_;FZvT?-aOb)v@BCgg{`~!*NmGb1q zy9fKwAjK~*=i~gZ`d`iaIX-;oFgGj_edr@QdK`Dft6VwLk{hKw60xiWOhSA#BFE}E z3ElyJ{dgGtc%+?`KV!fl!MQDaECjS1vQo(t@)pr`dKb=M2E4fWoJbK7*gYEC3OU3IGPs|A82y%z;dSxGycE%yb^TIp<$r={n3rFulx@&VpgCKNeVHEoey z1H(PuGY5*u?Me}Nm0mzZ!0O){XbOR+J&cq`!p?a(6&193^jqId*{ zF%sQ%AVPQOyRL0_e>~LY1#R1EIKyfo{>VDgqfgW)PnPobI7*8u&-iv@=`hC?-i`~e zM>QJN%{8Ao`Vef0ND;*((}=S8-ep7}5Jti|ndCK-fm>*Rm}i92qSt{LuQrdyL4 zz*bOHc;~xlDV**!C(=Kfw93}%CxV_EyD4kQ zts6Dg*$=a47Vp2U5vtft^1oTyF<84OH8Rb{-E2LG&3w(g`b5M(YqdXr9&gXz9eKf5|oo({R*=5^^o891HO59Q6OhFWvSvlrxq#yd8QaZL{-Lmh3MueM-uxbqA4+yydJ^di0i#Y?;smvdXoqEA@>e9Q8Cy zTPbk*pH$I=3lay?R7a>+(N%S0%r)isnfHHT$Tp66LlzJ~nZdT7|7O`^dO!M!c=^_m zDyLd&vY1CDy+ThTBi_Mg9iH}f?^mP$Ki-r7$Aj|UaP1R`%71C%om>9I>i;RFC8((f~`!cm*Z>Svu==c+EHi8eo+e)YiJA~Rr`6u(u!LIa@hY|*9>Y?4t(c{yQ ztw1LCoZ~RT+&GHXB{sQ$-m}H;o3?^6;nk`B{`9@-TaI?e*5$!pBEfL9Nmh5jyF1OzN5Zs~j z)FYsWh=5KmAB}X4slp=+ik%*5u3Tkm%wlAW7t}Lawsa zBh`;xG9qGnjy5ch%KrH{Wfs!KT+N!jK>OCHxZnJnhCU8Rwa2xCzfPT=o^y8z0yYN;Rq{GfwVzL1 z;_aS3d>krmms+|%FMY!U39)J)PUfa5tLD|>KFH$#`|vCCvt51~!cEX=w-451KKewN z@nh&3j@pGNAK--Ka+5Dj=KNXIorB>v?k&Wh{wy5IVatWO_XkZS#K zbeD}w4>b+mdoo@E8w5s{*KxNV3;Tx8uVCDw1=aL(iXWw(Je+${4sdPuHK;dH8@jrpnh+6c0s6##gA<%U$G!Cf}vL>!D(r2vbWILYe5zYd$3Frt9tZ?bb_DcYH9 zG}TP+7@Df%3!HmF!hsSttX!WnMy9mxU4nvD3EbQ{9JU1p|1M(}Y$Eb{hzD6|kn;f@ zep_ST8t!!`I4DgaueCWXm_MS`UIt}JRG67@VQ#-_yC zDUpLnh?%5kJ)r|5rVr^eV;Gk0zh@}zM}iK&1Y#4-lt&?P-ZJ3O9rcHi*tGB31UFfu z&^G?YnW5b4^!C6)^pZcN|52P@V!DfY7<%#x5GIYIs~uP0zS!_6sHV~eh=KkU9) z*K9RCF+TkmziG#^>dpTF|MFHgRb3=SElD_Q9UgHgCdbiz zWWf6KIolCTDelR%f&-HCoOBlt^c8@@Qo01s^arnSoDh>8KG z!{LS|20z7xm+Oeu6ng6N2VP;jSannU<&M{4pTV0&-#BSn$dT*mYN%j;aG?4Jq?n$ z!~+&zs~&`$k2tvcmHsi7K^x@06#k;U*`%Alxr}xjj<&~}oLG`1QRNuX*AYyiX$;Sr z4or1*y~7foFw3~@$=1M%7CqqAxe^d!3%6C61|IPCRY{8_@2F)dIPxFubxd7pZNF4XN z>}MZRq(a$IFtgB2z)djFtQp~vmGUi~3aa~sO&-9N4oV4bR8TV$*g}{oSe`U#lRiPi zFLHv0S}na4`dxkUs9ueQ06Tfqv*_F*fq%|i2xluuS|&avjb#iuc(ru%mO$#mB@T1Y zI5aCm9|bHx(en19=U0ucuR1Or5tDO!Az(I)x1OE}8N^ob-c>}0W&sS64}1{eF+GG0 za>CATSW$w?|HHKj!y0_+QwOp&x!t=L=%%VcrvpFjHPc6L0cRB@v}e?2%eDrKHDUS` z9OzRROgCH+WWFX;C(MV&x`Rx;E*S+8$}?}}BNHM)U&j+o(Cjsr%2Z&jhsyx*GaJml z_{Nc;lo`wDE;MR~z0KgMt7{iUheFc!S>-KFJ@Ig=y>#Qse*AHlABRJiXYq&w#G=5X z_+yo=1^Il(;x>Ts>UO~#>&WF)`Ko662wt4)yD&T_i2BwA0lDCs{&%o~&|l1=vZbSJ z8H;vdNXm}9~5(Mj(gwOSmikzu*g*!u$R z5{eRioSeD*a`y~2XfJW|Nb@D+FyPn#I#3n10puY*ZGglv#6@JV-PVyapRN6OzbJ%s zicMCtBMh)XB9y+rd(gT7_hr?umd3I(m3%YMqCRTgz<#HKVj5OZY>LGd4>A_-9;X~+ zqw0hja{j@9;C`)AcwS#c=Rj`J=dZ*7+*if1MV^5y<`Pk>C@QD$J`<$1ciN&U0TM&c zYxeW2_TFDlI=-u-CiUXX=J26VTR9h)X?#$D@zW=%R0DR3NTV+bMO_<8+OoqC68l&m zD1Z+A`1yML2`}UMUBZ#^=q_(*_{tX(Ys`}sBHp1W;Tor6T~Rp~^YL&D4UO4O)nK<6 zFC(aqK_|f4E}1v}Ey?8Zcdnv=+Xmq3?3#;*|B2nha^;=dN#&Kcoj+&+ec>s-L@B%D z)8(@o`i67cm7dEQZj;@$fnv)r34XO&q<|~d=a)`n2LgYs4zV~n!Hb;CubA_T(!63X z4U5Ob3vj8Qc=#G62{0Q1q4`4JQmK%t6de7x1cADJcX6&NBAfqi$gia4f(5nL@9=d# z;-PHQNw##7Jar#JUGkdDfx_1vfLJlJ0<^8t9yBgm3(uA&M)AT8cN=w_dgBK3 zyec6(Pc4sNrZw|+EW}+}ZOTQo=}Y}bos)+y2vZ$F$K`xE*dyUL!Kai&FjHf?Hv}2V zU~XE4FXFv1hwfRS42JQDR$D>#6#N4zC2llP{;%o|xqDVpeAL;EL;CCxdCjG_T)Y{Z zLjF2%6@?Q>a)~yHhkqH>fxr7Hfvil8@3(_MEcajUJbQAPnvy1oS@csS7BrqxTnb+$ zJ`yjuNF2AP1lnq==GhLH#8;$s-hPb(2qOojAgvECNJlIUa!jj0%PR{M#m@zX#W}Th zZTp>ZVz{(265Z>O{dbZ4DY~up(PC>D%4Z-iq$(|^p>_L8y1A0A$|j`jpIU0-eol%| z=TcY*DSovp{$0q3!Y2B4l>1F9r`?^S?R#lNeRx8`XtOHTyZCz+?}2eX2P;n}L5X*DX59|4CZV|92dQ zZ)1AtgVxfFQmT$(2KMk-TtA+-l}jNTZ;qo|V)gdp{Y76qC`oNUReo#tWqxG%7}JFQ z{6sI(gC=$H`Rq06N?SE7WSDvW9%Oxf@GLRWe6j4U$G*V6XT1E8P~ZsTq{Sg?F1?o3 zji&<$S$`fW=Xn-DWw3l%TC!ica~Oygc6Q5h!<+8FgI1xs=FzlXy>B15^ivCX?{FTU zs+2@3TK3y{8+*sw zmh_+Z{$)?=p*6_#Uk%2dmAo`govTip!Ey1e--pmoA7DkB=U2R!c1iG~fzj(bTvmst z`p6yk$mF9D{FfHXqf48=g`?BHgFxdy0s@};JNTcAck+<4_#!n?zWKJfAIrTi_|v7= zz8|mEgCsLPN>$&ouzd(u==%-wprhU8Sled5f)<}Dwet!b$+r6I9I#XOn2|(j67tUi zi}Du!abs4?f2_!RJVwi@_c7xQO6Y(5q-PlSS+tlj&cAO$hExJr%sW)ucbi->iH2Fo zsd*i_!m7e~po6^4SldJ1;SYjY?CuU~is9TI<$A<79_g6C(KvPb5;5_Ljre3Aw9tQT zLsbsX$otCkp?`f~o?za8Lj2J;xE9fC${Q1I>o<8&wH~K%Dn4&z>-@EV+$yqqiKvT1 z8pm_%j@oabR+njkhQCXYlV0glAFi^F?yoMf#>V?>OaBJnbvh@;B>EedV|ED`nAI9< zLOa1j`w@WNDGEcWgb5JB2rni(O&H8@5k1jS#u>Fr0FsiqGnpZ zYAg6Q_HtNTmDi6fj*zB1ntvaoi|{NVQHW*eF2c7GhzQ{oRLawo`+NYG@sT1`^tV6V1e1?gS$@`QXPvPXP_g6S= z^#vdb88OOOhCd(%zbX|-`v9= zCz)NgOclSiTG~QM(z_X|dR78F&-G$mwBzfhWUz$Ew5udF*}$tX6VCSAljoi!|Ht7!}!?e z?jYCM<>w^*rP^DKlTNI#>(8`s$L&&M`GP9sP7!^qZ;ZOEdcvW14GtkG!gtKK@8CW8 z^;OiGh64*_KQ9~mOGpACw-^h7Fq1=&-%8;70m~&?4yBa^RX7Qv+qGXm!iln1P%YKf zHgU);u%7;OWh}`JqIS5IAviGPKmTH~Dgclb@$||f$#XO)(%JnP+6$4h9BEaS49Ptq zt^RGz(jr4-cqv0qZnylKRQz~O|!VgG3icH2RntqxhKy3waiVsXJiSusiia_g4 z>{6v;x;Xu$PhMX=Q7H`~Os2u8etY39xR5isLFI4yZ!%VuX-tc9*7LgON>?kcgj=n? znM{9%Pk4*0B#l6wo_#G#-6lAe4$0m_D_X`Uk9q2tKPj=waJ-KG3f4#R`#d01Q?7ea z_{ZAQRekfHz`3&zPm)Dvt#lzJy}A$miSEsg3H z!ndNQxq*T*+PcOVoZ>5v5&NYTr&1>e%nWq7>Kniw$|;h1b`avFyU)6#0~>&}eRENn zRi(sIP zuoT7pkBO&}f|g^mIOV!Z)@43WC_lU}_4=yPgVMF5h?Le*2C!b(rvq;)=6+<8sYCto zo4XhpC}%UZlNj3K)8*(^ddpHOTF+_J@MO;j({+XVv)Np=rzr!;g}l&2U68}nY_>W6 zK)jqz(D`ug<9VEAO=g44!Pi8?FA`E1nGdKvUvAAp2)^~^D z-`_RBrV<&1l-vP=w^51ouwVp_eU{X|e*eyv=JLx*=g`j^**};5EAsOtnN=A3zSWfy zKZUGlOZ#zpIb>oYM0oWs0+rRinp`*%cySIem-n)8$Tx{a@$zP@y7ScY^9)JPqEn3! zpcpmEs)I%Ay`5+G*^jR{@VP!{nJrfWwiXZkDX#sioAUc=e@zuh2?!uD88eV_l{nS( z5A&qbX+-8Rt)1FqlO7;d;{2FT?tCc=GBGsuR?XWD4`zP;{&;NG461Vu80;F(&zJ?J zSBtS|%`m0xn~Xn2Vt5Bg_oH8G#Z)9e!7Cg232-*OV_UH2T zfbEs-NPY)x4AsU?isHOIBQDf9JQaxgradpJ{QMR!ggW={6y~bH(WQ6P+*v=)OyLCaJdEhq=m2`*+7+<~;d7^c4274x; zv>A8m-DIj#>Ndt^T|rpMpzvM;Dc*Z$Z3clOw|2P`WYBJ+a><-1Cu|*e7yGZOqS~!? z1n$)bjh;;v;i5Sb+bfsI26Fnok>{jz*2wI480cQGOcU(xORYlN*R6Ifr4_DjhjhM) zu-}2*7)ap(l5$|c3NxPEbsq^)hE_X>zUF#WnfxXW&*Fg9hB01IKBFb6!`iYZiliu&a=h5hfYXh3rIurFILjI1cYoVFi5ll;EL3b$5eITXyQS18KUH z=zyi2SS|SN3ZEsQyeEr^m%abYpazqB1VaE6;n!j-qEJq5N7s+o5s8J&zI>4-jbFy$|H zy0yH|=MT5a&T;*Gg|_K^4oE+*VC&0+3hy!*;7iBfI8phzCfp;0wuw8uxAnS0%yfQt zvIYp>A6eKU^9x=1g8}tTd0ck3S3NguylB~yHp%K#b%>wZe;3{$!tf}jlFzT_Bpt$f zjVhX!hsK^HC(6l~1U1Zo?RBv@;xIU26%KEU`+ulYr^>0YZT5O2k|Ek-c{6h*F_jlu zO!c>5;YyX=y@VZvZ=X2sxNG;aXOHd;or+lH?EeJ$kW83H{orAUqb)0-C>cad}VVJ4$2>kW2V>bpdQsO5dWgppZe}?jG7msaKAz{N zz?p}_P8c=zKVhM2nxD<1xY?*)#R|_p*%RTJflEW{L6*at>6V8nCBM^KIpQB|J7lJq z#YGl+5WGAoPh;$n!`Js+BlOAB6mNMQe!r&th1R}A@vf@GXkhLN9o5(*zBggzsHLLhX3!zE04GT zH>q1={5M+z;eY3_LT^$&XD)qd_YPGlRI&kNss;~i|A>C#d@C$4i8()QrX%#)C?^HY|pp#NJ5u>|X_G!U;>=UB>ib~HRX2&_s?QKzljTi2OYtDMQ zZg6p+MI8bJ{o*`Og8=ViZT|~WR{r(!Vxvyt5=3k*imAL_z_gbK^|^?CTwzoE_MA(* zi2m71`UPFjAS8v`WJ;B@{$`CoU@;g~MMcGI$@G4u-&@vW?n)ztDJx*?9ofWM`$dxX zaTn%jD*WDpP3ilj<9@erYDdVB9+dXb^*KOE1dbLX=k_WM(} zv3qSpYzyVZDYsPSC=1__7drTj@x>)!x5xXFC*8rNc1kTTDkXhBwJvD%DQo?8*}{-e z&HDofA?NE+mi~uVA{{d#=MIYF7RGUkJJ;8D7!fGwANqg1uvuh6#UX9Ti|a+ux-`%) zZ5gSjBllM#H7NtptqnJvU{nc6dUQC-=l7Yos?m+1=5kR+jkC0yjw-oYtAr!mpPy{Y zAs2mURL9laJE1rf)8t|Ga;;pVrc(`P3aTZi@fEHnSV*wJ{$XviC#y*S8k}VWic;Ze z71IRa3twHKE=GM^?J#_F4Ov;Fic1cz~ zI&@Ui%R;8O?>F5eNG@pZ(%>MX(g=vO-E#6g=;9W$Jq89-);a)_h89@Mm8{sQR3gdg zb&cFW6%B%i0iSh9Nf%@C4oB+8Dw?}&)xE##ywH`q!4R8tdfcSKn{93UZevVhpN#32 zV1+!Z@^XSef_^sl-V&e#z1`pUFlE`(Fz zg+&;nj`2vZrs&rEToOg>Dv?c_;-B?YQ5iFkKoV#|_T+iye4)}mWpHyV;mRHO5>1s1 z7q@!OjX9Mf%vg?8*%LMll>KB*D59Q|DE&TW>6eSDH@Ji)CfV6LvM4NM5Mb+70*IsH z{xZ5Mp~n>;$H*J0nP026>Ot(s=kQWYj}!|pG;{427(Mho`tPs3tO)wto?oor#WBuO z{CR%d-bv0~AO4+?detHb1ML}&knd*HVU2su2=G3MUD=PLXG?a8Ufh4r)C;1o($c%t zo!#mDjY>hbGtRxVpE-CG^z*G|+T?~GpYDLhjIDk|QHAmQ=jz-wy{(WbVeCQU2+BM5 zw3gJ9LlUdKT|>cDUXWFLxa~4)2EDUBQr`m^uAk~@AN+JSIF`5jH$g}H#?Q?_yfkb- z*zku=_*bDFv=dG4JhP?b2-nM_$*tu)0Ol^VZ(VTj(WFM)&?BfX&{`eLkKahJbObN zox-0XlTbNJDI|qRB)?tK*lugy+P}O`g@VC;xf_%#uNrwh*6XGjYBsIesab=uKIJz= z+^vx)aI>C<=;vVw#x%VJ2Q5|L>e82Pd#iZbfFabKH|PVXGe%hXs8?`4ODKzegd9G<5ja zM~pT1G`6w~5Y%r%y@WvqaZE5!u}NP2-P)M2s)usXU2%Mq_4>$6Wg0996#a>k4XAAf zjrt%Y*BrmLE0>wju3 zwzdrg3c^Fg`+f{AxIDl>d|*Dw@<1j{{bcB#s$bW>VQgcoqGm-O?Kt=~(-!wwpA$CL zP!y+I*m?D#7lT}IbjuPX)jd8#Y`bNl>n@lms8yWL%0GkikEzXQ#v~0lFP0ttm*gLE zCX9I?LodpAQ_3{1@2tjCTJl4Sh5zRpS> z0gU5srzv;VTSORCEg&-r^Lt-icp1iWuaM5hs5i{j2Sj9YuFbMGeZVrh)(TA_awl{1 z6_J7^zQ!ZfIV3}P7X63w5l2u;|K)tA0#MH9_3Ox+djQJ$TAwaVZX0{q+f$eLIbG&X zo%u}sGpFSEJ^HIX&Wt+jMy6P@miM}1wEV~mBD2^VXL#BaT(4G&##?TWG zWx<&zzFy!uWhGZ^NViDmMOrQB}`XOPH(l{3QIA zE4??^&5!PW71-Y)P->8xT%ynK-d6`rcvbfF6v#z=-IS66YA%}&bqzN~Ldjo4;Ivje zQ}U3>_+2fwm#=jHgaefPeRw5NHlnw)wZ%4OImi;SHGHBd?nhLK#MT)J6o!Ce9OBiM zGV*vkn%_~rvEA3E&@%b|f#1crMQhrslTIGD>H!+R{Y(4GW7KsD-3-q0_F0*(u6k{IAcz*7Z_USOWb6@b zmlV6?w{z@f5Kw{$)TGc`G7saq-->KW(kg?tSvon^iHzELPNhq{mgIN{$#?B~IOw5AGs1I9JxQ z^o>o~5%r86vnc`;))MvuLRzy$QkM+blO$-0`;Vp8>%VU8d9iOd#`-W>3T}1oWdfd8 zwj~=AGjmoNSShj8FKvBR|gq`h>+Dh&}xwpW2u zzV&AVkg#HwX3gzd~p!OJq9HGGwZ8Di(8-fQTQ7*^IY&7+0J2olCO8VPFwTf+k_eWFi_d3I$9I{7M69mbT|0myhM2$) z`o`($(r%+3{)#v3uJ7Tt>+&-Tr9GL zK-J%nNKU!8+47DV&=_8Wzekq~SaCc0`4)-+1|IO^gWo0M@@ofr_>NWxs5i}v(8FG6 zM?LAzQl?s$z?q+0KCBkf1;yRh=bO*Dn%~TUaOUIg<@=MvFwk6uH3(ZM2lF!~qGaFc zC>@db<#o|Vj)rR*v)MdEtsUq2tX`c7M{z$6M$YWapbAxBNFv78X}kS0;i>#gD;@AL zOGgeV?Y`&TUX9@KI2VA|HED2QeRFZi*`R1}C-E){gcn0it^MY&Gf_EGF2rxipbVz| zAzSpC+>f8h4IV`G`hi8lecnZCLOHPFoJVO$03yf!^g$7`VZ)bn|BeBgTyw$07mWeU zo(E+XL_d3L{H2f|-BXMbH+@(*OQm~fqitQ&V{XR!-y)?5+z6C3`WcwEF)a*sm4tM6 zJ&U~`N1AwgG5h}3`$)j!f8u`shS~m(FYDIC(4HGGUl1=(-Dnpe@R;IpYo%{sVhDij Wnj<@$ntjj@VI)Lkzf}n7`~4p&g3;9g literal 0 HcmV?d00001 diff --git a/addons/web/doc/images/tests2.png b/addons/web/doc/images/tests2.png new file mode 100644 index 0000000000000000000000000000000000000000..59835b257b5e18f236303a34c66ede42f0bbc29e GIT binary patch literal 37769 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 literal 0 HcmV?d00001 diff --git a/addons/web/doc/images/tests3.png b/addons/web/doc/images/tests3.png new file mode 100644 index 0000000000000000000000000000000000000000..10b45eddedcbaf300d54245b85134efb2736c3cb GIT binary patch literal 37827 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 literal 0 HcmV?d00001 diff --git a/addons/web/doc/index.rst b/addons/web/doc/index.rst index 6a0d8dee2d4..a0c66be12fd 100644 --- a/addons/web/doc/index.rst +++ b/addons/web/doc/index.rst @@ -24,6 +24,8 @@ Contents: guides/client-action + testing + Indices and tables ================== diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst new file mode 100644 index 00000000000..34826201dc9 --- /dev/null +++ b/addons/web/doc/testing.rst @@ -0,0 +1,479 @@ +.. highlight:: javascript + +Testing in OpenERP Web +====================== + +Javascript Unit Testing +----------------------- + +OpenERP Web 7.0 includes means to unit-test both the core code of +OpenERP Web and your own javascript modules. On the javascript side, +unit-testing is based on QUnit_ with a number of helpers and +extensions for better integration with OpenERP. + +To see what the runner looks like, find (or start) an OpenERP server +with the web client enabled, and navigate to ``/web/tests`` e.g. `on +OpenERP's CI `_. This will +show the runner selector, which lists all modules with javascript unit +tests, and allows starting any of them (or all javascript tests in all +modules at once). + +.. image:: ./images/runner.png + :align: center + +Clicking any runner button will launch the corresponding tests in the +bundled QUnit_ runner: + +.. image:: ./images/tests.png + :align: center + +Writing a test case +------------------- + +The first step is to list the test file(s). This is done through the +``test`` key of the openerp manifest, by adding javascript files to it +(next to the usual YAML files, if any): + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'test': ['static/test/demo.js'], + } + +and to create the corresponding test file(s) + +.. note:: + + test files which do not exist will be ignored, if all test files + of a module are ignored (can not be found), the test runner will + consider that the module has no javascript tests + +After that, refreshing the runner selector will display the new module +and allow running all of its (0 so far) tests: + +.. image:: ./images/runner2.png + :align: center + +The next step is to create a test case:: + + openerp.testing.section('basic section', function (test) { + test('my first test', function () { + ok(false, "this test has run"); + }); + }); + +All testing helpers and structures live in the ``openerp.testing`` +module. OpenERP tests live in a :js:func:`~openerp.testing.section`, +which is itself part of a module. The first argument to a section is +the name of the section, the second one is the section body. + +:js:func:`~openerp.testing.test`, provided by the +:js:func:`~openerp.testing.section` to the callback, is used to +register a given test case which will be run whenever the test runner +actually does its job. OpenERP Web test case use standard `QUnit +assertions`_ within them. + +Launching the test runner at this point will run the test and display +the corresponding assertion message, with red colors indicating the +test failed: + +.. image:: ./images/tests2.png + :align: center + +Fixing the test (by replacing ``false`` to ``true`` in the assertion) +will make it pass: + +.. image:: ./images/tests3.png + :align: center + +Assertions +---------- + +As noted above, OpenERP Web's tests use `qunit assertions`_. They are +available globally (so they can just be called without references to +anything). The following list is available: + +.. js:function:: ok(state[, message]) + + checks that ``state`` is truthy (in the javascript sense) + +.. js:function:: strictEqual(actual, expected[, message]) + + checks that the actual (produced by a method being tested) and + expected values are identical (roughly equivalent to ``ok(actual + === expected, message)``) + +.. js:function:: notStrictEqual(actual, expected[, message]) + + checks that the actual and expected values are *not* identical + (roughly equivalent to ``ok(actual !== expected, message)``) + +.. js:function:: deepEqual(actual, expected[, message]) + + deep comparison between actual and expected: recurse into + containers (objects and arrays) to ensure that they have the same + keys/number of elements, and the values match. + +.. js:function:: notDeepEqual(actual, expected[, message]) + + inverse operation to :js:func:`deepEqual` + +.. js:function:: throws(block[, expected][, message]) + + checks that, when called, the ``block`` throws an + error. Optionally validates that error against ``expected``. + + :param Function block: + :param expected: if a regexp, checks that the thrown error's + message matches the regular expression. If an + error type, checks that the thrown error is of + that type. + :type expected: Error | RegExp + +.. js:function:: equal(actual, expected[, message]) + + checks that ``actual`` and ``expected`` are loosely equal, using + the ``==`` operator and its coercion rules. + +.. js:function:: notEqual(actual, expected[, message]) + + inverse operation to :js:func:`equal` + +Getting an OpenERP instance +--------------------------- + +The OpenERP instance is the base through which most OpenERP Web +modules behaviors (functions, objects, …) are accessed. As a result, +the test framework automatically builds one, and loads the module +being tested and all of its dependencies inside it. This new instance +is provided as the first positional parameter to your test +cases. Let's observe by adding javascript code (not test code) to the +test module: + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + } + +:: + + // src/js/demo.js + openerp.web_tests_demo = function (instance) { + instance.web_tests_demo = { + value_true: true, + SomeType: instance.web.Class.extend({ + init: function (value) { + this.value = value; + } + }) + }; + }; + +and then adding a new test case, which simply checks that the +``instance`` contains all the expected stuff we created in the +module:: + + // test/demo.js + test('module content', function (instance) { + ok(instance.web_tests_demo.value_true, "should have a true value"); + var type_instance = new instance.web_tests_demo.SomeType(42); + strictEqual(type_instance.value, 42, "should have provided value"); + }); + +DOM Scratchpad +-------------- + +As in the wider client, arbitrarily accessing document content is +strongly discouraged during tests. But DOM access is still needed to +e.g. fully initialize :js:class:`widgets <~openerp.web.Widget>` before +testing them. + +Thus, test cases get a DOM scratchpad as its second positional +parameter, in a jQuery instance. That scratchpad is fully cleaned up +before each test, and as long as it doesn't do anything outside the +scrartchpad your code can do whatever it wants:: + + // test/demo.js + test('DOM content', function (instance, $scratchpad) { + $scratchpad.html('

'); + ok($scratchpad.find('span').hasClass('foo'), + "should have provided class"); + }); + test('clean scratchpad', function (instance, $scratchpad) { + ok(!$scratchpad.children().length, "should have no content"); + ok(!$scratchpad.text(), "should have no text"); + }); + +.. note:: + + the top-level element of the scratchpad is not cleaned up, test + cases can add text or DOM children but shoud not alter + ``$scratchpad`` itself. + +Loading templates +----------------- + +To avoid the corresponding processing costs, by default templates are +not loaded into QWeb. If you need to render e.g. widgets making use of +QWeb templates, you can request their loading through the +:js:attr:`~TestOptions.templates` option. + +This will automatically load all relevant templates in the instance's +qweb before running the test case: + +.. code-block:: python + + { + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + 'qweb': ['static/src/xml/demo.xml'], + } + +.. code-block:: xml + + + + + +

+
+
+
+ +:: + + // test/demo.js + test('templates', {templates: true}, function (instance) { + var s = instance.web.qweb.render('DemoTemplate'); + var texts = $(s).find('p').map(function () { + return $(this).text(); + }).get(); + + deepEqual(texts, ['0', '1', '2', '3', '4']); + }); + +Asynchronous cases +------------------ + +The test case examples so far are all synchronous, they execute from +the first to the last line and once the last line has executed the +test is done. But the web client is full of :doc:`asynchronous code +`, and thus test cases need to be async-aware. + +This is done by returning a :js:class:`deferred ` from the +case callback:: + + // test/demo.js + test('asynchronous', { + asserts: 1 + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.resolve(); + }, 100); + return d; + }); + +This example also introduces an options object to the test case. In +this case, it's used to specify the number of assertions the test case +should expect, if less or more assertions are specified the case will +count as failed. + +Asynchronous test cases *must* specify the number of assertions they +will run. This allows more easily catching situations where e.g. the +test architecture was not warned about asynchronous operations. + +.. note:: + + asynchronous test cases also have a 2 seconds timeout: if the test + does not finish within 2 seconds, it will be considered + failed. This pretty much always means the test will not resolve. + +.. note:: + + if the returned deferred is rejected, the test will be failed + unless :js:attr:`~TestOptions.fail_on_rejection` is set to + ``false``. + +RPC +--- + +An important subset of asynchronous test cases is test cases which +need to perform (and chain, to an extent) RPC calls. + +.. note:: + + because they are a subset of asynchronous cases, RPC cases must + also provide a valid :js:attr:`assertions count + ` + +By default, test cases will fail when trying to perform an RPC +call. The ability to perform RPC calls must be explicitly requested by +a test case (or its containing test suite) through +:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or +``rpc``. + +Mock RPC +++++++++ + +The preferred (and most fastest from a setup and execution time point +of view) way to do RPC during tests is to mock the RPC calls: while +setting up the test case, provide what the RPC responses "should" be, +and only test the code between the "user" (the test itself) and the +RPC call, before the call is effectively done. + +To do this, set the :js:attr:`rpc option <~TestOptions.rpc>` to +``mock``. This will add a third parameter to the test case callback: + +.. js:function:: mock(rpc_spec, handler) + + Can be used in two different ways depending on the shape of the + first parameter: + + * If it matches the pattern ``model:method`` (if it contains a + colon, essentially) the call will set up the mocking of an RPC + call straight to the OpenERP server (through XMLRPC) as + performed via e.g. :js:func:`openerp.web.Model.call`. + + In that case, ``handler`` should be a function taking two + arguments ``args`` and ``kwargs``, matching the corresponding + arguments on the server side. Hander should simply return the + value as if it were returned by the Python XMLRPC handler:: + + test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { + // set up mocking + mock('people.famous:name_search', function (args, kwargs) { + strictEqual(kwargs.name, 'bob'); + return [ + [1, "Microsoft Bob"], + [2, "Bob the Builder"], + [3, "Silent Bob"] + ]; + }); + + // actual test code + return new instance.web.Model('people.famous') + .call('name_search', {name: 'bob'}).pipe(function (result) { + strictEqual(result.length, 3, "shoud return 3 people"); + strictEqual(result[0][1], "Microsoft Bob", + "the most famous bob should be Microsoft Bob"); + }); + }); + + * Otherwise, if it matches an absolute path (e.g. ``/a/b/c``) it + will mock a JSON-RPC call to a web client controller, such as + ``/web/webclient/translations``. In that case, the handler takes + a single ``params`` argument holding all of the parameters + provided over JSON-RPC. + + As previously, the handler should simply return the result value + as if returned by the original JSON-RPC handler:: + + test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) { + var fetched_dbs = false, fetched_langs = false; + mock('/web/database/get_list', function () { + fetched_dbs = true; + return ['foo', 'bar', 'baz']; + }); + mock('/web/session/get_lang_list', function () { + fetched_langs = true; + return [['vo_IS', 'Hopelandic / Vonlenska']]; + }); + + // widget needs that or it blows up + instance.webclient = {toggle_bars: openerp.testing.noop}; + var dbm = new instance.web.DatabaseManager({}); + return dbm.appendTo($s).pipe(function () { + ok(fetched_dbs, "should have fetched databases"); + ok(fetched_langs, "should have fetched languages"); + deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); + }); + }); + +.. note:: + + mock handlers can contain assertions, these assertions should be + part of the assertions count (and if multiple calls are made to a + handler containing assertions, it multiplies the effective number + of assertions) + +Actual RPC +++++++++++ + +.. TODO:: rpc to database (implement & document) + +Testing API +----------- + +.. todo:: implement options on sections + +.. js:class:: TestOptions + + the various options which can be passed to + :js:func:`~openerp.testing.section` or + :js:func:`~openerp.testing.case` + + .. js:attribute:: TestOptions.asserts + + An integer, the number of assertions which should run during a + normal execution of the test. Mandatory for asynchronous tests. + + .. js:attribute:: TestOptions.setup + + .. todo:: implement & document setup (async?) + + .. js:attribute:: TestOptions.teardown + + .. todo:: implement & document teardown (async?) + + .. js:attribute:: TestOptions.fail_on_rejection + + If the test is asynchronous and its resulting promise is + rejected, fail the test. Defaults to ``true``, set to + ``false`` to not fail the test in case of rejection:: + + // test/demo.js + test('unfail rejection', { + asserts: 1, + fail_on_rejection: false + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.reject(); + }, 100); + return d; + }); + + .. js:attribute:: TestOptions.rpc + + RPC method to use during tests, one of ``"mock"`` or + ``"rpc"``. Any other value will disable RPC for the test (if + they were enabled by the suite for instance). + + .. js:attribute:: TestOptions.templates + + Whether the current module (and its dependencies)'s templates + should be loaded into QWeb before starting the test. A + boolean, ``false`` by default. + +Running through Python +---------------------- + +.. todo:: make that work and document it + +.. _qunit: http://qunitjs.com/ + +.. _qunit assertions: http://api.qunitjs.com/category/assert/ diff --git a/addons/web/http.py b/addons/web/http.py index 65630768737..b1d50597bf1 100644 --- a/addons/web/http.py +++ b/addons/web/http.py @@ -537,7 +537,7 @@ class Root(object): :rtype: ``Controller | None`` """ if l: - ps = '/' + '/'.join(l) + ps = '/' + '/'.join(filter(None, l)) meth = 'index' while ps: c = controllers_path.get(ps) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 3cb4437d1c3..80f965a6200 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -296,14 +296,14 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ $('.oe_secondary_menus_container,.oe_user_menu_placeholder').empty(); var fetch_db = this.rpc("/web/database/get_list", {}).pipe( function(result) { - self.db_list = result.db_list; + self.db_list = result; }, function (_, ev) { ev.preventDefault(); self.db_list = null; }); var fetch_langs = this.rpc("/web/session/get_lang_list", {}).then(function(result) { - self.lang_list = result.lang_list; + self.lang_list = result; }); return $.when(fetch_db, fetch_langs).then(self.do_render); }, diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js new file mode 100644 index 00000000000..4eadc3a5415 --- /dev/null +++ b/addons/web/static/src/js/testing.js @@ -0,0 +1,179 @@ +// Test support structures and methods for OpenERP +openerp.testing = {}; +(function (testing) { + var dependencies = { + corelib: [], + coresetup: ['corelib'], + data: ['corelib', 'coresetup'], + dates: [], + formats: ['coresetup', 'dates'], + chrome: ['corelib', 'coresetup'], + views: ['corelib', 'coresetup', 'data', 'chrome'], + search: ['data', 'coresetup', 'formats'], + list: ['views', 'data'], + form: ['data', 'views', 'list', 'formats'], + list_editable: ['list', 'form', 'data'], + }; + + testing.dependencies = window['oe_all_dependencies'] || []; + testing.current_module = null; + testing.templates = { }; + testing.add_template = function (name) { + var xhr = QWeb2.Engine.prototype.get_xhr(); + xhr.open('GET', name, false); + xhr.send(null); + (testing.templates[testing.current_module] = + testing.templates[testing.current_module] || []) + .push(xhr.responseXML); + }; + /** + * Function which does not do anything + */ + testing.noop = function () { }; + /** + * Alter provided instance's ``session`` attribute to make response + * mockable: + * + * * The ``responses`` parameter can be used to provide a map of (RPC) + * paths (e.g. ``/web/view/load``) to a function returning a response + * to the query. + * * ``instance.session`` grows a ``responses`` attribute which is + * a map of the same (and is in fact initialized to the ``responses`` + * parameter if one is provided) + * + * Note that RPC requests to un-mocked URLs will be rejected with an + * error message: only explicitly specified urls will get a response. + * + * Mocked sessions will *never* perform an actual RPC connection. + * + * @param instance openerp instance being initialized + * @param {Object} [responses] + */ + testing.mockifyRPC = function (instance, responses) { + var session = instance.session; + session.responses = responses || {}; + session.rpc_function = function (url, payload) { + var fn, params; + var needle = payload.params.model + ':' + payload.params.method; + if (url.url === '/web/dataset/call_kw' + && needle in this.responses) { + fn = this.responses[needle]; + params = [ + payload.params.args || [], + payload.params.kwargs || {} + ]; + } else { + fn = this.responses[url.url]; + params = [payload]; + } + + if (!fn) { + return $.Deferred().reject({}, 'failed', + _.str.sprintf("Url %s not found in mock responses, with arguments %s", + url.url, JSON.stringify(payload.params)) + ).promise(); + } + try { + return $.when(fn.apply(null, params)).pipe(function (result) { + // Wrap for RPC layer unwrapper thingy + return {result: result}; + }); + } catch (e) { + // not sure why this looks like that + return $.Deferred().reject({}, 'failed', String(e)); + } + }; + }; + + var _load = function (instance, module, loaded) { + if (!loaded) { loaded = []; } + + var deps = dependencies[module]; + if (!deps) { throw new Error("Unknown dependencies for " + module); } + + var to_load = _.difference(deps, loaded); + while (!_.isEmpty(to_load)) { + _load(instance, to_load[0], loaded); + to_load = _.difference(deps, loaded); + } + openerp.web[module](instance); + loaded.push(module); + }; + + testing.section = function (name, body) { + QUnit.module(testing.current_module + '.' + name); + body(testing.case); + }; + testing.case = function (name, options, callback) { + if (_.isFunction(options)) { + callback = options; + options = {}; + } + + var module = testing.current_module; + var module_index = _.indexOf(testing.dependencies, module); + var module_deps = testing.dependencies.slice( + // If module not in deps (because only tests, no JS) -> indexOf + // returns -1 -> index becomes 0 -> replace with ``undefined`` so + // Array#slice returns a full copy + 0, module_index + 1 || undefined); + QUnit.test(name, function (env) { + var instance = openerp.init(module_deps); + if (_.isNumber(options.asserts)) { + expect(options.asserts) + } + + if (options.templates) { + for(var i=0; i - - - - OpenERP Web Test Suite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - diff --git a/addons/web/static/test/testing.js b/addons/web/static/test/testing.js deleted file mode 100644 index 1be8e94e74b..00000000000 --- a/addons/web/static/test/testing.js +++ /dev/null @@ -1,97 +0,0 @@ -// Test support structures and methods for OpenERP -openerp.testing = (function () { - var xhr = QWeb2.Engine.prototype.get_xhr(); - xhr.open('GET', '/web/static/src/xml/base.xml', false); - xhr.send(null); - var doc = xhr.responseXML; - - var dependencies = { - corelib: [], - coresetup: ['corelib'], - data: ['corelib', 'coresetup'], - dates: [], - formats: ['coresetup', 'dates'], - chrome: ['corelib', 'coresetup'], - views: ['corelib', 'coresetup', 'data', 'chrome'], - search: ['data', 'coresetup', 'formats'], - list: ['views', 'data'], - form: ['data', 'views', 'list', 'formats'], - list_editable: ['list', 'form', 'data'], - }; - - return { - /** - * Function which does not do anything - */ - noop: function () { }, - /** - * Loads 'base.xml' template file into qweb for the provided instance - * - * @param instance openerp instance being initialized, to load the template file in - */ - loadTemplate: function (instance) { - instance.web.qweb.add_template(doc); - }, - /** - * Alter provided instance's ``session`` attribute to make response - * mockable: - * - * * The ``responses`` parameter can be used to provide a map of (RPC) - * paths (e.g. ``/web/view/load``) to a function returning a response - * to the query. - * * ``instance.session`` grows a ``responses`` attribute which is - * a map of the same (and is in fact initialized to the ``responses`` - * parameter if one is provided) - * - * Note that RPC requests to un-mocked URLs will be rejected with an - * error message: only explicitly specified urls will get a response. - * - * Mocked sessions will *never* perform an actual RPC connection. - * - * @param instance openerp instance being initialized - * @param {Object} [responses] - */ - mockifyRPC: function (instance, responses) { - var session = instance.session; - session.responses = responses || {}; - session.rpc_function = function (url, payload) { - var fn = this.responses[url.url + ':' + payload.params.method] - || this.responses[url.url]; - - if (!fn) { - return $.Deferred().reject({}, 'failed', - _.str.sprintf("Url %s not found in mock responses, with arguments %s", - url.url, JSON.stringify(payload.params)) - ).promise(); - } - return $.when(fn(payload)); - }; - }, - /** - * Creates an openerp web instance loading the specified module after - * all of its dependencies. - * - * @param {String} module - * @returns OpenERP Web instance - */ - instanceFor: function (module) { - var instance = openerp.init([]); - this._load(instance, module); - return instance; - }, - _load: function (instance, module, loaded) { - if (!loaded) { loaded = []; } - - var deps = dependencies[module]; - if (!deps) { throw new Error("Unknown dependencies for " + module); } - - var to_load = _.difference(deps, loaded); - while (!_.isEmpty(to_load)) { - this._load(instance, to_load[0], loaded); - to_load = _.difference(deps, loaded); - } - openerp.web[module](instance); - loaded.push(module); - } - } -})(); diff --git a/addons/web_graph/static/lib/flotr2/lib/bean.js b/addons/web_graph/static/lib/flotr2/lib/bean.js index 6e6e3ef4eb5..1a854771006 100644 --- a/addons/web_graph/static/lib/flotr2/lib/bean.js +++ b/addons/web_graph/static/lib/flotr2/lib/bean.js @@ -9,9 +9,7 @@ */ /*global module:true, define:true*/ !function (name, context, definition) { - if (typeof module !== 'undefined') module.exports = definition(name, context); - else if (typeof define === 'function' && typeof define.amd === 'object') define(definition); - else context[name] = definition(name, context); + context[name] = definition(name, context); }('bean', this, function (name, context) { var win = window , old = context[name] diff --git a/addons/web_tests_demo/__init__.py b/addons/web_tests_demo/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/addons/web_tests_demo/__openerp__.py b/addons/web_tests_demo/__openerp__.py new file mode 100644 index 00000000000..7404ef6b4fc --- /dev/null +++ b/addons/web_tests_demo/__openerp__.py @@ -0,0 +1,8 @@ +{ + 'name': "Demonstration of web/javascript tests", + 'category': 'Hidden', + 'depends': ['web'], + 'js': ['static/src/js/demo.js'], + 'test': ['static/test/demo.js'], + 'qweb': ['static/src/xml/demo.xml'], +} diff --git a/addons/web_tests_demo/static/src/js/demo.js b/addons/web_tests_demo/static/src/js/demo.js new file mode 100644 index 00000000000..b35b44b80f8 --- /dev/null +++ b/addons/web_tests_demo/static/src/js/demo.js @@ -0,0 +1,11 @@ +// static/src/js/demo.js +openerp.web_tests_demo = function (instance) { + instance.web_tests_demo = { + value_true: true, + SomeType: instance.web.Class.extend({ + init: function (value) { + this.value = value; + } + }) + }; +}; diff --git a/addons/web_tests_demo/static/src/xml/demo.xml b/addons/web_tests_demo/static/src/xml/demo.xml new file mode 100644 index 00000000000..1bd3862d70e --- /dev/null +++ b/addons/web_tests_demo/static/src/xml/demo.xml @@ -0,0 +1,7 @@ + +
+ +

+
+
+
diff --git a/addons/web_tests_demo/static/test/demo.js b/addons/web_tests_demo/static/test/demo.js new file mode 100644 index 00000000000..0bf5a1a58b6 --- /dev/null +++ b/addons/web_tests_demo/static/test/demo.js @@ -0,0 +1,87 @@ +openerp.testing.section('basic section', function (test) { + test('my first test', function () { + ok(true, "this test has run"); + }); + test('module content', function (instance) { + ok(instance.web_tests_demo.value_true, "should have a true value"); + var type_instance = new instance.web_tests_demo.SomeType(42); + strictEqual(type_instance.value, 42, "should have provided value"); + }); + test('DOM content', function (instance, $scratchpad) { + $scratchpad.html('
ok
'); + ok($scratchpad.find('span').hasClass('foo'), + "should have provided class"); + }); + test('clean scratchpad', function (instance, $scratchpad) { + ok(!$scratchpad.children().length, "should have no content"); + ok(!$scratchpad.text(), "should have no text"); + }); + + test('templates', {templates: true}, function (instance) { + var s = instance.web.qweb.render('DemoTemplate'); + var texts = $(s).find('p').map(function () { + return $(this).text(); + }).get(); + + deepEqual(texts, ['0', '1', '2', '3', '4']); + }); + + test('asynchronous', { + asserts: 1 + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.resolve(); + }, 100); + return d; + }); + test('unfail rejection', { + asserts: 1, + fail_on_rejection: false + }, function () { + var d = $.Deferred(); + setTimeout(function () { + ok(true); + d.reject(); + }, 100); + return d; + }); + + test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { + mock('people.famous:name_search', function (args, kwargs) { + strictEqual(kwargs.name, 'bob'); + return [ + [1, "Microsoft Bob"], + [2, "Bob the Builder"], + [3, "Silent Bob"] + ]; + }); + return new instance.web.Model('people.famous') + .call('name_search', {name: 'bob'}).pipe(function (result) { + strictEqual(result.length, 3, "shoud return 3 people"); + strictEqual(result[0][1], "Microsoft Bob", + "the most famous bob should be Microsoft Bob"); + }); + }); + test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) { + var fetched_dbs = false, fetched_langs = false; + mock('/web/database/get_list', function () { + fetched_dbs = true; + return ['foo', 'bar', 'baz']; + }); + mock('/web/session/get_lang_list', function () { + fetched_langs = true; + return [['vo_IS', 'Hopelandic / Vonlenska']]; + }); + + // widget needs that or it blows up + instance.webclient = {toggle_bars: openerp.testing.noop}; + var dbm = new instance.web.DatabaseManager({}); + return dbm.appendTo($s).pipe(function () { + ok(fetched_dbs, "should have fetched databases"); + ok(fetched_langs, "should have fetched languages"); + deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); + }); + }); +}); From 04282ff00e8fa70c3eb0e9a48ba0cd32aa0e1cd7 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 26 Oct 2012 10:45:43 +0200 Subject: [PATCH 004/188] [IMP] port search test to new framework, add handling of web.{submodule} dependencies bzr revid: xmo@openerp.com-20121026084543-fobkc3ta5q2jc3q6 --- addons/web/doc/testing.rst | 35 +- addons/web/static/src/js/boot.js | 10 +- addons/web/static/src/js/testing.js | 111 +++-- addons/web/static/src/js/view_list.js | 2 +- addons/web/static/src/js/views.js | 3 +- addons/web/static/test/search.js | 655 +++++++++++--------------- 6 files changed, 395 insertions(+), 421 deletions(-) diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 34826201dc9..582960846e4 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -417,26 +417,49 @@ Actual RPC Testing API ----------- -.. todo:: implement options on sections +.. js:function:: openerp.testing.section(name[, options], body) + + :param String name: + :param TestOptions options: + :param body: + :type body: Function<:js:func:`~openerp.testing.case`, void> + +.. js:function:: openerp.testing.case(name[, options], callback) + + :param String name: + :param TestOptions options: + :param callback: + :type callback: Function> .. js:class:: TestOptions the various options which can be passed to :js:func:`~openerp.testing.section` or - :js:func:`~openerp.testing.case` + :js:func:`~openerp.testing.case`. Except for + :js:attr:`~TestOptions.setup` and + :js:attr:`~TestOptions.teardown`, an option on + :js:func:`~openerp.testing.case` will overwrite the corresponding + option on :js:func:`~openerp.testing.section` so + e.g. :js:attr:`~TestOptions.rpc` can be set for a + :js:func:`~openerp.testing.section` and then differently set for + some :js:func:`~openerp.testing.case` of that + :js:func:`~openerp.testing.section` .. js:attribute:: TestOptions.asserts - + An integer, the number of assertions which should run during a normal execution of the test. Mandatory for asynchronous tests. - + .. js:attribute:: TestOptions.setup - .. todo:: implement & document setup (async?) + Test case setup, run right before each test case. A section's + :js:func:`~TestOptions.setup` is run before the case's own, if + both are specified. .. js:attribute:: TestOptions.teardown - .. todo:: implement & document teardown (async?) + Test case teardown, a case's :js:func:`~TestOptions.teardown` + is run before the corresponding section if both are present. .. js:attribute:: TestOptions.fail_on_rejection diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 05ce709e80a..631a7f8c6f5 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -19,12 +19,14 @@ /** * OpenERP instance constructor * - * @param {Array} modules list of modules to initialize + * @param {Array|String} modules list of modules to initialize */ init: function(modules) { - // By default only web will be loaded, the rest will be by loaded - // by openerp.web.Session on the first session_authenticate - modules = _.union(['web'], modules || []); + if (modules === "fuck your shit, don't load anything you cunt") { + modules = []; + } else { + modules = _.union(['web'], modules || []); + } var new_instance = { // links to the global openerp _openerp: openerp, diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js index 4eadc3a5415..e4f327bf0c3 100644 --- a/addons/web/static/src/js/testing.js +++ b/addons/web/static/src/js/testing.js @@ -85,23 +85,17 @@ openerp.testing = {}; }; }; - var _load = function (instance, module, loaded) { - if (!loaded) { loaded = []; } - - var deps = dependencies[module]; - if (!deps) { throw new Error("Unknown dependencies for " + module); } - - var to_load = _.difference(deps, loaded); - while (!_.isEmpty(to_load)) { - _load(instance, to_load[0], loaded); - to_load = _.difference(deps, loaded); + testing.section = function (name, options, body) { + if (_.isFunction(options)) { + body = options; + options = {}; } - openerp.web[module](instance); - loaded.push(module); - }; + _.defaults(options, { + setup: testing.noop, + teardown: testing.noop + }); - testing.section = function (name, body) { - QUnit.module(testing.current_module + '.' + name); + QUnit.module(testing.current_module + '.' + name, {_oe: options}); body(testing.case); }; testing.case = function (name, options, callback) { @@ -109,6 +103,10 @@ openerp.testing = {}; callback = options; options = {}; } + _.defaults(options, { + setup: testing.noop, + teardown: testing.noop + }); var module = testing.current_module; var module_index = _.indexOf(testing.dependencies, module); @@ -117,13 +115,66 @@ openerp.testing = {}; // returns -1 -> index becomes 0 -> replace with ``undefined`` so // Array#slice returns a full copy 0, module_index + 1 || undefined); - QUnit.test(name, function (env) { - var instance = openerp.init(module_deps); - if (_.isNumber(options.asserts)) { - expect(options.asserts) + QUnit.test(name, function () { + // module testing environment + var self = this; + var opts = _.defaults({ + // section setup + // case setup + // test + // case teardown + // section teardown + setup: function () { + if (self._oe.setup.apply(null, arguments)) { + throw new Error("Asynchronous setup not implemented"); + } + if (options.setup.apply(null, arguments)) { + throw new Error("Asynchronous setup not implemented"); + } + }, + teardown: function () { + if (options.teardown.apply(null, arguments)) { + throw new Error("Asynchronous teardown not implemented"); + } + if (self._oe.teardown(null, arguments)) { + throw new Error("Asynchronous teardown not implemented"); + } + } + }, options, this._oe); + + var instance; + if (!opts.dependencies) { + instance = openerp.init(module_deps); + } else { + // empty-but-specified dependencies actually allow running + // without loading any module into the instance + + // TODO: clean up this mess + var d = opts.dependencies.slice(); + var di = 0; + while (di < d.length) { + var m = /^web\.(\w+)$/.exec(d[di]); + if (m) { + d[di] = m[1]; + } + d.splice.apply(d, [di+1, 0].concat( + _(dependencies[d[di]]).reverse())); + ++di; + } + + instance = openerp.init("fuck your shit, don't load anything you cunt"); + _(d).chain() + .reverse() + .uniq() + .each(function (module) { + openerp.web[module](instance); + }); + } + if (_.isNumber(opts.asserts)) { + expect(opts.asserts); } - if (options.templates) { + if (opts.templates) { for(var i=0; i Date: Fri, 26 Oct 2012 11:21:44 +0200 Subject: [PATCH 005/188] [IMP] port basic/existing tests to new framework, apart from editor stuff bzr revid: xmo@openerp.com-20121026092144-0arxx2v9oi28e3d6 --- addons/web/static/src/js/testing.js | 3 + addons/web/static/test/Widget.js | 158 +++++++++++-------- addons/web/static/test/class.js | 67 ++++---- addons/web/static/test/evals.js | 39 ++--- addons/web/static/test/form.js | 40 ++--- addons/web/static/test/formats.js | 199 +++++++++++------------- addons/web/static/test/list-utils.js | 223 +++++++++++---------------- addons/web/static/test/registry.js | 77 +++++---- addons/web/static/test/rpc.js | 48 +++--- 9 files changed, 395 insertions(+), 459 deletions(-) diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js index e4f327bf0c3..45728902e7f 100644 --- a/addons/web/static/src/js/testing.js +++ b/addons/web/static/src/js/testing.js @@ -151,6 +151,9 @@ openerp.testing = {}; // TODO: clean up this mess var d = opts.dependencies.slice(); + // dependencies list should be in deps order, reverse to make + // loading order from last + d.reverse(); var di = 0; while (di < d.length) { var m = /^web\.(\w+)$/.exec(d[di]); diff --git a/addons/web/static/test/Widget.js b/addons/web/static/test/Widget.js index 3e6cc262565..44b7cfe0dfa 100644 --- a/addons/web/static/test/Widget.js +++ b/addons/web/static/test/Widget.js @@ -1,32 +1,7 @@ -$(document).ready(function () { - var $fix = $('#qunit-fixture'); - var mod = { - setup: function () { - instance = window.openerp.init([]); - window.openerp.web.corelib(instance); - - instance.web.qweb = new QWeb2.Engine(); - instance.web.qweb.add_template( - '' + - '' + - '
    ' + - '
  1. ' + - '' + - '' + - '
  2. ' + - '
' + - '
' + - '' + - '

' + - '
' + - '
'); - } - }; - var instance; - - module('Widget.proxy', mod); - test('(String)', function () { +openerp.testing.section('Widget.proxy', { + dependencies: ['web.corelib'] +}, function (test) { + test('(String)', function (instance) { var W = instance.web.Widget.extend({ exec: function () { this.executed = true; @@ -37,7 +12,7 @@ $(document).ready(function () { fn(); ok(w.executed, 'should execute the named method in the right context'); }); - test('(String)(*args)', function () { + test('(String)(*args)', function (instance) { var W = instance.web.Widget.extend({ exec: function (arg) { this.executed = arg; @@ -49,7 +24,7 @@ $(document).ready(function () { ok(w.executed, "should execute the named method in the right context"); equal(w.executed, 42, "should be passed the proxy's arguments"); }); - test('(String), include', function () { + test('(String), include', function (instance) { // the proxy function should handle methods being changed on the class // and should always proxy "by name", to the most recent one var W = instance.web.Widget.extend({ @@ -67,23 +42,43 @@ $(document).ready(function () { equal(w.executed, 2, "should be lazily resolved"); }); - test('(Function)', function () { + test('(Function)', function (instance) { var w = new (instance.web.Widget.extend({ })); var fn = w.proxy(function () { this.executed = true; }); fn(); ok(w.executed, "should set the function's context (like Function#bind)"); }); - test('(Function)(*args)', function () { + test('(Function)(*args)', function (instance) { var w = new (instance.web.Widget.extend({ })); var fn = w.proxy(function (arg) { this.executed = arg; }); fn(42); equal(w.executed, 42, "should be passed the proxy's arguments"); }); - - module('Widget.renderElement', mod); - test('no template, default', function () { +}); +openerp.testing.section('Widget.renderElement', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '' + + '' + + '
    ' + + '
  1. ' + + '' + + '' + + '
  2. ' + + '
' + + '
' + + '' + + '

' + + '
' + + '
'); + } +}, function (test) { + test('no template, default', function (instance) { var w = new (instance.web.Widget.extend({ })); var $original = w.$el; @@ -98,7 +93,7 @@ $(document).ready(function () { equal(w.el.attributes.length, 0, "should not have generated any attribute"); ok(_.isEmpty(w.$el.html(), "should not have generated any content")); }); - test('no template, custom tag', function () { + test('no template, custom tag', function (instance) { var w = new (instance.web.Widget.extend({ tagName: 'ul' })); @@ -106,7 +101,7 @@ $(document).ready(function () { equal(w.el.nodeName, 'UL', "should have generated the custom element tag"); }); - test('no template, @id', function () { + test('no template, @id', function (instance) { var w = new (instance.web.Widget.extend({ id: 'foo' })); @@ -116,7 +111,7 @@ $(document).ready(function () { equal(w.$el.attr('id'), 'foo', "should have generated the id attribute"); equal(w.el.id, 'foo', "should also be available via property"); }); - test('no template, @className', function () { + test('no template, @className', function (instance) { var w = new (instance.web.Widget.extend({ className: 'oe_some_class' })); @@ -125,7 +120,7 @@ $(document).ready(function () { equal(w.el.className, 'oe_some_class', "should have the right property"); equal(w.$el.attr('class'), 'oe_some_class', "should have the right attribute"); }); - test('no template, bunch of attributes', function () { + test('no template, bunch of attributes', function (instance) { var w = new (instance.web.Widget.extend({ attributes: { 'id': 'some_id', @@ -152,7 +147,7 @@ $(document).ready(function () { equal(w.$el.attr('spoiler'), 'snape kills dumbledore'); }); - test('template', function () { + test('template', function (instance) { var w = new (instance.web.Widget.extend({ template: 'test.widget.template' })); @@ -162,9 +157,41 @@ $(document).ready(function () { equal(w.$el.children().length, 5); equal(w.el.textContent, '01234'); }); - - module('Widget.$', mod); - test('basic-alias', function () { + test('repeated', { asserts: 4 }, function (instance, $fix) { + var w = new (instance.web.Widget.extend({ + template: 'test.widget.template-value' + })); + w.value = 42; + return w.appendTo($fix) + .done(function () { + equal($fix.find('p').text(), '42', "DOM fixture should contain initial value"); + equal(w.$el.text(), '42', "should set initial value"); + w.value = 36; + w.renderElement(); + equal($fix.find('p').text(), '36', "DOM fixture should use new value"); + equal(w.$el.text(), '36', "should set new value"); + }); + }); +}); +openerp.testing.section('Widget.$', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '' + + '' + + '
    ' + + '
  1. ' + + '' + + '' + + '
  2. ' + + '
' + + '
' + + '
'); + } +}, function (test) { + test('basic-alias', function (instance) { var w = new (instance.web.Widget.extend({ template: 'test.widget.template' })); @@ -173,9 +200,26 @@ $(document).ready(function () { ok(w.$('li:eq(3)').is(w.$el.find('li:eq(3)')), "should do the same thing as calling find on the widget root"); }); - - module('Widget.events', mod); - test('delegate', function () { +}); +openerp.testing.section('Widget.events', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.qweb = new QWeb2.Engine(); + instance.web.qweb.add_template( + '' + + '' + + '
    ' + + '
  1. ' + + '' + + '' + + '
  2. ' + + '
' + + '
' + + '
'); + } +}, function (test) { + test('delegate', function (instance) { var a = []; var w = new (instance.web.Widget.extend({ template: 'test.widget.template', @@ -199,7 +243,7 @@ $(document).ready(function () { ok(a[i], "should pass test " + i); } }); - test('undelegate', function () { + test('undelegate', function (instance) { var clicked = false, newclicked = false; var w = new (instance.web.Widget.extend({ template: 'test.widget.template', @@ -218,22 +262,4 @@ $(document).ready(function () { ok(!clicked, "undelegate should unbind events delegated"); ok(newclicked, "undelegate should only unbind events it created"); }); - - module('Widget.renderElement', mod); - asyncTest('repeated', 4, function () { - var w = new (instance.web.Widget.extend({ - template: 'test.widget.template-value' - })); - w.value = 42; - w.appendTo($fix) - .always(start) - .done(function () { - equal($fix.find('p').text(), '42', "DOM fixture should contain initial value"); - equal(w.$el.text(), '42', "should set initial value"); - w.value = 36; - w.renderElement(); - equal($fix.find('p').text(), '36', "DOM fixture should use new value"); - equal(w.$el.text(), '36', "should set new value"); - }); - }); }); diff --git a/addons/web/static/test/class.js b/addons/web/static/test/class.js index faad4421e31..bb3fb7e12b9 100644 --- a/addons/web/static/test/class.js +++ b/addons/web/static/test/class.js @@ -1,30 +1,25 @@ -$(document).ready(function () { - var openerp; - module('web-class', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - } - }); - test('Basic class creation', function () { - var C = openerp.web.Class.extend({ +openerp.testing.section('class', { + dependencies: ['web.corelib'] +}, function (test) { + test('Basic class creation', function (instance) { + var C = instance.web.Class.extend({ foo: function () { return this.somevar; } }); - var instance = new C(); - instance.somevar = 3; + var i = new C(); + i.somevar = 3; - ok(instance instanceof C); - strictEqual(instance.foo(), 3); + ok(i instanceof C); + strictEqual(i.foo(), 3); }); - test('Class initialization', function () { - var C1 = openerp.web.Class.extend({ + test('Class initialization', function (instance) { + var C1 = instance.web.Class.extend({ init: function () { this.foo = 3; } }); - var C2 = openerp.web.Class.extend({ + var C2 = instance.web.Class.extend({ init: function (arg) { this.foo = arg; } @@ -36,8 +31,8 @@ $(document).ready(function () { strictEqual(i1.foo, 3); strictEqual(i2.foo, 42); }); - test('Inheritance', function () { - var C0 = openerp.web.Class.extend({ + test('Inheritance', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; } @@ -57,8 +52,8 @@ $(document).ready(function () { strictEqual(new C1().foo(), 2); strictEqual(new C2().foo(), 3); }); - test('In-place extension', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 3; }, @@ -83,8 +78,8 @@ $(document).ready(function () { strictEqual(new C0().foo(), 5); strictEqual(new C0().qux(), 5); }); - test('In-place extension and inheritance', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension and inheritance', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); @@ -101,24 +96,24 @@ $(document).ready(function () { strictEqual(new C1().foo(), 4); strictEqual(new C1().bar(), 2); }); - test('In-place extensions alter existing instances', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extensions alter existing instances', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); - var instance = new C0(); - strictEqual(instance.foo(), 1); - strictEqual(instance.bar(), 1); + var i = new C0(); + strictEqual(i.foo(), 1); + strictEqual(i.bar(), 1); C0.include({ foo: function () { return 2; }, bar: function () { return 2 + this._super(); } }); - strictEqual(instance.foo(), 2); - strictEqual(instance.bar(), 3); + strictEqual(i.foo(), 2); + strictEqual(i.bar(), 3); }); - test('In-place extension of subclassed types', function () { - var C0 = openerp.web.Class.extend({ + test('In-place extension of subclassed types', function (instance) { + var C0 = instance.web.Class.extend({ foo: function () { return 1; }, bar: function () { return 1; } }); @@ -126,13 +121,13 @@ $(document).ready(function () { foo: function () { return 1 + this._super(); }, bar: function () { return 1 + this._super(); } }); - var instance = new C1(); - strictEqual(instance.foo(), 2); + var i = new C1(); + strictEqual(i.foo(), 2); C0.include({ foo: function () { return 2; }, bar: function () { return 2 + this._super(); } }); - strictEqual(instance.foo(), 3); - strictEqual(instance.bar(), 4); + strictEqual(i.foo(), 3); + strictEqual(i.bar(), 4); }); }); diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js index 757d98c5bcc..6eec615b199 100644 --- a/addons/web/static/test/evals.js +++ b/addons/web/static/test/evals.js @@ -1,18 +1,11 @@ -$(document).ready(function () { - var openerp; - - module("eval.contexts", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - } - }); - test('context_sequences', function () { +openerp.testing.section('eval.contexts', { + dependencies: ['web.coresetup'] +}, function (test) { + test('context_sequences', function (instance) { // Context n should have base evaluation context + all of contexts // 0..n-1 in its own evaluation context var active_id = 4; - var result = openerp.session.test_eval_contexts([ + var result = instance.session.test_eval_contexts([ { "__contexts": [ { @@ -55,8 +48,8 @@ $(document).ready(function () { record_id: active_id }); }); - test('non-literal_eval_contexts', function () { - var result = openerp.session.test_eval_contexts([{ + test('non-literal_eval_contexts', function (instance) { + var result = instance.session.test_eval_contexts([{ "__ref": "compound_context", "__contexts": [ {"__ref": "context", "__debug": "{'type':parent.type}", @@ -133,17 +126,15 @@ $(document).ready(function () { }]); deepEqual(result, {type: 'out_invoice'}); }); - module('eval.domains', { - setup: function () { - openerp = window.openerp.testing.instanceFor('coresetup'); - window.openerp.web.dates(openerp); - } - }); - test('current_date', function () { - var current_date = openerp.web.date_to_str(new Date()); - var result = openerp.session.test_eval_domains( +}); +openerp.testing.section('eval.contexts', { + dependencies: ['web.coresetup', 'web.dates'] +}, function (test) { + test('current_date', function (instance) { + var current_date = instance.web.date_to_str(new Date()); + var result = instance.session.test_eval_domains( [[],{"__ref":"domain","__debug":"[('name','>=',current_date),('name','<=',current_date)]","__id":"5dedcfc96648"}], - openerp.session.test_eval_get_context()); + instance.session.test_eval_get_context()); deepEqual(result, [ ['name', '>=', current_date], ['name', '<=', current_date] diff --git a/addons/web/static/test/form.js b/addons/web/static/test/form.js index aace926a96a..0c8107ce9bc 100644 --- a/addons/web/static/test/form.js +++ b/addons/web/static/test/form.js @@ -1,33 +1,21 @@ -$(document).ready(function () { - var openerp; - module("form.widget", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - window.openerp.web.form(openerp); - } - }); - test("compute_domain", function () { +openerp.testing.section('compute_domain', { + dependencies: ['web.form'] +}, function (test) { + test("basic", function (instance) { var fields = { 'a': {value: 3}, 'group_method': {value: 'line'}, 'select1': {value: 'day'}, 'rrule_type': {value: 'monthly'} }; - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['a', '=', 3]], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['group_method','!=','count']], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( [['select1','=','day'], ['rrule_type','=','monthly']], fields)); }); - test("compute_domain or", function () { + test("or", function (instance) { var web = { 'section_id': {value: null}, 'user_id': {value: null}, @@ -38,22 +26,22 @@ $(document).ready(function () { '|', ['user_id','=',3], ['member_ids', 'in', [3]]]; - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'section_id': {value: 42}}))); - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'user_id': {value: 3}}))); - ok(openerp.web.form.compute_domain(domain, _.extend( + ok(instance.web.form.compute_domain(domain, _.extend( {}, web, {'member_ids': {value: 3}}))); }); - test("compute_domain not", function () { + test("not", function (instance) { var fields = { 'a': {value: 5}, 'group_method': {value: 'line'} }; - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( ['!', ['a', '=', 3]], fields)); - ok(openerp.web.form.compute_domain( + ok(instance.web.form.compute_domain( ['!', ['group_method','=','count']], fields)); }); }); diff --git a/addons/web/static/test/formats.js b/addons/web/static/test/formats.js index 4fe07ff0a9c..4536501d71d 100644 --- a/addons/web/static/test/formats.js +++ b/addons/web/static/test/formats.js @@ -1,16 +1,8 @@ -$(document).ready(function () { - var openerp; - - module('server-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - } - }); - test('Parse server datetime', function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); +openerp.testing.section('server-formats', { + dependencies: ['web.coresetup', 'web.dates'] +}, function (test) { + test('Parse server datetime', function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); deepEqual( [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()], @@ -20,92 +12,86 @@ $(document).ready(function () { date.getHours(), date.getMinutes(), date.getSeconds()], [2009, 5 - 1, 4, 12 - (date.getTimezoneOffset() / 60), 34, 23]); - var date2 = openerp.web.str_to_datetime('2011-12-10 00:00:00'); + var date2 = instance.web.str_to_datetime('2011-12-10 00:00:00'); deepEqual( [date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate(), date2.getUTCHours(), date2.getUTCMinutes(), date2.getUTCSeconds()], [2011, 12 - 1, 10, 0, 0, 0]); }); - test('Parse server date', function () { - var date = openerp.web.str_to_date("2009-05-04"); + test('Parse server date', function (instance) { + var date = instance.web.str_to_date("2009-05-04"); deepEqual( [date.getFullYear(), date.getMonth(), date.getDate()], [2009, 5 - 1, 4]); }); - test('Parse server time', function () { - var date = openerp.web.str_to_time("12:34:23"); + test('Parse server time', function (instance) { + var date = instance.web.str_to_time("12:34:23"); deepEqual( [date.getHours(), date.getMinutes(), date.getSeconds()], [12, 34, 23]); }); - - module('web-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - window.openerp.web.formats(openerp); - } - }); - test("format_datetime", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"datetime"}); +}); +openerp.testing.section('web-formats', { + dependencies: ['web.formats'] +}, function (test) { + test("format_datetime", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"datetime"}); equal(str, date.toString("MM/dd/yyyy HH:mm:ss")); }); - test("format_date", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"date"}); + test("format_date", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"date"}); equal(str, date.toString("MM/dd/yyyy")); }); - test("format_time", function () { - var date = openerp.web.str_to_datetime("2009-05-04 12:34:23"); - var str = openerp.web.format_value(date, {type:"time"}); + test("format_time", function (instance) { + var date = instance.web.str_to_datetime("2009-05-04 12:34:23"); + var str = instance.web.format_value(date, {type:"time"}); equal(str, date.toString("HH:mm:ss")); }); - test("format_float_time", function () { + test("format_float_time", function (instance) { strictEqual( - openerp.web.format_value(1.0, {type:'float', widget:'float_time'}), + instance.web.format_value(1.0, {type:'float', widget:'float_time'}), '01:00'); strictEqual( - openerp.web.format_value(0.9853, {type:'float', widget:'float_time'}), + instance.web.format_value(0.9853, {type:'float', widget:'float_time'}), '00:59'); strictEqual( - openerp.web.format_value(0.0085, {type:'float', widget:'float_time'}), + instance.web.format_value(0.0085, {type:'float', widget:'float_time'}), '00:01'); strictEqual( - openerp.web.format_value(-1.0, {type:'float', widget:'float_time'}), + instance.web.format_value(-1.0, {type:'float', widget:'float_time'}), '-01:00'); strictEqual( - openerp.web.format_value(-0.9853, {type:'float', widget:'float_time'}), + instance.web.format_value(-0.9853, {type:'float', widget:'float_time'}), '-00:59'); strictEqual( - openerp.web.format_value(-0.0085, {type:'float', widget:'float_time'}), + instance.web.format_value(-0.0085, {type:'float', widget:'float_time'}), '-00:01'); }); - test("format_float", function () { + test("format_float", function (instance) { var fl = 12.1234; - var str = openerp.web.format_value(fl, {type:"float"}); + var str = instance.web.format_value(fl, {type:"float"}); equal(str, "12.12"); - equal(openerp.web.format_value(12.02, {type: 'float'}), + equal(instance.web.format_value(12.02, {type: 'float'}), '12.02'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 3]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 3]}), '0.000'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 4]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 4]}), '0.0002'); - equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 6]}), + equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 6]}), '0.000200'); - equal(openerp.web.format_value(1, {type: 'float', digits: [1, 6]}), + equal(instance.web.format_value(1, {type: 'float', digits: [1, 6]}), '1.000000'); - equal(openerp.web.format_value(1, {type: 'float'}), + equal(instance.web.format_value(1, {type: 'float'}), '1.00'); - equal(openerp.web.format_value(-11.25, {type: 'float'}), + equal(instance.web.format_value(-11.25, {type: 'float'}), "-11.25"); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(1111111.25, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(1111111.25, {type: 'float'}), "1111,11,1.25"); - openerp.web._t.database.parameters.grouping = [1, 0]; - equal(openerp.web.format_value(-11.25, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 0]; + equal(instance.web.format_value(-11.25, {type: 'float'}), "-1,1.25"); }); // test("parse_datetime", function () { @@ -123,29 +109,29 @@ $(document).ready(function () { // var res = openerp.web.parse_value(val.toString("HH:mm:ss"), {type:"time"}); // equal(val.toString("HH:mm:ss"), res.toString("HH:mm:ss")); // }); - test('parse_integer', function () { - var val = openerp.web.parse_value('123,456', {type: 'integer'}); + test('parse_integer', function (instance) { + var val = instance.web.parse_value('123,456', {type: 'integer'}); equal(val, 123456); - openerp.web._t.database.parameters.thousands_sep = '|'; - var val2 = openerp.web.parse_value('123|456', {type: 'integer'}); + instance.web._t.database.parameters.thousands_sep = '|'; + var val2 = instance.web.parse_value('123|456', {type: 'integer'}); equal(val2, 123456); }); - test("parse_float", function () { + test("parse_float", function (instance) { var str = "134,112.1234"; - var val = openerp.web.parse_value(str, {type:"float"}); + var val = instance.web.parse_value(str, {type:"float"}); equal(val, 134112.1234); var str = "-134,112.1234"; - var val = openerp.web.parse_value(str, {type:"float"}); + var val = instance.web.parse_value(str, {type:"float"}); equal(val, -134112.1234); - _.extend(openerp.web._t.database.parameters, { + _.extend(instance.web._t.database.parameters, { decimal_point: ',', thousands_sep: '.' }); - var val3 = openerp.web.parse_value('123.456,789', {type: 'float'}); + var val3 = instance.web.parse_value('123.456,789', {type: 'float'}); equal(val3, 123456.789); }); - test('intersperse', function () { - var g = openerp.web.intersperse; + test('intersperse', function (instance) { + var g = instance.web.intersperse; equal(g("", []), ""); equal(g("0", []), "0"); equal(g("012", []), "012"); @@ -176,60 +162,61 @@ $(document).ready(function () { equal(g("12345678", [3,3,3,3], '.'), '12.345.678'); equal(g("12345678", [3,0], '.'), '12.345.678'); }); - test('format_integer', function () { - openerp.web._t.database.parameters.grouping = [3, 3, 3, 3]; - equal(openerp.web.format_value(1000000, {type: 'integer'}), + test('format_integer', function (instance) { + instance.web._t.database.parameters.grouping = [3, 3, 3, 3]; + equal(instance.web.format_value(1000000, {type: 'integer'}), '1,000,000'); - openerp.web._t.database.parameters.grouping = [3, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'integer'}), + instance.web._t.database.parameters.grouping = [3, 2, -1]; + equal(instance.web.format_value(106500, {type: 'integer'}), '1,06,500'); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'integer'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(106500, {type: 'integer'}), '106,50,0'); }); - test('format_float', function () { - openerp.web._t.database.parameters.grouping = [3, 3, 3, 3]; - equal(openerp.web.format_value(1000000, {type: 'float'}), + test('format_float', function (instance) { + instance.web._t.database.parameters.grouping = [3, 3, 3, 3]; + equal(instance.web.format_value(1000000, {type: 'float'}), '1,000,000.00'); - openerp.web._t.database.parameters.grouping = [3, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'float'}), + instance.web._t.database.parameters.grouping = [3, 2, -1]; + equal(instance.web.format_value(106500, {type: 'float'}), '1,06,500.00'); - openerp.web._t.database.parameters.grouping = [1, 2, -1]; - equal(openerp.web.format_value(106500, {type: 'float'}), + instance.web._t.database.parameters.grouping = [1, 2, -1]; + equal(instance.web.format_value(106500, {type: 'float'}), '106,50,0.00'); - _.extend(openerp.web._t.database.parameters, { + _.extend(instance.web._t.database.parameters, { grouping: [3, 0], decimal_point: ',', thousands_sep: '.' }); - equal(openerp.web.format_value(6000, {type: 'float'}), + equal(instance.web.format_value(6000, {type: 'float'}), '6.000,00'); }); - module('custom-date-formats', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.dates(openerp); - window.openerp.web.formats(openerp); - } +}); +openerp.testing.section('web-formats', { + dependencies: ['web.formats'] +}, function (test) { + test('format stripper', function (instance) { + strictEqual(instance.web.strip_raw_chars('%a, %Y %b %d'), + '%a, %Y %b %d'); + strictEqual(instance.web.strip_raw_chars('%a, %Y.eko %bren %da'), + '%a, %Y. %b %d'); }); - test('format stripper', function () { - strictEqual(openerp.web.strip_raw_chars('%a, %Y %b %d'), '%a, %Y %b %d'); - strictEqual(openerp.web.strip_raw_chars('%a, %Y.eko %bren %da'), '%a, %Y. %b %d'); + test('ES date format', function (instance) { + instance.web._t.database.parameters.date_format = '%a, %Y %b %d'; + var date = instance.web.str_to_date("2009-05-04"); + strictEqual(instance.web.format_value(date, {type:"date"}), + 'Mon, 2009 May 04'); + strictEqual(instance.web.parse_value('Mon, 2009 May 04', {type: 'date'}), + '2009-05-04'); }); - test('ES date format', function () { - openerp.web._t.database.parameters.date_format = '%a, %Y %b %d'; - var date = openerp.web.str_to_date("2009-05-04"); - strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009 May 04'); - strictEqual(openerp.web.parse_value('Mon, 2009 May 04', {type: 'date'}), '2009-05-04'); - }); - test('extended ES date format', function () { - openerp.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da'; - var date = openerp.web.str_to_date("2009-05-04"); - strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009. May 04'); - strictEqual(openerp.web.parse_value('Mon, 2009. May 04', {type: 'date'}), '2009-05-04'); + test('extended ES date format', function (instance) { + instance.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da'; + var date = instance.web.str_to_date("2009-05-04"); + strictEqual(instance.web.format_value(date, {type:"date"}), + 'Mon, 2009. May 04'); + strictEqual(instance.web.parse_value('Mon, 2009. May 04', {type: 'date'}), + '2009-05-04'); }); }); diff --git a/addons/web/static/test/list-utils.js b/addons/web/static/test/list-utils.js index 6200ba788ce..84661138315 100644 --- a/addons/web/static/test/list-utils.js +++ b/addons/web/static/test/list-utils.js @@ -1,45 +1,34 @@ -$(document).ready(function () { - var openerp, - create = function (o) { - if (typeof Object.create === 'function') { - return Object.create(o); - } - function Cls() {} - Cls.prototype = o; - return new Cls; - }; - module('list-events', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); +openerp.testing.section('list.events', { + dependencies: ['web.list'] +}, function (test) { + var create = function (o) { + if (typeof Object.create === 'function') { + return Object.create(o); } - }); - test('Simple event triggering', function () { - var e = create(openerp.web.list.Events), passed = false; + function Cls() {} + Cls.prototype = o; + return new Cls; + }; + test('Simple event triggering', function (instance) { + var e = create(instance.web.list.Events), passed = false; e.bind('foo', function () { passed = true; }); e.trigger('foo'); ok(passed); }); - test('Bind all', function () { - var e = create(openerp.web.list.Events), event = null; + test('Bind all', function (instance) { + var e = create(instance.web.list.Events), event = null; e.bind(null, function (ev) { event = ev; }); e.trigger('foo'); strictEqual(event, 'foo'); }); - test('Propagate trigger params', function () { - var e = create(openerp.web.list.Events), p = false; + test('Propagate trigger params', function (instance) { + var e = create(instance.web.list.Events), p = false; e.bind(null, function (_, param) { p = param }); e.trigger('foo', true); strictEqual(p, true) }); - test('Bind multiple callbacks', function () { - var e = create(openerp.web.list.Events), count; + test('Bind multiple callbacks', function (instance) { + var e = create(instance.web.list.Events), count; e.bind('foo', function () { count++; }) .bind('bar', function () { count++; }) .bind(null, function () { count++; }) @@ -59,20 +48,20 @@ $(document).ready(function () { e.trigger('baz'); strictEqual(count, 3); }); - test('Mixin events', function () { - var cls = openerp.web.Class.extend({ + test('Mixin events', function (instance) { + var cls = instance.web.Class.extend({ method: function () { this.trigger('e'); } }); - cls.include(openerp.web.list.Events); - var instance = new cls, triggered = false; + cls.include(instance.web.list.Events); + var i = new cls, triggered = false; - instance.bind('e', function () { triggered = true; }); - instance.method(); + i.bind('e', function () { triggered = true; }); + i.method(); ok(triggered); }); - test('Unbind all handlers', function () { - var e = create(openerp.web.list.Events), passed = 0; + test('Unbind all handlers', function (instance) { + var e = create(instance.web.list.Events), passed = 0; e.bind('foo', function () { passed++; }); e.trigger('foo'); strictEqual(passed, 1); @@ -80,8 +69,8 @@ $(document).ready(function () { e.trigger('foo'); strictEqual(passed, 1); }); - test('Unbind one handler', function () { - var e = create(openerp.web.list.Events), p1 = 0, p2 = 0, + test('Unbind one handler', function (instance) { + var e = create(instance.web.list.Events), p1 = 0, p2 = 0, h1 = function () { p1++; }, h2 = function () { p2++; }; e.bind('foo', h1); e.bind('foo', h2); @@ -93,29 +82,20 @@ $(document).ready(function () { strictEqual(p1, 1); strictEqual(p2, 2); }); - - module('list-records', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('Basic record initialization', function () { - var r = new openerp.web.list.Record({qux: 3}); +}); +openerp.testing.section('list.records', { + dependencies: ['web.list'] +}, function (test) { + test('Basic record initialization', function (instance) { + var r = new instance.web.list.Record({qux: 3}); r.set('foo', 1); r.set('bar', 2); strictEqual(r.get('foo'), 1); strictEqual(r.get('bar'), 2); strictEqual(r.get('qux'), 3); }); - test('Change all the things', function () { - var r = new openerp.web.list.Record(), changed = false, field; + test('Change all the things', function (instance) { + var r = new instance.web.list.Record(), changed = false, field; r.bind('change', function () { changed = true; }); r.bind(null, function (e) { field = field || e.split(':')[1]}); r.set('foo', 1); @@ -123,8 +103,8 @@ $(document).ready(function () { ok(changed); strictEqual(field, 'foo'); }); - test('Change single field', function () { - var r = new openerp.web.list.Record(), changed = 0; + test('Change single field', function (instance) { + var r = new instance.web.list.Record(), changed = 0; r.bind('change:foo', function () { changed++; }); r.set('foo', 1); r.set('bar', 1); @@ -132,21 +112,12 @@ $(document).ready(function () { strictEqual(r.get('bar'), 1); strictEqual(changed, 1); }); - - module('list-collections', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('degenerate-fetch', function () { - var c = new openerp.web.list.Collection(); +}); +openerp.testing.section('list.collections', { + dependencies: ['web.list'] +}, function (test) { + test('degenerate-fetch', function (instance) { + var c = new instance.web.list.Collection(); strictEqual(c.length, 0); c.add({id: 1, value: 2}); c.add({id: 2, value: 3}); @@ -155,16 +126,16 @@ $(document).ready(function () { strictEqual(c.length, 4); var r = c.at(2), r2 = c.get(1); - ok(r instanceof openerp.web.list.Record); + ok(r instanceof instance.web.list.Record); strictEqual(r.get('id'), 3); strictEqual(r.get('value'), 5); - ok(r2 instanceof openerp.web.list.Record); + ok(r2 instanceof instance.web.list.Record); strictEqual(r2.get('id'), 1); strictEqual(r2.get('value'), 2); }); - test('degenerate-indexed-add', function () { - var c = new openerp.web.list.Collection([ + test('degenerate-indexed-add', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -175,8 +146,8 @@ $(document).ready(function () { strictEqual(c.at(1).get('value'), 55); strictEqual(c.at(3).get('value'), 20); }); - test('degenerate-remove', function () { - var c = new openerp.web.list.Collection([ + test('degenerate-remove', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -188,9 +159,9 @@ $(document).ready(function () { equal(c.get(2), undefined); strictEqual(c.at(1).get('value'), 20); }); - test('degenerate-remove-bound', function () { + test('degenerate-remove-bound', function (instance) { var changed = false, - c = new openerp.web.list.Collection([ {id: 1, value: 5} ]); + c = new instance.web.list.Collection([ {id: 1, value: 5} ]); c.bind('change', function () { changed = true; }); var record = c.get(1); c.remove(record); @@ -198,8 +169,8 @@ $(document).ready(function () { ok(!changed, 'removed records should not trigger events in their ' + 'parent collection'); }); - test('degenerate-reset', function () { - var event, obj, c = new openerp.web.list.Collection([ + test('degenerate-reset', function (instance) { + var event, obj, c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -218,9 +189,9 @@ $(document).ready(function () { strictEqual(c.length, 1); strictEqual(c.get(42).get('value'), 55); }); - test('degenerate-reset-bound', function () { + test('degenerate-reset-bound', function (instance) { var changed = false, - c = new openerp.web.list.Collection([ {id: 1, value: 5} ]); + c = new instance.web.list.Collection([ {id: 1, value: 5} ]); c.bind('change', function () { changed = true; }); var record = c.get(1); c.reset(); @@ -229,9 +200,9 @@ $(document).ready(function () { 'parent collection'); }); - test('degenerate-propagations', function () { + test('degenerate-propagations', function (instance) { var values = []; - var c = new openerp.web.list.Collection([ + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -244,8 +215,8 @@ $(document).ready(function () { c.get(3).set('value', 21); deepEqual(values, [6, 11, 21]); }); - test('BTree', function () { - var root = new openerp.web.list.Collection(), + test('BTree', function (instance) { + var root = new instance.web.list.Collection(), c = root.proxy('admin'), total = 0; c.add({id: 1, name: "Administrator", login: 'admin'}); @@ -260,8 +231,8 @@ $(document).ready(function () { c.at(1).set('wealth', 5); strictEqual(total, 47); }); - test('degenerate-successor', function () { - var root = new openerp.web.list.Collection([ + test('degenerate-successor', function (instance) { + var root = new instance.web.list.Collection([ {id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}, @@ -282,8 +253,8 @@ $(document).ready(function () { root.at(3).attributes, "wraparound should have no effect if not succ(last_record)"); }); - test('successor', function () { - var root = new openerp.web.list.Collection(); + test('successor', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]); root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]); root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]); @@ -298,8 +269,8 @@ $(document).ready(function () { root.get(3).attributes, "should wraparound within a collection"); }); - test('degenerate-predecessor', function () { - var root = new openerp.web.list.Collection([ + test('degenerate-predecessor', function (instance) { + var root = new instance.web.list.Collection([ {id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}, @@ -320,8 +291,8 @@ $(document).ready(function () { root.at(0).attributes, "wraparound should have no effect if not pred(first_record)"); }); - test('predecessor', function () { - var root = new openerp.web.list.Collection(); + test('predecessor', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]); root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]); root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]); @@ -336,21 +307,12 @@ $(document).ready(function () { root.get(4).attributes, "should wraparound within a collection"); }); - - module('list-hofs', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('each, degenerate', function () { - var c = new openerp.web.list.Collection([ +}); +openerp.testing.section('list.collections.hom', { + dependencies: ['web.list'] +}, function (test) { + test('each, degenerate', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -362,8 +324,8 @@ $(document).ready(function () { ids, [1, 2, 3], 'degenerate collections should be iterated in record order'); }); - test('each, deep', function () { - var root = new openerp.web.list.Collection(), + test('each, deep', function (instance) { + var root = new instance.web.list.Collection(), ids = []; root.proxy('foo').add([ {id: 1, value: 5}, @@ -382,8 +344,8 @@ $(document).ready(function () { ids, [1, 2, 3, 10, 20, 30], 'tree collections should be deeply iterated'); }); - test('map, degenerate', function () { - var c = new openerp.web.list.Collection([ + test('map, degenerate', function (instance) { + var c = new instance.web.list.Collection([ {id: 1, value: 5}, {id: 2, value: 10}, {id: 3, value: 20} @@ -395,8 +357,8 @@ $(document).ready(function () { ids, [1, 2, 3], 'degenerate collections should be iterated in record order'); }); - test('map, deep', function () { - var root = new openerp.web.list.Collection(); + test('map, deep', function (instance) { + var root = new instance.web.list.Collection(); root.proxy('foo').add([ {id: 1, value: 5}, {id: 2, value: 10}, @@ -414,29 +376,20 @@ $(document).ready(function () { ids, [1, 2, 3, 10, 20, 30], 'tree collections should be deeply iterated'); }); - - module("list-weirds", { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.chrome(openerp); - // views loader stuff - window.openerp.web.data(openerp); - window.openerp.web.views(openerp); - window.openerp.web.list(openerp); - } - }); - test('set-from-noid', function () { - var root = new openerp.web.list.Collection(); +}); +openerp.testing.section('list.collection.weirdoes', { + dependencies: ['web.list'] +}, function (test) { + test('set-from-noid', function (instance) { + var root = new instance.web.list.Collection(); root.add({v: 3}); root.at(0).set('id', 42); var record = root.get(42); equal(root.length, 1); equal(record.get('v'), 3, "should have fetched the original record"); }); - test('set-from-previd', function () { - var root = new openerp.web.list.Collection(); + test('set-from-previd', function (instance) { + var root = new instance.web.list.Collection(); root.add({id: 1, v: 2}); root.get(1).set('id', 42); var record = root.get(42); diff --git a/addons/web/static/test/registry.js b/addons/web/static/test/registry.js index ca689a351e0..2ad69a541bc 100644 --- a/addons/web/static/test/registry.js +++ b/addons/web/static/test/registry.js @@ -1,58 +1,55 @@ -$(document).ready(function () { - var openerp; - module('Registry', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - openerp.web.Foo = {}; - openerp.web.Bar = {}; - openerp.web.Foo2 = {}; - } - }); - test('key set', function () { - var reg = new openerp.web.Registry(); +openerp.testing.section('registry', { + dependencies: ['web.corelib'], + setup: function (instance) { + instance.web.Foo = {}; + instance.web.Bar = {}; + instance.web.Foo2 = {}; + } +}, function (test) { + test('key set', function (instance) { + var reg = new instance.web.Registry(); - reg.add('foo', 'openerp.web.Foo') - .add('bar', 'openerp.web.Bar'); - strictEqual(reg.get_object('bar'), openerp.web.Bar); + reg.add('foo', 'instance.web.Foo') + .add('bar', 'instance.web.Bar'); + strictEqual(reg.get_object('bar'), instance.web.Bar); }); - test('extension', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('extension', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); - var reg2 = reg.extend({ 'foo': 'openerp.web.Foo2' }); - strictEqual(reg.get_object('foo'), openerp.web.Foo); - strictEqual(reg2.get_object('foo'), openerp.web.Foo2); + var reg2 = reg.extend({ 'foo': 'instance.web.Foo2' }); + strictEqual(reg.get_object('foo'), instance.web.Foo); + strictEqual(reg2.get_object('foo'), instance.web.Foo2); }); - test('remain-linked', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('remain-linked', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); var reg2 = reg.extend(); - reg.add('foo2', 'openerp.web.Foo2'); - strictEqual(reg.get_object('foo2'), openerp.web.Foo2); - strictEqual(reg2.get_object('foo2'), openerp.web.Foo2); + reg.add('foo2', 'instance.web.Foo2'); + strictEqual(reg.get_object('foo2'), instance.web.Foo2); + strictEqual(reg2.get_object('foo2'), instance.web.Foo2); }); - test('multiget', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('multiget', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); strictEqual(reg.get_any(['qux', 'grault', 'bar', 'foo']), - openerp.web.Bar); + instance.web.Bar); }); - test('extended-multiget', function () { - var reg = new openerp.web.Registry({ - foo: 'openerp.web.Foo', - bar: 'openerp.web.Bar' + test('extended-multiget', function (instance) { + var reg = new instance.web.Registry({ + foo: 'instance.web.Foo', + bar: 'instance.web.Bar' }); var reg2 = reg.extend(); strictEqual(reg2.get_any(['qux', 'grault', 'bar', 'foo']), - openerp.web.Bar); + instance.web.Bar); }); }); diff --git a/addons/web/static/test/rpc.js b/addons/web/static/test/rpc.js index fbe7147f2e6..84b4afa8baf 100644 --- a/addons/web/static/test/rpc.js +++ b/addons/web/static/test/rpc.js @@ -1,16 +1,8 @@ -$(document).ready(function () { - var openerp; - - module('Misordered resolution management', { - setup: function () { - openerp = window.openerp.init([]); - window.openerp.web.corelib(openerp); - window.openerp.web.coresetup(openerp); - window.openerp.web.data(openerp); - } - }); - test('Resolve all correctly ordered, sync', function () { - var dm = new openerp.web.DropMisordered(), flag = false; +openerp.testing.section('misordered resolution managemeng', { + dependencies: ['web.data'] +}, function (test) { + test('Resolve all correctly ordered, sync', function (instance) { + var dm = new instance.web.DropMisordered(), flag = false; var d1 = $.Deferred(), d2 = $.Deferred(), r1 = dm.add(d1), r2 = dm.add(d2); @@ -23,8 +15,8 @@ $(document).ready(function () { ok(flag); }); - test("Don't resolve mis-ordered, sync", function () { - var dm = new openerp.web.DropMisordered(), + test("Don't resolve mis-ordered, sync", function (instance) { + var dm = new instance.web.DropMisordered(), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -44,8 +36,8 @@ $(document).ready(function () { ok(done2); ok(!fail2); }); - test('Fail mis-ordered flag, sync', function () { - var dm = new openerp.web.DropMisordered(true), + test('Fail mis-ordered flag, sync', function (instance) { + var dm = new instance.web.DropMisordered(true), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -66,8 +58,8 @@ $(document).ready(function () { ok(!fail2); }); - asyncTest('Resolve all correctly ordered, async', 1, function () { - var dm = new openerp.web.DropMisordered(); + test('Resolve all correctly ordered, async', {asserts: 1}, function (instance) { + var dm = new instance.web.DropMisordered(); var d1 = $.Deferred(), d2 = $.Deferred(), r1 = dm.add(d1), r2 = dm.add(d2); @@ -75,13 +67,12 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 100); setTimeout(function () { d2.resolve(); }, 200); - $.when(r1, r2).done(function () { - start(); + return $.when(r1, r2).done(function () { ok(true); }); }); - asyncTest("Don't resolve mis-ordered, async", 4, function () { - var dm = new openerp.web.DropMisordered(), + test("Don't resolve mis-ordered, async", {asserts: 4}, function (instance) { + var dm = new instance.web.DropMisordered(), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -94,18 +85,20 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 200); setTimeout(function () { d2.resolve(); }, 100); + var done = $.Deferred(); setTimeout(function () { - start(); // d1 is in limbo ok(!done1); ok(!fail1); // d2 is resolved ok(done2); ok(!fail2); + done.resolve(); }, 400); + return $.when(d1, d2, done); }); - asyncTest('Fail mis-ordered flag, async', 4, function () { - var dm = new openerp.web.DropMisordered(true), + test('Fail mis-ordered flag, async', {asserts: 4}, function (instance) { + var dm = new instance.web.DropMisordered(true), done1 = false, done2 = false, fail1 = false, fail2 = false; @@ -118,6 +111,7 @@ $(document).ready(function () { setTimeout(function () { d1.resolve(); }, 200); setTimeout(function () { d2.resolve(); }, 100); + var done = $.Deferred(); setTimeout(function () { start(); // d1 is failed @@ -126,6 +120,8 @@ $(document).ready(function () { // d2 is resolved ok(done2); ok(!fail2); + done.resolve(); }, 400); + return $.when(d1, d2, done) }); }); From 6abc1134f5193d0a80066834a17f344ce24b09d8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 26 Oct 2012 12:04:52 +0200 Subject: [PATCH 006/188] [IMP] port list-edition tests to new framework bzr revid: xmo@openerp.com-20121026100452-8s4j9g0mxzfuy834 --- addons/web/static/test/list-editable.js | 260 ++++++++++-------------- 1 file changed, 113 insertions(+), 147 deletions(-) diff --git a/addons/web/static/test/list-editable.js b/addons/web/static/test/list-editable.js index 0388e56048d..0fc930793f2 100644 --- a/addons/web/static/test/list-editable.js +++ b/addons/web/static/test/list-editable.js @@ -1,16 +1,13 @@ -$(document).ready(function () { - var $fix = $('#qunit-fixture'); - - var instance; - var baseSetup = function () { - instance = openerp.testing.instanceFor('list_editable'); - - openerp.testing.loadTemplate(instance); - - openerp.testing.mockifyRPC(instance); - }; - - +openerp.testing.section('editor', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + mock('test.model:create', function () { + return 42; + }); + } +}, function (test) { /** * * @param {String} name @@ -30,7 +27,7 @@ $(document).ready(function () { } /** - * @param {Array} fields + * @param {Array} [fields] * @return {Object} */ function makeFormView(fields) { @@ -67,46 +64,37 @@ $(document).ready(function () { }; } - module('editor', { - setup: baseSetup - }); - asyncTest('base-state', 2, function () { + test('base-state', {asserts: 2}, function (instance, $fix) { var e = new instance.web.list.Editor({ dataset: {ids: []}, edition_view: function () { return makeFormView(); } }); - e.appendTo($fix) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) + return e.appendTo($fix) .done(function () { ok(!e.is_editing(), "should not be editing"); ok(e.form instanceof instance.web.FormView, "should use default form type"); }); }); - asyncTest('toggle-edition-save', 4, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; - instance.session.responses['/web/dataset/call_kw:read'] = function () { - return { result: [{ - id: 42, - a: false, - b: false, - c: false - }]}; - }; + test('toggle-edition-save', { + asserts: 4, + setup: function (instance, $s, mock) { + mock('test.model:read', function () { + return [{id: 42, a: false, b: false, c: false}]; + }); + } + }, function (instance, $fix) { var e = new instance.web.list.Editor({ - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ field('a'), field('b'), field('c') ]); } }); var counter = 0; - e.appendTo($fix) + return e.appendTo($fix) .pipe(function () { return e.edit({}, function () { ++counter; @@ -117,26 +105,21 @@ $(document).ready(function () { equal(counter, 3, "should have configured all fields"); return e.save(); }) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) .done(function (record) { ok(!e.is_editing(), "should have stopped editing"); equal(record.id, 42, "should have newly created id"); }) }); - asyncTest('toggle-edition-cancel', 2, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; + test('toggle-edition-cancel', { asserts: 2 }, function (instance, $fix) { var e = new instance.web.list.Editor({ - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ field('a'), field('b'), field('c') ]); } }); var counter = 0; - e.appendTo($fix) + return e.appendTo($fix) .pipe(function () { return e.edit({}, function () { ++counter; @@ -145,22 +128,20 @@ $(document).ready(function () { .pipe(function (form) { return e.cancel(); }) - .always(start) - .fail(function (error) { ok(false, error && error.message); }) .done(function (record) { ok(!e.is_editing(), "should have stopped editing"); ok(!record.id, "should have no id"); }) }); - asyncTest('toggle-save-required', 2, function () { - instance.session.responses['/web/dataset/call_kw:create'] = function () { - return { result: 42 }; - }; + test('toggle-save-required', { + asserts: 2, + fail_on_rejection: false + }, function (instance, $fix) { var e = new instance.web.list.Editor({ do_warn: function () { warnings++; }, - dataset: new instance.web.DataSetSearch(), + dataset: new instance.web.DataSetSearch(null, 'test.model'), prepends_on_create: function () { return false; }, edition_view: function () { return makeFormView([ @@ -169,7 +150,7 @@ $(document).ready(function () { }); var counter = 0; var warnings = 0; - e.appendTo($fix) + return e.appendTo($fix) .pipe(function () { return e.edit({}, function () { ++counter; @@ -178,78 +159,73 @@ $(document).ready(function () { .pipe(function (form) { return e.save(); }) - .always(start) .done(function () { ok(false, "cancel should not succeed"); }) .fail(function () { equal(warnings, 1, "should have been warned"); ok(e.is_editing(), "should have kept editing"); - }) + }); }); - - module('list-edition', { - setup: function () { - baseSetup(); - - var records = {}; - _.extend(instance.session.responses, { - '/web/view/load': function () { - return {result: { - type: 'tree', - fields: { - a: {type: 'char', string: "A"}, - b: {type: 'char', string: "B"}, - c: {type: 'char', string: "C"} - }, - arch: { - tag: 'tree', - attrs: {}, - children: [ - {tag: 'field', attrs: {name: 'a'}}, - {tag: 'field', attrs: {name: 'b'}}, - {tag: 'field', attrs: {name: 'c'}} - ] - } - }}; +}); +openerp.testing.section('list.edition', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + var records = {}; + mock('demo:create', function (args) { + records[42] = _.extend({}, args[0]); + return 42; + }); + mock('demo:read', function (args) { + var id = args[0][0]; + if (id in records) { + return [records[id]]; + } + return []; + }); + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"}, + b: {type: 'char', string: "B"}, + c: {type: 'char', string: "C"} }, - '/web/dataset/call_kw:create': function (params) { - records[42] = _.extend({}, params.params.args[0]); - return {result: 42}; - }, - '/web/dataset/call_kw:read': function (params) { - var id = params.params.args[0][0]; - if (id in records) { - return {result: [records[id]]}; - } - return {result: []}; + arch: { + tag: 'tree', + attrs: {}, + children: [ + {tag: 'field', attrs: {name: 'a'}}, + {tag: 'field', attrs: {name: 'b'}}, + {tag: 'field', attrs: {name: 'c'}} + ] } - }) - } - }); - asyncTest('newrecord', 6, function () { + }; + }); + } +}, function (test) { + test('newrecord', {asserts: 6}, function (instance, $fix, mock) { var got_defaults = false; - instance.session.responses['/web/dataset/call_kw:default_get'] = function (params) { - var fields = params.params.args[0]; + mock('demo:default_get', function (args) { + var fields = args[0]; deepEqual( fields, ['a', 'b', 'c'], "should ask defaults for all fields"); got_defaults = true; - return {result: { - a: "qux", - b: "quux" - }}; - }; + return { a: "qux", b: "quux" }; + }); var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); - l.appendTo($fix) + return l.appendTo($fix) .pipe(l.proxy('reload_content')) .pipe(function () { return l.start_edition(); }) - .always(start) .pipe(function () { ok(got_defaults, "should have fetched default values for form"); + return l.save_edition(); }) .pipe(function (result) { @@ -260,45 +236,39 @@ $(document).ready(function () { "should have used default values"); ok(!result.record.get('c'), "should have no value if there was no default"); - }) - .fail(function (e) { ok(false, e && e.message || e); }); - }); - - module('list-edition-events', { - setup: function () { - baseSetup(); - _.extend(instance.session.responses, { - '/web/view/load': function () { - return {result: { - type: 'tree', - fields: { - a: {type: 'char', string: "A"}, - b: {type: 'char', string: "B"}, - c: {type: 'char', string: "C"} - }, - arch: { - tag: 'tree', - attrs: {}, - children: [ - {tag: 'field', attrs: {name: 'a'}}, - {tag: 'field', attrs: {name: 'b'}}, - {tag: 'field', attrs: {name: 'c'}} - ] - } - }}; - }, - '/web/dataset/call_kw:read': function (params) { - return {result: [{ - id: 1, - a: 'foo', - b: 'bar', - c: 'baz' - }]}; - } }); - } }); - asyncTest('edition events', 4, function () { +}); +openerp.testing.section('list.edition.events', { + dependencies: ['web.list_editable'], + rpc: 'mock', + templates: true, + setup: function (instance, $s, mock) { + mock('demo:read', function () { + return [{ id: 1, a: 'foo', b: 'bar', c: 'baz' }]; + }); + mock('/web/view/load', function () { + return { + type: 'tree', + fields: { + a: {type: 'char', string: "A"}, + b: {type: 'char', string: "B"}, + c: {type: 'char', string: "C"} + }, + arch: { + tag: 'tree', + attrs: {}, + children: [ + {tag: 'field', attrs: {name: 'a'}}, + {tag: 'field', attrs: {name: 'b'}}, + {tag: 'field', attrs: {name: 'c'}} + ] + } + }; + }); + } +}, function (test) { + test('edition events', {asserts: 4}, function (instance, $fix) { var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var o = { counter: 0, @@ -306,9 +276,8 @@ $(document).ready(function () { }; var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); l.on('edit:before edit:after', o, o.onEvent); - l.appendTo($fix) + return l.appendTo($fix) .pipe(l.proxy('reload_content')) - .always(start) .pipe(function () { ok(l.options.editable, "should be editable"); equal(o.counter, 0, "should have seen no event yet"); @@ -317,11 +286,10 @@ $(document).ready(function () { .pipe(function () { ok(l.editor.is_editing(), "should be editing"); equal(o.counter, 2, "should have seen two edition events"); - }) - .fail(function (e) { ok(false, e && e.message); }); + }); }); - asyncTest('edition events: cancelling', 3, function () { + test('edition events: cancelling', {asserts: 3}, function (instance, $fix) { var edit_after = false; var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]); var l = new instance.web.ListView({}, ds, false, {editable: 'top'}); @@ -331,9 +299,8 @@ $(document).ready(function () { l.on('edit:after', {}, function () { edit_after = true; }); - l.appendTo($fix) + return l.appendTo($fix) .pipe(l.proxy('reload_content')) - .always(start) .pipe(function () { ok(l.options.editable, "should be editable"); return l.start_edition(); @@ -343,7 +310,6 @@ $(document).ready(function () { ok(!l.editor.is_editing(), "should not be editing"); ok(!edit_after, "should not have fired the edit:after event"); return $.when(); - }) - .fail(function (e) { ok(false, e && e.message || e); }); + }); }); }); From bf4a26d3e8613c24b3a360013525cfef28458176 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 29 Oct 2012 12:01:54 +0100 Subject: [PATCH 007/188] [ADD] actual-RPC tests, with UI. Bump QUnit timeout to 10s so RPC can run at all bzr revid: xmo@openerp.com-20121029110154-5927gaix8k0ijl0c --- addons/web/controllers/testing.py | 2 +- addons/web/doc/images/db-query.png | Bin 0 -> 7142 bytes addons/web/doc/images/tests2.png | Bin 37769 -> 20114 bytes addons/web/doc/images/tests3.png | Bin 37827 -> 20382 bytes addons/web/doc/testing.rst | 86 +++++++++- addons/web/static/src/js/testing.js | 182 ++++++++++++++++------ addons/web_tests_demo/__init__.py | 14 ++ addons/web_tests_demo/static/test/demo.js | 15 ++ 8 files changed, 242 insertions(+), 57 deletions(-) create mode 100644 addons/web/doc/images/db-query.png diff --git a/addons/web/controllers/testing.py b/addons/web/controllers/testing.py index 0cfc633a492..9947f1e1ed5 100644 --- a/addons/web/controllers/testing.py +++ b/addons/web/controllers/testing.py @@ -53,7 +53,7 @@ TESTING = Template(u""" diff --git a/addons/web/doc/images/db-query.png b/addons/web/doc/images/db-query.png new file mode 100644 index 0000000000000000000000000000000000000000..e063b724001871f3846ead587810069347a8eab6 GIT binary patch literal 7142 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 U?IK$f`NBkzl~#}{kudW8FIjHf#{d8T literal 0 HcmV?d00001 diff --git a/addons/web/doc/images/tests2.png b/addons/web/doc/images/tests2.png index 59835b257b5e18f236303a34c66ede42f0bbc29e..c8a6f8ae9eefbeff46a9b45e3a9948676d820714 100644 GIT binary patch literal 20114 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 diff --git a/addons/web/doc/images/tests3.png b/addons/web/doc/images/tests3.png index 10b45eddedcbaf300d54245b85134efb2736c3cb..247f70716af614d48ed6255832cb2d71dce5d9f2 100644 GIT binary patch literal 20382 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 diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 582960846e4..61077072ad2 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -297,8 +297,8 @@ test architecture was not warned about asynchronous operations. .. note:: - asynchronous test cases also have a 2 seconds timeout: if the test - does not finish within 2 seconds, it will be considered + asynchronous test cases also have a 10 seconds timeout: if the + test does not finish within 10 seconds, it will be considered failed. This pretty much always means the test will not resolve. .. note:: @@ -328,8 +328,8 @@ a test case (or its containing test suite) through Mock RPC ++++++++ -The preferred (and most fastest from a setup and execution time point -of view) way to do RPC during tests is to mock the RPC calls: while +The preferred (and fastest from a setup and execution time point of +view) way to do RPC during tests is to mock the RPC calls: while setting up the test case, provide what the RPC responses "should" be, and only test the code between the "user" (the test itself) and the RPC call, before the call is effectively done. @@ -412,7 +412,83 @@ To do this, set the :js:attr:`rpc option <~TestOptions.rpc>` to Actual RPC ++++++++++ -.. TODO:: rpc to database (implement & document) +A more realistic (but significantly slower and more expensive) way to +perform RPC calls is to perform actual calls to an actually running +OpenERP server. To do this, set the :js:attr:`rpc option +<~TestOptions.rpc>` to ``rpc``, it will not provide any new parameter +but will enable actual RPC, and the automatic creation and destruction +of databases (from a specified source) around tests. + +First, create a basic model we can test stuff with: + +.. code-block:: javascript + + from openerp.osv import orm, fields + + class TestObject(orm.Model): + _name = 'web_tests_demo.model' + + _columns = { + 'name': fields.char("Name", required=True), + 'thing': fields.char("Thing"), + 'other': fields.char("Other", required=True) + } + _defaults = { + 'other': "bob" + } + +then the actual test:: + + test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) { + var Model = new instance.web.Model('web_tests_demo.model'); + return Model.call('create', [{name: "Bob"}]) + .pipe(function (id) { + return Model.call('read', [[id]]); + }).pipe(function (records) { + strictEqual(records.length, 1); + var record = records[0]; + strictEqual(record.name, "Bob"); + strictEqual(record.thing, false); + // default value + strictEqual(record.other, 'bob'); + }); + }); + +This test looks like a "mock" RPC test but for the lack of mock +response (and the different ``rpc`` type), however it has further +ranging consequences in that it will copy an existing database to a +new one, run the test in full on that temporary database and destroy +the database, to simulate an isolated and transactional context and +avoid affecting other tests. One of the consequences is that it takes +a *long* time to run (5~10s, most of that time being spent waiting for +a database duplication). + +Furthermore, as the test needs to clone a database, it also has to ask +which database to clone, the database/super-admin password and the +password of the ``admin`` user (in order to authenticate as said +user). As a result, the first time the test runner encounters an +``rpc: "rpc"`` test configuration it will produce the following +prompt: + +.. image:: ./images/db-query.png + :align: center + +and stop the testing process until the necessary information has been +provided. + +The prompt will only appear once per test run, all tests will use the +same "source" database. + +.. note:: + + The handling of that information is currently rather brittle and + unchecked, incorrect values will likely crash the runner. + +.. note:: + + The runner does not currently store this information (for any + longer than a test run that is), the prompt will have to be filled + every time. Testing API ----------- diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js index 45728902e7f..744bd9fa2cd 100644 --- a/addons/web/static/src/js/testing.js +++ b/addons/web/static/src/js/testing.js @@ -85,6 +85,7 @@ openerp.testing = {}; }; }; + var db = window['oe_db_info'] || undefined; testing.section = function (name, options, body) { if (_.isFunction(options)) { body = options; @@ -115,32 +116,69 @@ openerp.testing = {}; // returns -1 -> index becomes 0 -> replace with ``undefined`` so // Array#slice returns a full copy 0, module_index + 1 || undefined); + + // Serialize options for this precise test case + // WARNING: typo is from jquery, do not fix! + var env = QUnit.config.currentModuleTestEnviroment; + var opts = _.defaults({ + // section setup + // case setup + // test + // case teardown + // section teardown + setup: function () { + var args = [].slice.call(arguments); + return $.when(env._oe.setup.apply(null, args)) + .pipe(function () { + return options.setup.apply(null, args); + }); + }, + teardown: function () { + var args = [].slice.call(arguments); + return $.when(options.teardown.apply(null, args)) + .pipe(function () { + return env._oe.teardown.apply(null, args); + }); + } + }, options, env._oe); + // FIXME: if this test is ignored, will still query + if (opts.rpc === 'rpc' && !db) { + QUnit.config.autostart = false; + db = { + source: null, + supadmin: null, + password: null + }; + var $msg = $('

') + .append('

A test needs to clone a database

') + .append('

Please provide the source clone information

') + .append(' Source DB: ').append('').append('
') + .append(' DB Password: ').append('').append('
') + .append('Admin Password: ').append('').append('
') + .append('') + .submit(function (e) { + e.preventDefault(); + e.stopPropagation(); + db.source = $msg.find('input[name=source]').val(); + db.supadmin = $msg.find('input[name=supadmin]').val(); + db.password = $msg.find('input[name=password]').val(); + QUnit.start(); + $.unblockUI(); + }); + $.blockUI({ + message: $msg, + css: { + fontFamily: 'monospace', + textAlign: 'left', + whiteSpace: 'pre-wrap', + cursor: 'default' + } + }); + } + QUnit.test(name, function () { // module testing environment var self = this; - var opts = _.defaults({ - // section setup - // case setup - // test - // case teardown - // section teardown - setup: function () { - if (self._oe.setup.apply(null, arguments)) { - throw new Error("Asynchronous setup not implemented"); - } - if (options.setup.apply(null, arguments)) { - throw new Error("Asynchronous setup not implemented"); - } - }, - teardown: function () { - if (options.teardown.apply(null, arguments)) { - throw new Error("Asynchronous teardown not implemented"); - } - if (self._oe.teardown(null, arguments)) { - throw new Error("Asynchronous teardown not implemented"); - } - } - }, options, this._oe); var instance; if (!opts.dependencies) { @@ -202,38 +240,80 @@ openerp.testing = {}; break; case 'rpc': async = true; + (function (setup, teardown) { + // Bunch of random base36 characters + var dbname = 'test_' + Math.random().toString(36).slice(2); + opts.setup = function (instance, $s) { + // FIXME hack: don't want the session to go through shitty loading process of everything + instance.session.session_init = testing.noop; + instance.session.load_modules = testing.noop; + instance.session.session_bind(); + return instance.session.rpc('/web/database/duplicate', { + fields: [ + {name: 'super_admin_pwd', value: db.supadmin}, + {name: 'db_original_name', value: db.source}, + {name: 'db_name', value: dbname} + ] + }).pipe(function (result) { + if (result.error) { + return $.Deferred().reject(result.error).promise(); + } + return instance.session.session_authenticate( + dbname, 'admin', db.password, true); + }).pipe(function () { + return setup(instance, $s); + }); + }; + opts.teardown = function (instance, $s) { + return $.when(teardown(instance, $s)).pipe(function () { + return instance.session.session_logout() + }).pipe(function () { + return instance.session.rpc('/web/database/drop', { + fields: [ + {name: 'drop_pwd', value: db.supadmin}, + {name: 'drop_db', value: db.dbname} + ] + }); + }).pipe(function (result) { + if (result.error) { + return $.Deferred().reject(result.error).promise(); + } + return result; + }); + }; + })(opts.setup, opts.teardown); } - // TODO: async setup/teardown - opts.setup(instance, $fixture, mock); - - var result = callback(instance, $fixture, mock); - - // TODO: cleanup which works on errors - if (!(result && _.isFunction(result.then))) { - if (async) { - ok(false, "asynchronous test cases must return a promise"); - } - opts.teardown(instance, $fixture, mock); - return; - } - + // Always execute tests asynchronously stop(); - if (!_.isNumber(opts.asserts)) { - ok(false, "asynchronous test cases must specify the " - + "number of assertions they expect"); - } - result.always(function () { - start(); - opts.teardown(instance, $fixture, mock); - }).fail(function (error) { - if (options.fail_on_rejection === false) { - return; + $.when(opts.setup(instance, $fixture, mock)) + .pipe(function () { + var result = callback(instance, $fixture, mock); + if (!(result && _.isFunction(result.then))) { + if (async) { + ok(false, "asynchronous test cases must return a promise"); + } + } else { + if (!_.isNumber(opts.asserts)) { + ok(false, "asynchronous test cases must specify the " + + "number of assertions they expect"); + } } - ok(false, typeof error === 'object' && error.message - ? error.message - : JSON.stringify([].slice.call(arguments))); - }) + return $.when(result).fail(function (error) { + if (options.fail_on_rejection === false) { + return; + } + ok(false, typeof error === 'object' && error.message + ? error.message + : JSON.stringify([].slice.call(arguments))); + }) + }).pipe(function () { + return opts.teardown(instance, $fixture, mock); + }, function () { + return opts.teardown(instance, $fixture, mock); + }).always(function () { + start(); + }); }); }; })(openerp.testing); diff --git a/addons/web_tests_demo/__init__.py b/addons/web_tests_demo/__init__.py index e69de29bb2d..137d472ec74 100644 --- a/addons/web_tests_demo/__init__.py +++ b/addons/web_tests_demo/__init__.py @@ -0,0 +1,14 @@ +from openerp.osv import orm, fields + +class TestObject(orm.Model): + _name = 'web_tests_demo.model' + + _columns = { + 'name': fields.char("Name", required=True), + 'thing': fields.char("Thing"), + 'other': fields.char("Other", required=True) + } + _defaults = { + 'other': "bob" + } + diff --git a/addons/web_tests_demo/static/test/demo.js b/addons/web_tests_demo/static/test/demo.js index 0bf5a1a58b6..62cecf6f088 100644 --- a/addons/web_tests_demo/static/test/demo.js +++ b/addons/web_tests_demo/static/test/demo.js @@ -84,4 +84,19 @@ openerp.testing.section('basic section', function (test) { deepEqual(dbm.db_list, ['foo', 'bar', 'baz']); }); }); + + test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) { + var Model = new instance.web.Model('web_tests_demo.model'); + return Model.call('create', [{name: "Bob"}]) + .pipe(function (id) { + return Model.call('read', [[id]]); + }).pipe(function (records) { + strictEqual(records.length, 1); + var record = records[0]; + strictEqual(record.name, "Bob"); + strictEqual(record.thing, false); + // default value + strictEqual(record.other, 'bob'); + }); + }); }); From 21e776a56b9fedb25c48b1ea362227ed76de6321 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 29 Oct 2012 12:09:02 +0100 Subject: [PATCH 008/188] [IMP] document test runner global conf keys bzr revid: xmo@openerp.com-20121029110902-ob21050di74vcyqc --- addons/web/doc/testing.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 61077072ad2..4760f0780eb 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -409,6 +409,8 @@ To do this, set the :js:attr:`rpc option <~TestOptions.rpc>` to handler containing assertions, it multiplies the effective number of assertions) +.. _testing-rpc-rpc: + Actual RPC ++++++++++ @@ -568,6 +570,19 @@ Testing API should be loaded into QWeb before starting the test. A boolean, ``false`` by default. +The test runner can also use two global configuration values set +directly on the ``window`` object: + +* ``oe_all_dependencies`` is an ``Array`` of all modules with a web + component, ordered by dependency (for a module ``A`` with + dependencies ``A'``, any module of ``A'`` must come before ``A`` in + the array) + +* ``oe_db_info`` is an object with 3 keys ``source``, ``supadmin`` and + ``password``. It is used to pre-configure :ref:`actual RPC + ` tests, to avoid a prompt being displayed + (especially for headless situations). + Running through Python ---------------------- From a9f1489fd0dc32901823fbe09fc323479a444048 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 29 Oct 2012 13:00:04 +0100 Subject: [PATCH 009/188] [FIX] typos bzr revid: xmo@openerp.com-20121029120004-d8tv0hks9d6684az --- addons/web/doc/testing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 4760f0780eb..2d5876776a3 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -199,7 +199,7 @@ testing them. Thus, test cases get a DOM scratchpad as its second positional parameter, in a jQuery instance. That scratchpad is fully cleaned up before each test, and as long as it doesn't do anything outside the -scrartchpad your code can do whatever it wants:: +scratchpad your code can do whatever it wants:: // test/demo.js test('DOM content', function (instance, $scratchpad) { @@ -334,7 +334,7 @@ setting up the test case, provide what the RPC responses "should" be, and only test the code between the "user" (the test itself) and the RPC call, before the call is effectively done. -To do this, set the :js:attr:`rpc option <~TestOptions.rpc>` to +To do this, set the :js:attr:`rpc option ` to ``mock``. This will add a third parameter to the test case callback: .. js:function:: mock(rpc_spec, handler) @@ -349,8 +349,8 @@ To do this, set the :js:attr:`rpc option <~TestOptions.rpc>` to In that case, ``handler`` should be a function taking two arguments ``args`` and ``kwargs``, matching the corresponding - arguments on the server side. Hander should simply return the - value as if it were returned by the Python XMLRPC handler:: + arguments on the server side and should simply return the value + as if it were returned by the Python XMLRPC handler:: test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) { // set up mocking From e7fbd7290f430dd67e9b3f093aea837bdef6f81d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 29 Oct 2012 13:04:26 +0100 Subject: [PATCH 010/188] [IMP] add a doc blurb to testing.section and testing.case bzr revid: xmo@openerp.com-20121029120426-xdk03e5gvv1n03jw --- addons/web/doc/testing.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 2d5876776a3..e870ec091b7 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -497,6 +497,13 @@ Testing API .. js:function:: openerp.testing.section(name[, options], body) + A test section, serves as shared namespace for related tests (for + constants or values to only set up once). The ``body`` function + should contain the tests themselves. + + Note that the order in which tests are run is essentially + undefined, do *not* rely on it. + :param String name: :param TestOptions options: :param body: @@ -504,6 +511,10 @@ Testing API .. js:function:: openerp.testing.case(name[, options], callback) + Registers a test case callback in the test runner, the callback + will only be run once the runner is started (or maybe not at all, + if the test is filtered out). + :param String name: :param TestOptions options: :param callback: From 55ce6a560fb31e86b3a0ae8d21ccaec9e48db3da Mon Sep 17 00:00:00 2001 From: "pankita shah (Open ERP)" Date: Mon, 29 Oct 2012 18:12:26 +0530 Subject: [PATCH 011/188] [FIX] when user select lead and get draft mode bzr revid: shp@tinyerp.com-20121029124226-cjn6s3sj434rm5q7 --- addons/crm/crm_lead.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 9ee5aeb2301..00ee7582c4d 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -50,7 +50,7 @@ class crm_lead(base_stage, format_address, osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ section_id = self._get_default_section_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft'), ('type', '=', 'both')], context=context) + return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft'),'|', ('type', '=', 'lead'),('type', '=', 'both'),], context=context) def _resolve_section_id_from_context(self, cr, uid, context=None): """ Returns ID of section based on the value of 'section_id' @@ -340,7 +340,7 @@ class crm_lead(base_stage, format_address, osv.osv): cases = self.browse(cr, uid, cases, context=context) # collect all section_ids section_ids = [] - types = ['both'] + types = ['lead','opportunity','both'] if section_id: section_ids.append(section_id) for lead in cases: From 084a4217a7022fbf9ecaca6bbfed135798fe856c Mon Sep 17 00:00:00 2001 From: "pankita shah (Open ERP)" Date: Mon, 29 Oct 2012 18:53:13 +0530 Subject: [PATCH 012/188] [FIX] fixed when select type opportunuty then opportunuty in draft mode bzr revid: shp@tinyerp.com-20121029132313-5ctreoq9nv2fxvxc --- addons/crm/crm_lead.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 00ee7582c4d..da0a3f7d756 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -50,7 +50,7 @@ class crm_lead(base_stage, format_address, osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ section_id = self._get_default_section_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft'),'|', ('type', '=', 'lead'),('type', '=', 'both'),], context=context) + return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft'),'|', ('type', '=', 'lead'),'|',('type', '=', 'both'),('type','=','opportunity')], context=context) def _resolve_section_id_from_context(self, cr, uid, context=None): """ Returns ID of section based on the value of 'section_id' From 97208c971b9155cffa57f403109bc92104af9938 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Mon, 29 Oct 2012 18:37:14 +0100 Subject: [PATCH 013/188] [IMP] avoid tabs (4 spaces) in the middle of help text bzr revid: abo@openerp.com-20121029173714-qpr4rrhll576jxmm --- addons/crm/crm_lead.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index da0a3f7d756..0366045b90f 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -224,11 +224,7 @@ class crm_lead(base_stage, format_address, osv.osv): multi='day_close', type="float", store=True), 'state': fields.related('stage_id', 'state', type="selection", store=True, selection=crm.AVAILABLE_STATES, string="Status", readonly=True, - help='The Status is set to \'Draft\', when a case is created.\ - If the case is in progress the Status is set to \'Open\'.\ - When the case is over, the Status is set to \'Done\'.\ - If the case needs to be reviewed then the Status is \ - set to \'Pending\'.'), + help='The Status is set to \'Draft\', when a case is created. If the case is in progress the Status is set to \'Open\'. When the case is over, the Status is set to \'Done\'. If the case needs to be reviewed then the Status is set to \'Pending\'.'), # Only used for type opportunity 'probability': fields.float('Success Rate (%)',group_operator="avg"), From 7a8d6753021ea86f72ab2a7aca374e70620aa03c Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Mon, 29 Oct 2012 19:11:56 +0100 Subject: [PATCH 014/188] [IMP] code style remove mutable default remove useless whitespaces bzr revid: abo@openerp.com-20121029181156-ao52q3uun3ilp2qk --- addons/crm/crm_lead.py | 4 ++- addons/crm/crm_lead_view.xml | 66 ++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 0366045b90f..4074856ad81 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -324,7 +324,7 @@ class crm_lead(base_stage, format_address, osv.osv): cases = self.browse(cr, uid, ids2, context=context) return self._action(cr, uid, cases, False, context=context) - def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None): + def stage_find(self, cr, uid, cases, section_id, domain=None, order='sequence', context=None): """ Override of the base.stage method Parameter of the stage search taken from the lead: - type: stage type must be the same or 'both' @@ -332,6 +332,8 @@ class crm_lead(base_stage, format_address, osv.osv): be a default stage; if not set, stages must be default stages """ + if domain == None: + domain = [] if isinstance(cases, (int, long)): cases = self.browse(cr, uid, cases, context=context) # collect all section_ids diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index b6890a7de07..a05af900bb9 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -14,9 +14,9 @@ action_crm_lead_unread - + action - + crm.lead client_action_multi @@ -32,9 +32,9 @@ action_crm_lead_read - + action - + crm.lead client_action_multi @@ -143,7 +143,7 @@
- @@ -253,12 +253,12 @@ - + - + @@ -276,8 +276,8 @@ - - + + @@ -354,14 +354,14 @@ - + - + - - + + @@ -415,7 +415,7 @@ name="action_makeMeeting" type="object" context="{'search_default_attendee_id': active_id, 'default_attendee_id' : active_id}" - /> + />
-