Commit 11186505 authored by Evan Simpson's avatar Evan Simpson

Merge changes and unit tests from evan-script_fix-branch

parent bc460480
......@@ -89,7 +89,7 @@ This product provides support for Script objects containing restricted
Python code.
"""
__version__='$Revision: 1.23 $'[11:-2]
__version__='$Revision: 1.24 $'[11:-2]
import sys, os, traceback, re
from Globals import DTMLFile, MessageDialog
......@@ -145,10 +145,16 @@ class PythonScript(Script, Historical, Cacheable):
_params = _body = ''
manage_options = (
{'label':'Edit', 'action':'ZPythonScriptHTML_editForm'},
{'label':'Edit',
'action':'ZPythonScriptHTML_editForm',
'help': ('PythonScripts', 'PythonScript_edit.stx')},
) + BindingsUI.manage_options + (
{'label':'Test', 'action':'ZScriptHTML_tryForm'},
{'label':'Proxy', 'action':'manage_proxyForm'},
{'label':'Test',
'action':'ZScriptHTML_tryForm',
'help': ('PythonScripts', 'PythonScript_test.stx')},
{'label':'Proxy',
'action':'manage_proxyForm',
'help': ('OFSP','DTML-DocumentOrMethod_Proxy.stx')},
) + Historical.manage_options + SimpleItem.manage_options + \
Cacheable.manage_options
......
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
import sys
try:
sys.path.insert(0, '.')
import ZODB
except:
sys.path.insert(0, '../../..')
import ZODB
from Products.PythonScripts.PythonScript import PythonScript
from AccessControl.SecurityManagement import newSecurityManager
newSecurityManager(None, None)
from unittest import TestCase, TestSuite, VerboseTextTestRunner, makeSuite
TextTestRunner = VerboseTextTestRunner
# Test Classes
def readf(name):
return open('tscripts/%s%s' % (name, '.ps'), 'r').read()
class TestPythonScriptNoAq(TestCase):
def _newPS(self, txt):
ps = PythonScript('ps')
ps.ZBindings_edit({})
ps.write(txt)
ps._makeFunction(1)
return ps
def testEmpty(self):
empty = self._newPS('')()
assert empty is None, empty
def testReturn(self):
return1 = self._newPS('return 1')()
assert return1 == 1, return1
def testReturnNone(self):
none = self._newPS('return')()
assert none == None
def testParam1(self):
txt = self._newPS('##parameters=x\nreturn x')('txt')
assert txt == 'txt', txt
def testParam2(self):
one, two = self._newPS('##parameters=x,y\nreturn x,y')('one','two')
assert one == 'one'
assert two == 'two'
def testParam26(self):
import string
params = string.letters[:26]
sparams = string.join(params, ',')
tup = apply(self._newPS('##parameters=%s\nreturn %s'
% (sparams,sparams)), params)
assert tup == tuple(params), (tup, params)
def testArithmetic(self):
one = self._newPS('return 1 * 5 + 4 / 2 - 6')()
assert one == 1, one
def testImport(self):
a,b,c = self._newPS('import string; return string.split("a b c")')()
assert a == 'a'
assert b == 'b'
assert c == 'c'
def testWhileLoop(self):
one = self._newPS(readf('while_loop'))()
assert one == 1
def testForLoop(self):
ten = self._newPS(readf('for_loop'))()
assert ten == 10
def testMutateLiterals(self):
l, d = self._newPS(readf('mutate_literals'))()
assert l == [2], l
assert d == {'b': 2}
def testTupleUnpackAssignment(self):
d, x = self._newPS(readf('tuple_unpack_assignment'))()
assert d == {'a': 0, 'b': 1, 'c': 2}, d
assert x == 3, x
def testDoubleNegation(self):
one = self._newPS('return not not "this"')()
assert one == 1
def testTryExcept(self):
a,b = self._newPS(readf('try_except'))()
assert a==1
assert b==1
def testBigBoolean(self):
true = self._newPS(readf('big_boolean'))()
assert true, true
def testFibonacci(self):
r = self._newPS(readf('fibonacci'))()
assert r == [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377,
610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418, 317811, 514229, 832040,
1346269, 2178309, 3524578, 5702887, 9227465, 14930352,
24157817, 39088169, 63245986], r
test_classes = (TestPythonScriptNoAq,)
# unit test machinery
def test_suite():
ts = []
for tclass in test_classes:
ts.append(makeSuite(tclass, 'test'))
return TestSuite(tuple(ts))
def main():
alltests=test_suite()
runner = TextTestRunner()
runner.run(alltests)
def debug():
test_suite().debug()
if __name__=='__main__':
if len(sys.argv) > 1:
globals()[sys.argv[1]]()
else:
main()
mab = {'a': 1, 'b': 2}
r10 = range(10)
return r10[3:5][1] == 4 and r10[mab['b']] and 1 < mab['ab'[r10[1]]] < 3
l = []
a, b = 0, 1
while b < 100000000:
l.append(b)
a, b = b, a+b
return l
a = 0
for x in range(10):
a = a + 1
return a
l1 = [1, 2, 3]
l2 = [l1[0], l1[1]]
l2.extend(l1)
l2.append(4)
del l2[:2]
del l2[0]
l2[-2:] = []
d = {'a': 1, 'b': l2[0]}
d['a'] = 0
del d['a']
return l2, d
d = {}
(d['a'], d['b'], d['c'], x) = range(4)
return d, x
......@@ -110,15 +110,18 @@ class Munge_window:
if not stack:
self.last_empty_stack = op
def after_code_for(self, stack_idx):
def after_code_for(self, stack_idx, separt=1):
stack = self.stack
if stack_idx < 0 and len(stack) + stack_idx < 0:
whichop = self.last_empty_stack
if whichop is None:
return 0
else:
whichop = stack[stack_idx]
return self.code.index(whichop)+1
whichop = stack[stack_idx][separt]
return self.code.index(whichop) + separt
def before_code_for(self, stack_idx):
return self.after_code_for(stack_idx, separt=0)
def assert_stack_size(self, size, ctxt):
if self.use_stack and len(self.stack) != size:
......@@ -287,7 +290,7 @@ class Printing:
def PRINT_ITEM(self, w):
# Load the printing function before the code for the operand.
w.insert_code(self.print_prep, w.after_code_for(-2))
w.insert_code(self.print_prep, w.before_code_for(-1))
w.assert_stack_size(1, "at a 'print' statement")
# Instead of printing, call our function and discard the result.
w.set_code(1, self.call_print2)
......@@ -357,16 +360,17 @@ class AllowMapBuild:
def __init__(self, cb, w, fc):
pass
def STORE_SUBSCR(self, w):
if isinstance(w.stack[-2], ops.BUILD_MAP):
if (isinstance(w.stack[-2][0], ops.DUP_TOP) and
isinstance(w.stack[-4][0], ops.BUILD_MAP)):
w.do_op()
return 1
def _get_call(w):
load_guard = ((ops.LOAD_FAST, ops.LOAD_ATTR), (('$guard',), (guard,)))
# Load the binary guard function before its parameters are computed.
iops = w.insert_code(load_guard, w.after_code_for(-3))
iops = w.insert_code(load_guard, w.before_code_for(-2))
# Fix the execution stack to refer to the loaded function.
if w.use_stack: w.stack[-2:-2] = iops[1:]
if w.use_stack: w.stack[-2:-2] = [(iops[0], iops[1])]
# Call guard function instead of performing binary op
w.set_code(1, cf2)
return 1
......@@ -413,13 +417,13 @@ def GuardedBinaryOps(guards):
def _wrap(w):
load_guard = ((ops.LOAD_FAST,), ((guard,),))
# Load the guard function before the guarded object, call after.
w.insert_code(load_guard, w.after_code_for(spos - 1))
w.insert_code(load_guard, w.before_code_for(spos))
if spos == 0:
w.set_code(0, cf1)
else:
iops = w.insert_code(cf1, w.after_code_for(spos))
# Fix the execution stack.
if w.use_stack: w.stack[spos] = iops[0]
if w.use_stack: w.stack[spos] = (w.stack[spos][0], iops[0])
def _WriteGuardWrapper():
def model_handler(self, *args):
......
......@@ -2,7 +2,8 @@ import struct,dis,new
from label import Label
class ByteCode:
pass
def consume(self, stack, n):
stack[-n:]=[(stack[-n][0], self)]
class GenericOneByteCode(ByteCode):
def __init__(self,cs,code):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment