Spaces:
Running
Running
import sys | |
import unittest | |
import pythoncom | |
import win32com.server.policy | |
import win32com.test.util | |
from win32com.axscript import axscript | |
from win32com.axscript.server import axsite | |
from win32com.axscript.server.error import Exception | |
from win32com.client.dynamic import Dispatch | |
from win32com.server import connect, util | |
from win32com.server.exception import COMException | |
verbose = "-v" in sys.argv | |
class MySite(axsite.AXSite): | |
def __init__(self, *args): | |
self.exception_seen = None | |
axsite.AXSite.__init__(self, *args) | |
def OnScriptError(self, error): | |
self.exception_seen = exc = error.GetExceptionInfo() | |
context, line, char = error.GetSourcePosition() | |
if not verbose: | |
return | |
print(" >Exception:", exc[1]) | |
try: | |
st = error.GetSourceLineText() | |
except pythoncom.com_error: | |
st = None | |
if st is None: | |
st = "" | |
text = st + "\n" + (" " * (char - 1)) + "^" + "\n" + exc[2] | |
for line in text.splitlines(): | |
print(" >" + line) | |
class MyCollection(util.Collection): | |
def _NewEnum(self): | |
return util.Collection._NewEnum(self) | |
class Test: | |
_public_methods_ = ["echo", "fail"] | |
_public_attrs_ = ["collection"] | |
def __init__(self): | |
self.verbose = verbose | |
self.collection = util.wrap(MyCollection([1, "Two", 3])) | |
self.last = "" | |
self.fail_called = 0 | |
# self._connect_server_ = TestConnectServer(self) | |
def echo(self, *args): | |
self.last = "".join([str(s) for s in args]) | |
if self.verbose: | |
for arg in args: | |
print(arg, end=" ") | |
print() | |
def fail(self, *args): | |
print("**** fail() called ***") | |
for arg in args: | |
print(arg, end=" ") | |
print() | |
self.fail_called = 1 | |
# self._connect_server_.Broadcast(last) | |
#### Connections currently wont work, as there is no way for the engine to | |
#### know what events we support. We need typeinfo support. | |
IID_ITestEvents = pythoncom.MakeIID("{8EB72F90-0D44-11d1-9C4B-00AA00125A98}") | |
class TestConnectServer(connect.ConnectableServer): | |
_connect_interfaces_ = [IID_ITestEvents] | |
# The single public method that the client can call on us | |
# (ie, as a normal COM server, this exposes just this single method. | |
def __init__(self, object): | |
self.object = object | |
def Broadcast(self, arg): | |
# Simply broadcast a notification. | |
self._BroadcastNotify(self.NotifyDoneIt, (arg,)) | |
def NotifyDoneIt(self, interface, arg): | |
interface.Invoke(1000, 0, pythoncom.DISPATCH_METHOD, 1, arg) | |
VBScript = """\ | |
prop = "Property Value" | |
sub hello(arg1) | |
test.echo arg1 | |
end sub | |
sub testcollection | |
if test.collection.Item(0) <> 1 then | |
test.fail("Index 0 was wrong") | |
end if | |
if test.collection.Item(1) <> "Two" then | |
test.fail("Index 1 was wrong") | |
end if | |
if test.collection.Item(2) <> 3 then | |
test.fail("Index 2 was wrong") | |
end if | |
num = 0 | |
for each item in test.collection | |
num = num + 1 | |
next | |
if num <> 3 then | |
test.fail("Collection didn't have 3 items") | |
end if | |
end sub | |
""" | |
PyScript = """\ | |
# A unicode \xa9omment. | |
prop = "Property Value" | |
def hello(arg1): | |
test.echo(arg1) | |
def testcollection(): | |
# test.collection[1] = "New one" | |
got = [] | |
for item in test.collection: | |
got.append(item) | |
if got != [1, "Two", 3]: | |
test.fail("Didn't get the collection") | |
pass | |
""" | |
# XXX - needs py3k work! Throwing a bytes string with an extended char | |
# doesn't make much sense, but py2x allows it. What it gets upset with | |
# is a real unicode arg - which is the only thing py3k allows! | |
PyScript_Exc = """\ | |
def hello(arg1): | |
raise RuntimeError("exc with extended \xa9har") | |
""" | |
ErrScript = """\ | |
bad code for everyone! | |
""" | |
state_map = { | |
axscript.SCRIPTSTATE_UNINITIALIZED: "SCRIPTSTATE_UNINITIALIZED", | |
axscript.SCRIPTSTATE_INITIALIZED: "SCRIPTSTATE_INITIALIZED", | |
axscript.SCRIPTSTATE_STARTED: "SCRIPTSTATE_STARTED", | |
axscript.SCRIPTSTATE_CONNECTED: "SCRIPTSTATE_CONNECTED", | |
axscript.SCRIPTSTATE_DISCONNECTED: "SCRIPTSTATE_DISCONNECTED", | |
axscript.SCRIPTSTATE_CLOSED: "SCRIPTSTATE_CLOSED", | |
} | |
def _CheckEngineState(engine, name, state): | |
got = engine.engine.eScript.GetScriptState() | |
if got != state: | |
got_name = state_map.get(got, str(got)) | |
state_name = state_map.get(state, str(state)) | |
raise RuntimeError( | |
"Warning - engine %s has state %s, but expected %s" | |
% (name, got_name, state_name) | |
) | |
class EngineTester(win32com.test.util.TestCase): | |
def _TestEngine(self, engineName, code, expected_exc=None): | |
echoer = Test() | |
model = { | |
"test": util.wrap(echoer), | |
} | |
site = MySite(model) | |
engine = site._AddEngine(engineName) | |
try: | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_INITIALIZED) | |
engine.AddCode(code) | |
engine.Start() | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_STARTED) | |
self.assertTrue(not echoer.fail_called, "Fail should not have been called") | |
# Now call into the scripts IDispatch | |
ob = Dispatch(engine.GetScriptDispatch()) | |
try: | |
ob.hello("Goober") | |
self.assertTrue( | |
expected_exc is None, | |
"Expected %r, but no exception seen" % (expected_exc,), | |
) | |
except pythoncom.com_error: | |
if expected_exc is None: | |
self.fail( | |
"Unexpected failure from script code: %s" | |
% (site.exception_seen,) | |
) | |
if expected_exc not in site.exception_seen[2]: | |
self.fail( | |
"Could not find %r in %r" | |
% (expected_exc, site.exception_seen[2]) | |
) | |
return | |
self.assertEqual(echoer.last, "Goober") | |
self.assertEqual(str(ob.prop), "Property Value") | |
ob.testcollection() | |
self.assertTrue(not echoer.fail_called, "Fail should not have been called") | |
# Now make sure my engines can evaluate stuff. | |
result = engine.eParse.ParseScriptText( | |
"1+1", None, None, None, 0, 0, axscript.SCRIPTTEXT_ISEXPRESSION | |
) | |
self.assertEqual(result, 2) | |
# re-initialize to make sure it transitions back to initialized again. | |
engine.SetScriptState(axscript.SCRIPTSTATE_INITIALIZED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_INITIALIZED) | |
engine.Start() | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_STARTED) | |
# Transition back to initialized, then through connected too. | |
engine.SetScriptState(axscript.SCRIPTSTATE_INITIALIZED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_INITIALIZED) | |
engine.SetScriptState(axscript.SCRIPTSTATE_CONNECTED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_CONNECTED) | |
engine.SetScriptState(axscript.SCRIPTSTATE_INITIALIZED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_INITIALIZED) | |
engine.SetScriptState(axscript.SCRIPTSTATE_CONNECTED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_CONNECTED) | |
engine.SetScriptState(axscript.SCRIPTSTATE_DISCONNECTED) | |
_CheckEngineState(site, engineName, axscript.SCRIPTSTATE_DISCONNECTED) | |
finally: | |
engine.Close() | |
engine = None | |
site = None | |
def testVB(self): | |
self._TestEngine("VBScript", VBScript) | |
def testPython(self): | |
self._TestEngine("Python", PyScript) | |
def testPythonUnicodeError(self): | |
self._TestEngine("Python", PyScript) | |
def testVBExceptions(self): | |
self.assertRaises(pythoncom.com_error, self._TestEngine, "VBScript", ErrScript) | |
def testPythonExceptions(self): | |
expected = "RuntimeError: exc with extended \xa9har" | |
self._TestEngine("Python", PyScript_Exc, expected) | |
if __name__ == "__main__": | |
unittest.main() | |