CampBuddy/Camp.Buddy v2.2.1/Camp_Buddy-2.2.1-pc/renpy/test/testast.py
2025-03-03 23:00:33 +01:00

565 lines
13 KiB
Python

# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
import renpy.display
import renpy.test
from renpy.test.testmouse import click_mouse, move_mouse
# This is an object that is used to configure test settings.
_test = renpy.object.Object()
# Should we use maximum framerate mode?
_test.maximum_framerate = True
# How long should we wait before declaring the test stuck?
_test.timeout = 5.0
# Should we force the test to proceed despite suppress_underlay?
_test.force = False
# How long should we wait for a transition before we proceed?
_test.transition_timeout = 5.0
class Node(object):
"""
An AST node for a test script.
"""
def __init__(self, loc):
self.filename, self.linenumber = loc
def start(self):
"""
Called once when the node starts execution.
This is expected to return a state, or None to advance to the next
node.
"""
def execute(self, state, t):
"""
Called once each time the screen is drawn.
`state`
The last state that was returned from this node.
`t`
The time since start was called.
"""
return state
def ready(self):
"""
Returns True if this node is ready to execute, or False otherwise.
"""
return True
def report(self):
"""
Reports the location of this statement. This should only be called
in the execute method of leaf nodes of the test tree.
"""
renpy.test.testexecution.node_loc = (self.filename, self.linenumber)
class Pattern(Node):
position = None
always = False
def __init__(self, loc, pattern=None):
Node.__init__(self, loc)
self.pattern = pattern
def start(self):
return True
def execute(self, state, t):
self.report()
if renpy.display.interface.trans_pause and (t < _test.transition_timeout):
return state
if self.position is not None:
position = renpy.python.py_eval(self.position)
else:
position = (None, None)
f = renpy.test.testfocus.find_focus(self.pattern)
if f is None:
x, y = None, None
else:
x, y = renpy.test.testfocus.find_position(f, position)
if x is None:
if self.pattern:
return state
else:
x, y = renpy.exports.get_mouse_pos()
return self.perform(x, y, state, t)
def ready(self):
if self.always:
return True
f = renpy.test.testfocus.find_focus(self.pattern)
if f is not None:
return True
else:
return False
class Click(Pattern):
# The number of the button to click.
button = 1
def perform(self, x, y, state, t):
click_mouse(self.button, x, y)
return None
class Move(Pattern):
def perform(self, x, y, state, t):
move_mouse(x, y)
return None
class Scroll(Node):
def __init__(self, loc, pattern=None):
Node.__init__(self, loc)
self.pattern = pattern
def start(self):
return True
def execute(self, state, t):
self.report()
f = renpy.test.testfocus.find_focus(self.pattern)
if f is None:
return True
if not isinstance(f.widget, renpy.display.behavior.Bar):
return True
adj = f.widget.adjustment
if adj.value == adj.range:
new = 0
else:
new = adj.value + adj.page
if new > adj.range:
new = adj.range
adj.change(new)
return None
def ready(self):
f = renpy.test.testfocus.find_focus(self.pattern)
if f is not None:
return True
else:
return False
class Drag(Node):
def __init__(self, loc, points):
Node.__init__(self, loc)
self.points = points
self.pattern = None
self.button = 1
self.steps = 10
def start(self):
return True
def execute(self, state, t):
self.report()
if renpy.display.interface.trans_pause:
return state
if self.pattern:
f = renpy.test.testfocus.find_focus(self.pattern)
if f is None:
return state
else:
f = None
if state is True:
points = renpy.python.py_eval(self.points)
points = [ renpy.test.testfocus.find_position(f, i) for i in points ]
if len(points) < 2:
raise Exception("A drag requires at least two points.")
interpoints = [ ]
xa, ya = points[0]
interpoints.append((xa, ya))
for xb, yb in points[1:]:
for i in range(1, self.steps + 1):
done = 1.0 * i / self.steps
interpoints.append((
int(xa + done * (xb - xa)),
int(ya + done * (yb - ya)),
))
xa = xb
ya = yb
x, y = interpoints.pop(0)
renpy.test.testmouse.move_mouse(x, y)
renpy.test.testmouse.press_mouse(self.button)
else:
interpoints = state
x, y = interpoints.pop(0)
renpy.test.testmouse.move_mouse(x, y)
if not interpoints:
renpy.test.testmouse.release_mouse(self.button)
return None
else:
return interpoints
def ready(self):
if self.pattern is None:
return True
f = renpy.test.testfocus.find_focus(self.pattern)
if f is not None:
return True
else:
return False
class Type(Pattern):
interval = .01
def __init__(self, loc, keys):
Pattern.__init__(self, loc)
self.keys = keys
def start(self):
return 0
def perform(self, x, y, state, t):
if state >= len(self.keys):
return None
move_mouse(x, y)
keysym = self.keys[state]
renpy.test.testkey.down(self, keysym)
renpy.test.testkey.up(self, keysym)
return state + 1
class Action(Node):
def __init__(self, loc, expr):
Node.__init__(self, loc)
self.expr = expr
def start(self):
renpy.test.testexecution.action = renpy.python.py_eval(self.expr)
return True
def execute(self, state, t):
self.report()
if renpy.test.testexecution.action:
return True
else:
return None
def ready(self):
self.report()
action = renpy.python.py_eval(self.expr)
return renpy.display.behavior.is_sensitive(action)
class Pause(Node):
def __init__(self, loc, expr):
Node.__init__(self, loc)
self.expr = expr
def start(self):
return float(renpy.python.py_eval(self.expr))
def execute(self, state, t):
self.report()
if t < state:
return state
else:
return None
class Label(Node):
def __init__(self, loc, name):
Node.__init__(self, loc)
self.name = name
def start(self):
return True
def execute(self, state, t):
if self.name in renpy.test.testexecution.labels:
return None
else:
return state
def ready(self):
return self.name in renpy.test.testexecution.labels
################################################################################
# Non-clause statements.
class Until(Node):
"""
Executes `left` repeatedly until `right` is ready, then executes `right`
once before quitting.
"""
def __init__(self, loc, left, right):
Node.__init__(self, loc)
self.left = left
self.right = right
def start(self):
return (None, None, 0)
def execute(self, state, t):
child, child_state, start = state
if self.right.ready() and not (child is self.right):
child = self.right
child_state = None
elif child is None:
child = self.left
if child_state is None:
child_state = child.start()
start = t
if child_state is not None:
child_state = child.execute(child_state, t - start)
if (child_state is None) and (child is self.right):
return None
return child, child_state, start
def ready(self):
return self.left.ready() or self.right.ready()
class If(Node):
"""
If `condition` is ready, runs the block. Otherwise, goes to the next
statement.
"""
def __init__(self, loc, condition, block):
Node.__init__(self, loc)
self.condition = condition
self.block = block
def start(self):
return (None, None, 0)
def execute(self, state, t):
node, child_state, start = state
if node is None:
if not self.condition.ready():
return None
node = self.block
node, child_state, start = renpy.test.testexecution.execute_node(t, node, child_state, start)
if node is None:
return None
return (node, child_state, start)
class Python(Node):
def __init__(self, loc, code):
Node.__init__(self, loc)
self.code = code
def start(self):
renpy.test.testexecution.action = self
return True
def execute(self, state, t):
self.report()
if renpy.test.testexecution.action:
return True
else:
return None
def __call__(self):
renpy.python.py_exec_bytecode(self.code.bytecode)
class Assert(Node):
def __init__(self, loc, expr):
Node.__init__(self, loc)
self.expr = expr
def start(self):
renpy.test.testexecution.action = self
return True
def execute(self, state, t):
self.report()
if renpy.test.testexecution.action:
return True
else:
return None
def __call__(self):
if not renpy.python.py_eval(self.expr):
raise Exception("On line {}:{}, assertion {} failed.".format(self.filename, self.linenumber, self.expr))
class Jump(Node):
def __init__(self, loc, target):
Node.__init__(self, loc)
self.target = target
def start(self):
node = renpy.test.testexecution.lookup(self.target, self)
raise renpy.test.testexecution.TestJump(node)
class Call(Node):
def __init__(self, loc, target):
Node.__init__(self, loc)
self.target = target
def start(self):
print("Call test", self.target)
node = renpy.test.testexecution.lookup(self.target, self)
return (node, None, 0)
def execute(self, state, t):
node, child_state, start = state
node, child_state, start = renpy.test.testexecution.execute_node(t, node, child_state, start)
if node is None:
return None
return (node, child_state, start)
################################################################################
# Control structures.
class Block(Node):
def __init__(self, loc, block):
Node.__init__(self, loc)
self.block = block
def start(self):
return (0, None, None)
def execute(self, state, t):
i, start, s = state
if i >= len(self.block):
return None
if s is None:
s = self.block[i].start()
start = t
if s is not None:
s = self.block[i].execute(s, t - start)
if s is None:
i += 1
return i, start, s