ported the documentation for the framework's test library -- also extended srcdoc.ss a little bit
svn: r9499
This commit is contained in:
parent
6ffcad639c
commit
6a53f96e06
|
@ -821,84 +821,10 @@
|
|||
(define test:mouse-click mouse-click)
|
||||
(define test:new-window new-window)
|
||||
|
||||
#;
|
||||
(provide/doc
|
||||
(proc-doc
|
||||
test:number-pending-actions
|
||||
(-> number?)
|
||||
@{Returns the number of pending events (those that haven't completed yet)}))
|
||||
|
||||
(provide/contract/docs
|
||||
(test:number-pending-actions
|
||||
(-> number?)
|
||||
()
|
||||
"Returns the number of pending events (those that haven't completed yet)")
|
||||
|
||||
(test:run-interval
|
||||
(case->
|
||||
(number? . -> . void?)
|
||||
(-> number?))
|
||||
((msec) ())
|
||||
"See also"
|
||||
"\\hyperref{Actions and completeness}{Actions and completeness, section~}{}{fw:actions-completeness}."
|
||||
"The first case in the case-lambda sets"
|
||||
"the run interval to \\var{msec} milliseconds and the second"
|
||||
"returns the current setting.")
|
||||
|
||||
(test:reraise-error
|
||||
(-> void?)
|
||||
()
|
||||
"See also"
|
||||
"\\hyperref{Errors}{Errors, section~}{}{fw:test:errors}.")
|
||||
|
||||
(test:run-one
|
||||
((-> void?) . -> . void?)
|
||||
(f)
|
||||
"Runs the function \\var{f} as if it was a simulated event. See also"
|
||||
"\\hyperref{the test section}{section ~}{}{fw:test}.")
|
||||
|
||||
(test:current-get-eventspaces
|
||||
(case->
|
||||
((-> (listof eventspace?)) . -> . void?)
|
||||
(-> (-> (listof eventspace?))))
|
||||
((func) ())
|
||||
|
||||
"This parameter that specifies which "
|
||||
"\\hyperref{eventspaces}{eventspace (see section~}{)}{eventspaceinfo}"
|
||||
"are considered when finding the frontmost frame."
|
||||
|
||||
"The first case"
|
||||
"sets the parameter to \\var{func}. The procedure \\var{func} will be"
|
||||
"invoked with no arguments to determine the eventspaces to consider"
|
||||
"when finding the frontmost frame for simulated user events."
|
||||
|
||||
"The second case"
|
||||
"returns the current value of the parameter. This will be a procedure"
|
||||
"which, when invoked, returns a list of eventspaces.")
|
||||
(test:close-top-level-window
|
||||
((is-a?/c top-level-window<%>) . -> . void?)
|
||||
(tlw)
|
||||
"Use this function to simulate clicking on the close box of a frame."
|
||||
"Closes \\var{tlw} with this expression:"
|
||||
""
|
||||
"\\begin{schemedisplay}"
|
||||
"(when (send tlw can-close?)"
|
||||
" (send tlw on-close)"
|
||||
" (send tlw show #f))"
|
||||
"\\end{schemedisplay}")
|
||||
|
||||
(test:top-level-focus-window-has?
|
||||
(((is-a?/c area<%>) . -> . boolean?) . -> . boolean?)
|
||||
(test)
|
||||
"Calls \\var{test} for each child of the top-level-focus-frame"
|
||||
"and returns \\scheme|#t| if \\var{test} ever does, otherwise"
|
||||
"returns \\scheme|#f|. If there"
|
||||
"is no top-level-focus-window, returns \\scheme|#f|.")
|
||||
|
||||
;; ((frame-has? p) f) =
|
||||
;; f is a frame and it has a child (in it or a subpanel) that responds #t to p
|
||||
(test:button-push
|
||||
((or/c (λ (str)
|
||||
(proc-doc/names
|
||||
test:button-push
|
||||
(-> (or/c (λ (str)
|
||||
(and (string? str)
|
||||
(test:top-level-focus-window-has?
|
||||
(λ (c)
|
||||
|
@ -914,94 +840,102 @@
|
|||
(λ (btn)
|
||||
(test:top-level-focus-window-has?
|
||||
(λ (c) (eq? c btn))))))
|
||||
. -> .
|
||||
void?)
|
||||
(button)
|
||||
"Simulates pushing \\var{button}. If a string is supplied, the"
|
||||
"primitive searches for a button labelled with that string in the"
|
||||
"active frame. Otherwise, it pushes the button argument.")
|
||||
@{Simulates pushing @scheme[button]. If a string is supplied, the
|
||||
primitive searches for a button labelled with that string in the
|
||||
active frame. Otherwise, it pushes the button argument.})
|
||||
|
||||
(test:set-radio-box!
|
||||
((or/c string? (is-a?/c radio-box%)) (or/c string? number?) . -> . void?)
|
||||
(proc-doc/names
|
||||
test:set-radio-box!
|
||||
(-> (or/c string? (is-a?/c radio-box%)) (or/c string? number?) void?)
|
||||
(radio-box state)
|
||||
"Sets the radio-box to \\var{state}. If \\var{state} is a"
|
||||
"string, this function finds the choice with that label and"
|
||||
"if it is a number, it uses the number as an index into the"
|
||||
"state. If the number is out of range or if the label isn't"
|
||||
"in the radio box, an exception is raised."
|
||||
""
|
||||
"If \\var{radio-box} is a string, this function searches for a"
|
||||
"\\iscmclass{radio-box} with a label matching that string,"
|
||||
"otherwise it uses \\var{radio-box} itself.")
|
||||
@{Sets the radio-box to @scheme[state]. If @scheme[state] is a
|
||||
string, this function finds the choice with that label and
|
||||
if it is a number, it uses the number as an index into the
|
||||
state. If the number is out of range or if the label isn't
|
||||
in the radio box, an exception is raised.
|
||||
|
||||
(test:set-radio-box-item!
|
||||
(string? . -> . void?)
|
||||
If @scheme[radio-box] is a string, this function searches for a
|
||||
@scheme[radio-box%] object with a label matching that string,
|
||||
otherwise it uses @scheme[radio-box] itself.})
|
||||
|
||||
(proc-doc/names
|
||||
test:set-radio-box-item!
|
||||
(-> string? void?)
|
||||
(entry)
|
||||
"Finds a \\iscmclass{radio-box} that has a label \\var{entry}"
|
||||
"and sets the radio-box to \\var{entry}.")
|
||||
(test:set-check-box!
|
||||
((or/c string? (is-a?/c check-box%)) boolean? . -> . void?)
|
||||
@{Finds a @scheme[radio-box%] that has a label @scheme[entry]
|
||||
and sets the radio-box to @scheme[entry].})
|
||||
|
||||
(proc-doc/names
|
||||
test:set-check-box!
|
||||
(-> (or/c string? (is-a?/c check-box%)) boolean? void?)
|
||||
(check-box state)
|
||||
"Clears the \\iscmclass{check-box} item if \\var{state} is \\rawscm{\\#f}, and sets it"
|
||||
"otherwise."
|
||||
""
|
||||
"If \\var{check-box} is a string,"
|
||||
"this function searches for a \\iscmclass{check-box} with a label matching that string,"
|
||||
"otherwise it uses \\var{check-box} itself.")
|
||||
@{Clears the @scheme[check-box%] item if @scheme[state] is @scheme[#f], and sets it
|
||||
otherwise.
|
||||
|
||||
(test:set-choice!
|
||||
((or/c string? (is-a?/c choice%)) (or/c string? (and/c number? exact? integer? positive?)) . -> . void?)
|
||||
If @scheme[check-box] is a string,
|
||||
this function searches for a @scheme[check-box%] with a label matching that string,
|
||||
otherwise it uses @scheme[check-box] itself.})
|
||||
|
||||
(proc-doc/names
|
||||
test:set-choice!
|
||||
(-> (or/c string? (is-a?/c choice%)) (or/c string? (and/c number? exact? integer? positive?))
|
||||
void?)
|
||||
(choice str)
|
||||
"Selects \\var{choice}'s item \\var{str}. If \\var{choice} is a string,"
|
||||
"this function searches for a \\iscmclass{choice} with a label matching"
|
||||
"that string, otherwise it uses \\var{choice} itself.")
|
||||
@{Selects @scheme[choice]'s item @scheme[str]. If @scheme[choice] is a string,
|
||||
this function searches for a @scheme[choice%] with a label matching
|
||||
that string, otherwise it uses @scheme[choice] itself.})
|
||||
|
||||
(test:set-list-box!
|
||||
((or/c string? (is-a?/c list-box%)) (or/c string? (and/c number? exact? integer? positive?)) . -> . void?)
|
||||
(proc-doc/names
|
||||
test:set-list-box!
|
||||
(-> (or/c string? (is-a?/c list-box%)) (or/c string? (and/c number? exact? integer? positive?))
|
||||
void?)
|
||||
(choice str)
|
||||
"Selects \\var{list-box}'s item \\var{str}. If \\var{list-box} is a string,"
|
||||
"this function searches for a \\iscmclass{list-box} with a label matching"
|
||||
"that string, otherwise it uses \\var{list-box} itself.")
|
||||
@{Selects @scheme[list-box]'s item @scheme[str]. If @scheme[list-box] is a string,
|
||||
this function searches for a @scheme[list-box%] with a label matching
|
||||
that string, otherwise it uses @scheme[list-box] itself.})
|
||||
|
||||
(test:keystroke
|
||||
(proc-doc/names
|
||||
test:keystroke
|
||||
(->* ((or/c char? symbol?))
|
||||
((listof (symbols 'alt 'control 'meta 'shift 'noalt 'nocontrol 'nometea 'noshift)))
|
||||
void?)
|
||||
((key)
|
||||
((modifier-list null)))
|
||||
"This function simulates a user pressing a key. The argument, \\var{key},"
|
||||
"is just like the argument to the"
|
||||
"@link key-event get-key-code"
|
||||
"method of the"
|
||||
"@link key-event"
|
||||
"class. "
|
||||
""
|
||||
"{\\it Note:}"
|
||||
"To send the ``Enter'' key, use \\verb|#\return|,"
|
||||
"not \\verb|#\newline|."
|
||||
""
|
||||
"The \\rawscm{'shift} or \\rawscm{'noshift} modifier is implicitly set from \\var{key},"
|
||||
"but is overridden by the argument list. The \\rawscm{'shift} modifier is"
|
||||
"set for any capitol alpha-numeric letters and any of the following characters:"
|
||||
"\\begin{schemedisplay}"
|
||||
"#\\? #\\: #\\~ #\\\\ #\\|"
|
||||
"#\\< #\\> #\\{ #\\} #\\[ #\\] #\\( #\\)"
|
||||
"#\\! #\\@ #\\# #\\$ #\\% #\\^ #\\& #\\* #\\_ #\\+"
|
||||
"\\end{schemedisplay}"
|
||||
""
|
||||
"If conflicting modifiers are provided, the ones later in the list are used.")
|
||||
@{This function simulates a user pressing a key. The argument, @scheme[key],
|
||||
is just like the argument to the
|
||||
@method[key-event% get-key-code]
|
||||
method of the @scheme[key-event%] class.
|
||||
|
||||
(test:menu-select
|
||||
@italic{Note:}
|
||||
To send the ``Enter'' key, use @scheme[#\return],
|
||||
not @scheme[#\newline].
|
||||
|
||||
The @scheme['shift] or @scheme['noshift] modifier is implicitly set from @scheme[key],
|
||||
but is overridden by the argument list. The @scheme['shift] modifier is
|
||||
set for any capitol alpha-numeric letters and any of the following characters:
|
||||
@schemeblock[
|
||||
#\? #\: #\~ #\\ #\|
|
||||
#\< #\> #\{ #\} #\[ #\] #\( #\)
|
||||
#\! #\@ #\# #\$ #\% #\^ #\& #\* #\_ #\+
|
||||
]
|
||||
|
||||
If conflicting modifiers are provided, the ones later in the list are used.})
|
||||
|
||||
(proc-doc/names
|
||||
test:menu-select
|
||||
(string? string? . -> . void?)
|
||||
(menu item)
|
||||
"Selects the menu-item named \\var{item} in the menu named \\var{menu}."
|
||||
""
|
||||
"{\\it Note:}"
|
||||
"The string for the menu item does not include its keyboard equivalent."
|
||||
"For example, to select ``New'' from the ``File'' menu, "
|
||||
"use ``New'', not ``New Ctrl+m n''.")
|
||||
@{Selects the menu-item named @scheme[item] in the menu named @scheme[menu].
|
||||
|
||||
(test:mouse-click
|
||||
@italic{Note:}
|
||||
The string for the menu item does not include its keyboard equivalent.
|
||||
For example, to select ``New'' from the ``File'' menu,
|
||||
use ``New'', not ``New Ctrl+m n''.})
|
||||
|
||||
(proc-doc/names
|
||||
test:mouse-click
|
||||
(->*
|
||||
((symbols 'left 'middle 'right)
|
||||
(and/c exact? integer?)
|
||||
|
@ -1010,27 +944,90 @@
|
|||
void?)
|
||||
((button x y)
|
||||
((modifiers null)))
|
||||
"Simulates a mouse click at the coordinate: $(x,y)$ in the currently"
|
||||
"focused \\iscmintf{window}, assuming that it supports the "
|
||||
"@ilink canvas on-event"
|
||||
"method."
|
||||
"Use"
|
||||
"@flink test:button-push"
|
||||
"to click on a button."
|
||||
""
|
||||
"On the Macintosh, \\rawscm{'right} corresponds to holding down the command"
|
||||
"modifier key while clicking and \\rawscm{'middle} cannot be generated."
|
||||
""
|
||||
"Under Windows, \\rawscm{'middle} can only be generated if the user has a"
|
||||
"three button mouse."
|
||||
""
|
||||
"The modifiers later in the list \\var{modifiers} take precedence over"
|
||||
"ones that appear earlier.")
|
||||
@{Simulates a mouse click at the coordinate (x,y) in the currently
|
||||
focused @scheme[window], assuming that it supports the
|
||||
@method[canvas<%> on-event] method.
|
||||
Use @scheme[test:button-push] to click on a button.
|
||||
|
||||
(test:new-window
|
||||
((is-a?/c window<%>) . -> . void?)
|
||||
On the Macintosh, @scheme['right] corresponds to holding down the command
|
||||
modifier key while clicking and @scheme['middle] cannot be generated.
|
||||
|
||||
Under Windows, @scheme['middle] can only be generated if the user has a
|
||||
three button mouse.
|
||||
|
||||
The modifiers later in the list @scheme[modifiers] take precedence over
|
||||
ones that appear earlier.})
|
||||
|
||||
(proc-doc/names
|
||||
test:run-interval
|
||||
(case->
|
||||
(number? . -> . void?)
|
||||
(-> number?))
|
||||
((msec) ())
|
||||
@{See also @secref{test:actions-completeness}.
|
||||
The first case in the case-lambda sets
|
||||
the run interval to @scheme[msec] milliseconds and the second
|
||||
returns the current setting.})
|
||||
|
||||
(parameter-doc
|
||||
test:current-get-eventspaces
|
||||
(parameter/c (-> (listof eventspace?)))
|
||||
func
|
||||
|
||||
@{This parameter that specifies which
|
||||
\\hyperref{eventspaces}{eventspace see section~}{}{eventspaceinfo}
|
||||
are considered when finding the frontmost frame.
|
||||
The first case
|
||||
sets the parameter to @scheme[func]. The procedure @scheme[func] will be
|
||||
invoked with no arguments to determine the eventspaces to consider
|
||||
when finding the frontmost frame for simulated user events.
|
||||
The second case
|
||||
returns the current value of the parameter. This will be a procedure
|
||||
which, when invoked, returns a list of eventspaces.})
|
||||
|
||||
(proc-doc/names
|
||||
test:new-window
|
||||
(-> (is-a?/c window<%>) void?)
|
||||
(window)
|
||||
"Moves the keyboard focus to a new window within the currently active"
|
||||
"frame. Unfortunately, neither this function nor any other function in"
|
||||
"the test engine can cause the focus to move from the top-most (active)"
|
||||
"frame. "))
|
||||
@{Moves the keyboard focus to a new window within the currently active
|
||||
frame. Unfortunately, neither this function nor any other function in
|
||||
the test engine can cause the focus to move from the top-most (active) frame.})
|
||||
|
||||
(proc-doc/names
|
||||
test:close-top-level-window
|
||||
(-> (is-a?/c top-level-window<%>) void?)
|
||||
(tlw)
|
||||
@{Use this function to simulate clicking on the close box of a frame.
|
||||
Closes @scheme[tlw] with this expression:
|
||||
@schemeblock[
|
||||
(when (send tlw can-close?)
|
||||
(send tlw on-close)
|
||||
(send tlw show #f))]})
|
||||
|
||||
(proc-doc/names
|
||||
test:top-level-focus-window-has?
|
||||
(-> (-> (is-a?/c area<%>) boolean?) boolean?)
|
||||
(test)
|
||||
@{Calls @scheme[test] for each child of the top-level-focus-frame
|
||||
and returns @scheme[#t] if @scheme[test] ever does, otherwise
|
||||
returns @scheme[#f]. If there
|
||||
is no top-level-focus-window, returns @scheme[#f].})
|
||||
|
||||
|
||||
(proc-doc
|
||||
test:number-pending-actions
|
||||
(-> number?)
|
||||
@{Returns the number of pending events (those that haven't completed yet)})
|
||||
|
||||
(proc-doc
|
||||
test:reraise-error
|
||||
(-> void?)
|
||||
@{See also @secref{test:errors}.})
|
||||
|
||||
(proc-doc/names
|
||||
test:run-one
|
||||
(-> (-> void?) void?)
|
||||
(f)
|
||||
@{Runs the function @scheme[f] as if it was a simulated event.}))
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
(provide require/doc
|
||||
provide/doc
|
||||
proc-doc)
|
||||
parameter-doc
|
||||
proc-doc
|
||||
proc-doc/names)
|
||||
|
||||
(define-syntax-rule (require/doc spec ...)
|
||||
(void (quote-syntax (require/doc spec ...))))
|
||||
|
@ -53,26 +55,18 @@
|
|||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
[(_ id contract desc)
|
||||
(with-syntax ([(arg ...)
|
||||
(syntax-case #'contract (->d)
|
||||
[(->d (req ...) () result)
|
||||
#'(req ...)]
|
||||
(with-syntax ([((arg ...) result)
|
||||
(syntax-case #'contract (->d -> values)
|
||||
[(->d (req ...) () (values [name res] ...))
|
||||
#'((req ...) (values res ...))]
|
||||
[(->d (req ...) () [name res])
|
||||
#'((req ...) res)]
|
||||
[(-> result)
|
||||
#'(() result)]
|
||||
[else
|
||||
(raise-syntax-error
|
||||
#f
|
||||
"unsupported procedure contract form (arguments)"
|
||||
stx
|
||||
#'contract)])]
|
||||
[result
|
||||
(syntax-case #'contract (->d)
|
||||
[(->d reqs opts (values [name res] ...))
|
||||
#'(values res ...)]
|
||||
[(->d reqs opts [name res])
|
||||
#'res]
|
||||
[else
|
||||
(raise-syntax-error
|
||||
#f
|
||||
"unsupported procedure contract form (arguments)"
|
||||
"unsupported procedure contract form (no argument names)"
|
||||
stx
|
||||
#'contract)])])
|
||||
(values
|
||||
|
@ -80,4 +74,58 @@
|
|||
#'(defproc (id arg ...) result . desc)
|
||||
#'(scribble/manual)))])))
|
||||
|
||||
(define-provide/doc-transformer proc-doc/names
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
[(_ id contract names desc)
|
||||
(with-syntax ([header
|
||||
(syntax-case #'(contract names) (->d -> values)
|
||||
[((-> ctcs ... result) (arg-names ...))
|
||||
(begin
|
||||
(unless (= (length (syntax->list #'(ctcs ...)))
|
||||
(length (syntax->list #'(arg-names ...))))
|
||||
(raise-syntax-error #f "mismatched argument list and domain contract count" stx))
|
||||
#'([(id (arg-names ctcs) ...) result]))]
|
||||
|
||||
[((->* (mandatory ...) (optional ...) result)
|
||||
((mandatory-names ...)
|
||||
((optional-names optional-default) ...)))
|
||||
(begin
|
||||
(unless (= (length (syntax->list #'(mandatory-names ...)))
|
||||
(length (syntax->list #'(mandatory ...))))
|
||||
(raise-syntax-error #f "mismatched mandatory argument list and domain contract count" stx))
|
||||
(unless (= (length (syntax->list #'(optional-names ...)))
|
||||
(length (syntax->list #'(optional ...))))
|
||||
(raise-syntax-error #f "mismatched mandatory argument list and domain contract count" stx))
|
||||
#'([(id (mandatory-names mandatory) ... (optional-names optional optional-default) ...)
|
||||
result]))]
|
||||
[((case-> (-> doms ... rng) ...)
|
||||
((args ...) ...))
|
||||
(begin
|
||||
(for-each
|
||||
(λ (doms args)
|
||||
(unless (= (length (syntax->list doms))
|
||||
(length (syntax->list args)))
|
||||
(raise-syntax-error #f "mismatched case argument list and domain contract" stx)))
|
||||
(syntax->list #'((doms ...) ...))
|
||||
(syntax->list #'((args ...) ...)))
|
||||
#'([(id (args doms) ...) rng] ...))]
|
||||
[else
|
||||
(raise-syntax-error
|
||||
#f
|
||||
"unsupported procedure contract form (no argument names)"
|
||||
stx
|
||||
#'contract)])])
|
||||
(values
|
||||
#'[id contract]
|
||||
#'(defproc* header . desc)
|
||||
#'(scribble/manual)))])))
|
||||
|
||||
(define-provide/doc-transformer parameter-doc
|
||||
(lambda (stx)
|
||||
(syntax-case stx (parameter/c)
|
||||
[(_ id (parameter/c contract) arg-id desc)
|
||||
(values
|
||||
#'[id (parameter/c contract)]
|
||||
#'(defparam id arg-id contract . desc)
|
||||
#'(scribble/manual))])))
|
||||
|
|
|
@ -1,8 +1,118 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual)
|
||||
@(require scribble/manual scribble/extract)
|
||||
@(require (for-label framework/framework))
|
||||
@(require (for-label scheme/gui))
|
||||
@title{Test}
|
||||
|
||||
@(require framework/framework-docs)
|
||||
@(defmodule framework/test)
|
||||
|
||||
The framework provides several new primitive functions that simulate
|
||||
user actions, which may be used to test applications. You use these
|
||||
primitives and combine them just as regular MzScheme functions. For
|
||||
example,
|
||||
@schemeblock[
|
||||
(test:keystroke #\A)
|
||||
(test:menu-select "File" "Save")
|
||||
]
|
||||
sends a keystroke event to the window with the keyboard focus and invokes
|
||||
the callback function for the ``Save'' menu item from the ``File'' menu.
|
||||
This has the same effect as if the user typed the key ``A'', pulled
|
||||
down the ``File'' menu and selected ``Save''.
|
||||
|
||||
It is possible to load this portion of the framework without loading
|
||||
the rest of the framework. Use
|
||||
@scheme[(require framework/test)].
|
||||
|
||||
Currently, the test engine has primitives for pushing
|
||||
buttons, setting check-boxes and choices, sending keystrokes,
|
||||
selecting menu items and clicking the mouse. Many functions
|
||||
that are also useful in application testing, such as
|
||||
traversing a tree of panels, getting the text from a canvas,
|
||||
determining if a window is shown, and so on, exist in MrEd.
|
||||
|
||||
@section[#:tag "test:actions-completeness"]{Actions and completeness}
|
||||
|
||||
The actions associated with a testing primitive may not have finished
|
||||
when the primitive returns to its caller.
|
||||
Some actions may yield control before they can complete.
|
||||
For example, selecting ``Save As...'' from the ``File'' menu
|
||||
opens a dialog box and will not complete until the ``OK''
|
||||
or ``Cancel'' button is pushed.
|
||||
|
||||
However, all testing functions wait at least a minimum interval
|
||||
before returning to give the action a chance to finish.
|
||||
This interval controls the speed at which the test suite runs,
|
||||
and gives some slack time for events to complete.
|
||||
The default interval is 100 milliseconds. The interval can be queried
|
||||
or set with @scheme[test:run-interval].
|
||||
|
||||
A primitive action will not return until the run-interval has
|
||||
expired and the action has finished, raised an error, or yielded.
|
||||
The number of incomplete actions is given by
|
||||
@scheme[test:number-pending-actions].
|
||||
|
||||
@italic{Note:}
|
||||
Once a primitive action is started, it is not possible to undo it
|
||||
or kill its remaining effect.
|
||||
Thus, it is not possible to write a utility that flushes the
|
||||
incomplete actions and resets number-pending-actions to zero.
|
||||
|
||||
However, actions which do not complete right away often provide a
|
||||
way to cancel themselves.
|
||||
For example, many dialog boxes have a ``Cancel'' button which will
|
||||
terminate the action with no further effect.
|
||||
But this is accomplished by sending an additional action
|
||||
(the button push), not by undoing the original action.
|
||||
|
||||
@section[#:tag "test:errors"]{Errors}
|
||||
|
||||
Errors in the primitive actions (which necessarily run in the
|
||||
handler thread) are caught and reraised in the calling thread.
|
||||
|
||||
However, the primitive actions can only guarantee that the action
|
||||
has started, and they may return before the action has completed.
|
||||
As a consequence, an action may raise an error long after the
|
||||
function that started it has returned.
|
||||
In this case, the error is saved and reraised at the first opportunity
|
||||
(the next primitive action).
|
||||
|
||||
The test engine keeps a buffer for one error, saving only the
|
||||
first error. Any subsequent errors are discarded.
|
||||
Reraising an error empties the buffer, allowing the next error
|
||||
to be saved.
|
||||
|
||||
The function @scheme[test:reraise-error]
|
||||
reraises any pending errors.
|
||||
|
||||
@section{Technical Issues}
|
||||
|
||||
@subsection{Active Frame}
|
||||
|
||||
The Self Test primitive actions all implicitly apply to the
|
||||
top-most (active) frame.
|
||||
|
||||
@subsection{Thread Issues}
|
||||
|
||||
The code started by the primitive actions must run in the handler
|
||||
thread of the eventspace where the event takes place. As a result,
|
||||
the test suite that invokes the primitive actions must @italic{not} run
|
||||
in that handler thread (or else some actions will deadlock). See
|
||||
\Mrhyperref{the eventspace section}{see section~}{}{eventspaceinfo}
|
||||
for more info.
|
||||
|
||||
@subsection{Window Manager (Unix only)}
|
||||
|
||||
In order for the Self Tester to work correctly, the window manager
|
||||
must set the keyboard focus to follow the active frame.
|
||||
This is the default behavior in Microsoft Windows and MacOS,
|
||||
but not in X windows.
|
||||
|
||||
In X windows, you must explicitly tell your window manager to set the
|
||||
keyboard focus to the top-most frame, regardless of the position of the
|
||||
actual mouse.
|
||||
|
||||
@section{Test Functions}
|
||||
|
||||
@(def-fw-procs test)
|
||||
@(include-extracted (lib "test.ss" "framework"))
|
||||
|
|
|
@ -74,121 +74,6 @@ The precise set of exported names is:
|
|||
@scheme[preferences:restore-defaults].
|
||||
}}
|
||||
|
||||
@section{GUI Test Suite Utilities}
|
||||
|
||||
The framework provides several new primitive functions that simulate
|
||||
user actions, which may be used to test applications. You use these
|
||||
primitives and combine them just as regular MzScheme functions. For
|
||||
example,
|
||||
@schemeblock[
|
||||
(test:keystroke #\A)
|
||||
(test:menu-select "File" "Save")
|
||||
]
|
||||
sends a keystroke event to the window with the keyboard focus and invokes
|
||||
the callback function for the ``Save'' menu item from the ``File'' menu.
|
||||
This has the same effect as if the user typed the key ``A'', pulled
|
||||
down the ``File'' menu and selected ``Save''.
|
||||
|
||||
It is possible to load this portion of the framework without loading
|
||||
the rest of the framework. Use
|
||||
@scheme[(require framework/test)].
|
||||
|
||||
Currently, the test engine has primitives for pushing
|
||||
buttons, setting check-boxes and choices, sending keystrokes,
|
||||
selecting menu items and clicking the mouse. Many functions
|
||||
that are also useful in application testing, such as
|
||||
traversing a tree of panels, getting the text from a canvas,
|
||||
determining if a window is shown, and so on, exist in MrEd.
|
||||
|
||||
@subsection{Actions and completeness}
|
||||
|
||||
The actions associated with a testing primitive may not have finished
|
||||
when the primitive returns to its caller.
|
||||
Some actions may yield control before they can complete.
|
||||
For example, selecting ``Save As...'' from the ``File'' menu
|
||||
opens a dialog box and will not complete until the ``OK''
|
||||
or ``Cancel'' button is pushed.
|
||||
|
||||
However, all testing functions wait at least a minimum interval
|
||||
before returning to give the action a chance to finish.
|
||||
This interval controls the speed at which the test suite runs,
|
||||
and gives some slack time for events to complete.
|
||||
The default interval is 100 milliseconds. The interval can be queried
|
||||
or set with \iscmprocedure{test:run-interval}.
|
||||
|
||||
A primitive action will not return until the run-interval has
|
||||
expired and the action has finished, raised an error, or yielded.
|
||||
The number of incomplete actions is given by
|
||||
\iscmprocedure{test:number-pending-actions}.
|
||||
|
||||
{\it Note:}
|
||||
Once a primitive action is started, it is not possible to undo it
|
||||
or kill its remaining effect.
|
||||
Thus, it is not possible to write a utility that flushes the
|
||||
incomplete actions and resets number-pending-actions to zero.
|
||||
|
||||
However, actions which do not complete right away often provide a
|
||||
way to cancel themselves.
|
||||
For example, many dialog boxes have a ``Cancel'' button which will
|
||||
terminate the action with no further effect.
|
||||
But this is accomplished by sending an additional action
|
||||
(the button push), not by undoing the original action.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\subsection{Errors}
|
||||
\label{fw:test:errors}
|
||||
|
||||
Errors in the primitive actions (which necessarily run in the
|
||||
handler thread) are caught and reraised in the calling thread.
|
||||
|
||||
However, the primitive actions can only guarantee that the action
|
||||
has started, and they may return before the action has completed.
|
||||
As a consequence, an action may raise an error long after the
|
||||
function that started it has returned.
|
||||
In this case, the error is saved and reraised at the first opportunity
|
||||
(the next primitive action).
|
||||
|
||||
The test engine keeps a buffer for one error, saving only the
|
||||
first error. Any subsequent errors are discarded.
|
||||
Reraising an error empties the buffer, allowing the next error
|
||||
to be saved.
|
||||
|
||||
The function
|
||||
\iscmprocedure{test:reraise-error}
|
||||
reraises any pending errors.
|
||||
|
||||
\subsection{Technical Issues}
|
||||
|
||||
{\bf Active Frame}
|
||||
|
||||
The Self Test primitive actions all implicitly apply to the
|
||||
top-most (active) frame.
|
||||
|
||||
{\bf Thread Issues}
|
||||
|
||||
The code started by the primitive actions must run in the handler
|
||||
thread of the eventspace where the event takes place. As a result,
|
||||
the test suite that invokes the primitive actions must {\it not} run
|
||||
in that handler thread (or else some actions will deadlock). See
|
||||
\Mrhyperref{the eventspace section}{see section~}{}{eventspaceinfo}
|
||||
for more info.
|
||||
|
||||
{\bf Window Manager (Unix only)}
|
||||
|
||||
In order for the Self Tester to work correctly, the window manager
|
||||
must set the keyboard focus to follow the active frame.
|
||||
This is the default behavior in Microsoft Windows and MacOS,
|
||||
but not in X windows.
|
||||
|
||||
In X windows, you must explicitly tell your window manager to set the
|
||||
keyboard focus to the top-most frame, regardless of the position of the
|
||||
actual mouse. Some window managers may not implement such functionality.
|
||||
You can obtain such an effect in Fvwm and Fvwm95 by using the option:
|
||||
\begin{verbatim}
|
||||
Style "*" ClickToFocus
|
||||
\end{verbatim}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@section{Thanks}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user