Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
0c92553d
Commit
0c92553d
authored
Jul 12, 2013
by
Terry Jan Reedy
Browse files
Options
Browse Files
Download
Plain Diff
Merge with 3.3
parents
d0a03ad1
21784da4
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
449 additions
and
5 deletions
+449
-5
Lib/idlelib/idle_test/mock_tk.py
Lib/idlelib/idle_test/mock_tk.py
+221
-5
Lib/idlelib/idle_test/test_text.py
Lib/idlelib/idle_test/test_text.py
+228
-0
No files found.
Lib/idlelib/idle_test/mock_tk.py
View file @
0c92553d
"""Classes that replace tkinter gui objects used by an object being tested.
A gui object is anything with a master or parent paramenter, which is typically
required in spite of what the doc strings say.
"""
...
...
@@ -15,8 +16,10 @@ class Var:
return
self
.
value
class
Mbox_func
:
"""Generic mock for messagebox functions. All have same call signature.
Mbox instantiates once for each function. Tester uses attributes.
"""Generic mock for messagebox functions, which all have the same signature.
Instead of displaying a message box, the mock's call method saves the
arguments as instance attributes, which test functions can then examime.
"""
def
__init__
(
self
):
self
.
result
=
None
# The return for all show funcs
...
...
@@ -30,6 +33,7 @@ class Mbox_func:
class
Mbox
:
"""Mock for tkinter.messagebox with an Mbox_func for each function.
This module was 'tkMessageBox' in 2.x; hence the 'import as' in 3.x.
Example usage in test_module.py for testing functios in module.py:
---
...
...
@@ -49,9 +53,9 @@ class Test(unittest.TestCase):
def tearDownClass(cls):
module.tkMessageBox = orig_mbox
---
When tkMessageBox functions are the only gui making calls in a method,
th
is replacement makes the method gui-free and unit-testable.
For 'ask' functions, set func.result return before calling method.
For 'ask' functions, set func.result return value before calling the method
th
at uses the message function. When tkMessageBox functions are the
only gui alls in a method, this replacement makes the method gui-free,
"""
askokcancel
=
Mbox_func
()
# True or False
askquestion
=
Mbox_func
()
# 'yes' or 'no'
...
...
@@ -61,3 +65,215 @@ class Test(unittest.TestCase):
showerror
=
Mbox_func
()
# None
showinfo
=
Mbox_func
()
# None
showwarning
=
Mbox_func
()
# None
from
_tkinter
import
TclError
class
Text
:
"""A semi-functional non-gui replacement for tkinter.Text text editors.
The mock's data model is that a text is a list of
\
n
-terminated lines.
The mock adds an empty string at the beginning of the list so that the
index of actual lines start at 1, as with Tk. The methods never see this.
Tk initializes files with a terminal
\
n
that cannot be deleted. It is
invisible in the sense that one cannot move the cursor beyond it.
This class is only tested (and valid) with strings of ascii chars.
For testing, we are not concerned with Tk Text's treatment of,
for instance, 0-width characters or character + accent.
"""
def
__init__
(
self
,
master
=
None
,
cnf
=
{},
**
kw
):
'''Initialize mock, non-gui, text-only Text widget.
At present, all args are ignored. Almost all affect visual behavior.
There are just a few Text-only options that affect text behavior.
'''
self
.
data
=
[
''
,
'
\
n
'
]
def
index
(
self
,
index
):
"Return string version of index decoded according to current text."
return
"%s.%s"
%
self
.
_decode
(
index
,
endflag
=
1
)
def
_decode
(
self
,
index
,
endflag
=
0
):
"""Return a (line, char) tuple of int indexes into self.data.
This implements .index without converting the result back to a string.
The result is contrained by the number of lines and linelengths of
self.data. For many indexes, the result is initally (1, 0).
The input index may have any of several possible forms:
* line.char float: converted to 'line.char' string;
* 'line.char' string, where line and char are decimal integers;
* 'line.char lineend', where lineend='lineend' (and char is ignored);
* 'line.end', where end='end' (same as above);
* 'insert', the positions before terminal
\
n
;
* 'end', whose meaning depends on the endflag passed to ._endex.
* 'sel.first' or 'sel.last', where sel is a tag -- not implemented.
"""
if
isinstance
(
index
,
(
float
,
bytes
)):
index
=
str
(
index
)
try
:
index
=
index
.
lower
()
except
AttributeError
:
raise
TclError
(
'bad text index "%s"'
%
index
)
from
None
lastline
=
len
(
self
.
data
)
-
1
# same as number of text lines
if
index
==
'insert'
:
return
lastline
,
len
(
self
.
data
[
lastline
])
-
1
elif
index
==
'end'
:
return
self
.
_endex
(
endflag
)
line
,
char
=
index
.
split
(
'.'
)
line
=
int
(
line
)
# Out of bounds line becomes first or last ('end') index
if
line
<
1
:
return
1
,
0
elif
line
>
lastline
:
return
self
.
_endex
(
endflag
)
linelength
=
len
(
self
.
data
[
line
])
-
1
# position before/at \n
if
char
.
endswith
(
' lineend'
)
or
char
==
'end'
:
return
line
,
linelength
# Tk requires that ignored chars before ' lineend' be valid int
# Out of bounds char becomes first or last index of line
char
=
int
(
char
)
if
char
<
0
:
char
=
0
elif
char
>
linelength
:
char
=
linelength
return
line
,
char
def
_endex
(
self
,
endflag
):
'''Return position for 'end' or line overflow corresponding to endflag.
-1: position before terminal
\
n
; for .insert(), .delete
0: position after terminal
\
n
; for .get, .delete index 1
1: same viewed as begininning of non-existent next line (for .index)
'''
n
=
len
(
self
.
data
)
if
endflag
==
1
:
return
n
,
0
else
:
n
-=
1
return
n
,
len
(
self
.
data
[
n
])
+
endflag
def
insert
(
self
,
index
,
chars
):
"Insert chars before the character at index."
if
not
chars
:
# ''.splitlines() is [], not ['']
return
chars
=
chars
.
splitlines
(
True
)
if
chars
[
-
1
][
-
1
]
==
'
\
n
'
:
chars
.
append
(
''
)
line
,
char
=
self
.
_decode
(
index
,
-
1
)
before
=
self
.
data
[
line
][:
char
]
after
=
self
.
data
[
line
][
char
:]
self
.
data
[
line
]
=
before
+
chars
[
0
]
self
.
data
[
line
+
1
:
line
+
1
]
=
chars
[
1
:]
self
.
data
[
line
+
len
(
chars
)
-
1
]
+=
after
def
get
(
self
,
index1
,
index2
=
None
):
"Return slice from index1 to index2 (default is 'index1+1')."
startline
,
startchar
=
self
.
_decode
(
index1
)
if
index2
is
None
:
endline
,
endchar
=
startline
,
startchar
+
1
else
:
endline
,
endchar
=
self
.
_decode
(
index2
)
if
startline
==
endline
:
return
self
.
data
[
startline
][
startchar
:
endchar
]
else
:
lines
=
[
self
.
data
[
startline
][
startchar
:]]
for
i
in
range
(
startline
+
1
,
endline
):
lines
.
append
(
self
.
data
[
i
])
lines
.
append
(
self
.
data
[
endline
][:
endchar
])
return
''
.
join
(
lines
)
def
delete
(
self
,
index1
,
index2
=
None
):
'''Delete slice from index1 to index2 (default is 'index1+1').
Adjust default index2 ('index+1) for line ends.
Do not delete the terminal
\
n
at the very end of self.data ([-1][-1]).
'''
startline
,
startchar
=
self
.
_decode
(
index1
,
-
1
)
if
index2
is
None
:
if
startchar
<
len
(
self
.
data
[
startline
])
-
1
:
# not deleting \n
endline
,
endchar
=
startline
,
startchar
+
1
elif
startline
<
len
(
self
.
data
)
-
1
:
# deleting non-terminal \n, convert 'index1+1 to start of next line
endline
,
endchar
=
startline
+
1
,
0
else
:
# do not delete terminal \n if index1 == 'insert'
return
else
:
endline
,
endchar
=
self
.
_decode
(
index2
,
-
1
)
# restricting end position to insert position excludes terminal \n
if
startline
==
endline
and
startchar
<
endchar
:
self
.
data
[
startline
]
=
self
.
data
[
startline
][:
startchar
]
+
\
self
.
data
[
startline
][
endchar
:]
elif
startline
<
endline
:
self
.
data
[
startline
]
=
self
.
data
[
startline
][:
startchar
]
+
\
self
.
data
[
endline
][
endchar
:]
startline
+=
1
for
i
in
range
(
startline
,
endline
+
1
):
del
self
.
data
[
startline
]
def
compare
(
self
,
index1
,
op
,
index2
):
line1
,
char1
=
self
.
_decode
(
index1
)
line2
,
char2
=
self
.
_decode
(
index2
)
if
op
==
'<'
:
return
line1
<
line2
or
line1
==
line2
and
char1
<
char2
elif
op
==
'<='
:
return
line1
<
line2
or
line1
==
line2
and
char1
<=
char2
elif
op
==
'>'
:
return
line1
>
line2
or
line1
==
line2
and
char1
>
char2
elif
op
==
'>='
:
return
line1
>
line2
or
line1
==
line2
and
char1
>=
char2
elif
op
==
'=='
:
return
line1
==
line2
and
char1
==
char2
elif
op
==
'!='
:
return
line1
!=
line2
or
char1
!=
char2
else
:
raise
TclError
(
'''bad comparison operator "%s":'''
'''must be <, <=, ==, >=, >, or !='''
%
op
)
# The following Text methods normally do something and return None.
# Whether doing nothing is sufficient for a test will depend on the test.
def
mark_set
(
self
,
name
,
index
):
"Set mark *name* before the character at index."
pass
def
mark_unset
(
self
,
*
markNames
):
"Delete all marks in markNames."
def
tag_remove
(
self
,
tagName
,
index1
,
index2
=
None
):
"Remove tag tagName from all characters between index1 and index2."
pass
# The following Text methods affect the graphics screen and return None.
# Doing nothing should always be sufficient for tests.
def
scan_dragto
(
self
,
x
,
y
):
"Adjust the view of the text according to scan_mark"
def
scan_mark
(
self
,
x
,
y
):
"Remember the current X, Y coordinates."
def
see
(
self
,
index
):
"Scroll screen to make the character at INDEX is visible."
pass
# The following is a Misc method inheritet by Text.
# It should properly go in a Misc mock, but is included here for now.
def
bind
(
sequence
=
None
,
func
=
None
,
add
=
None
):
"Bind to this widget at event sequence a call to function func."
pass
Lib/idlelib/idle_test/test_text.py
0 → 100644
View file @
0c92553d
# Test mock_tk.Text class against tkinter.Text class by running same tests with both.
import
unittest
from
test.support
import
requires
from
_tkinter
import
TclError
import
tkinter
as
tk
class
TextTest
(
object
):
hw
=
'hello
\
n
world'
# usual initial insert after initialization
hwn
=
hw
+
'
\
n
'
# \n present at initialization, before insert
Text
=
None
def
setUp
(
self
):
self
.
text
=
self
.
Text
()
def
test_init
(
self
):
self
.
assertEqual
(
self
.
text
.
get
(
'1.0'
),
'
\
n
'
)
self
.
assertEqual
(
self
.
text
.
get
(
'end'
),
''
)
def
test_index_empty
(
self
):
index
=
self
.
text
.
index
for
dex
in
(
-
1.0
,
0.3
,
'1.-1'
,
'1.0'
,
'1.0 lineend'
,
'1.end'
,
'1.33'
,
'insert'
):
self
.
assertEqual
(
index
(
dex
),
'1.0'
)
for
dex
in
'end'
,
2.0
,
'2.1'
,
'33.44'
:
self
.
assertEqual
(
index
(
dex
),
'2.0'
)
def
test_index_data
(
self
):
index
=
self
.
text
.
index
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
for
dex
in
-
1.0
,
0.3
,
'1.-1'
,
'1.0'
:
self
.
assertEqual
(
index
(
dex
),
'1.0'
)
for
dex
in
'1.0 lineend'
,
'1.end'
,
'1.33'
:
self
.
assertEqual
(
index
(
dex
),
'1.5'
)
for
dex
in
'end'
,
'33.44'
:
self
.
assertEqual
(
index
(
dex
),
'3.0'
)
def
test_get
(
self
):
get
=
self
.
text
.
get
Equal
=
self
.
assertEqual
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
Equal
(
get
(
'end'
),
''
)
Equal
(
get
(
'end'
,
'end'
),
''
)
Equal
(
get
(
'1.0'
),
'h'
)
Equal
(
get
(
'1.0'
,
'1.1'
),
'h'
)
Equal
(
get
(
'1.0'
,
'1.3'
),
'hel'
)
Equal
(
get
(
'1.1'
,
'1.3'
),
'el'
)
Equal
(
get
(
'1.0'
,
'1.0 lineend'
),
'hello'
)
Equal
(
get
(
'1.0'
,
'1.10'
),
'hello'
)
Equal
(
get
(
'1.0 lineend'
),
'
\
n
'
)
Equal
(
get
(
'1.1'
,
'2.3'
),
'ello
\
n
wor'
)
Equal
(
get
(
'1.0'
,
'2.5'
),
self
.
hw
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
Equal
(
get
(
'0.0'
,
'5.0'
),
self
.
hwn
)
def
test_insert
(
self
):
insert
=
self
.
text
.
insert
get
=
self
.
text
.
get
Equal
=
self
.
assertEqual
insert
(
'1.0'
,
self
.
hw
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
insert
(
'1.0'
,
''
)
# nothing
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
insert
(
'1.0'
,
'*'
)
Equal
(
get
(
'1.0'
,
'end'
),
'*hello
\
n
world
\
n
'
)
insert
(
'1.0 lineend'
,
'*'
)
Equal
(
get
(
'1.0'
,
'end'
),
'*hello*
\
n
world
\
n
'
)
insert
(
'2.3'
,
'*'
)
Equal
(
get
(
'1.0'
,
'end'
),
'*hello*
\
n
wor*ld
\
n
'
)
insert
(
'end'
,
'x'
)
Equal
(
get
(
'1.0'
,
'end'
),
'*hello*
\
n
wor*ldx
\
n
'
)
insert
(
'1.4'
,
'x
\
n
'
)
Equal
(
get
(
'1.0'
,
'end'
),
'*helx
\
n
lo*
\
n
wor*ldx
\
n
'
)
def
test_no_delete
(
self
):
# if index1 == 'insert' or 'end' or >= end, there is no deletion
delete
=
self
.
text
.
delete
get
=
self
.
text
.
get
Equal
=
self
.
assertEqual
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
delete
(
'insert'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
delete
(
'end'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
delete
(
'insert'
,
'end'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
delete
(
'insert'
,
'5.5'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
delete
(
'1.4'
,
'1.0'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
delete
(
'1.4'
,
'1.4'
)
Equal
(
get
(
'1.0'
,
'end'
),
self
.
hwn
)
def
test_delete_char
(
self
):
delete
=
self
.
text
.
delete
get
=
self
.
text
.
get
Equal
=
self
.
assertEqual
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
delete
(
'1.0'
)
Equal
(
get
(
'1.0'
,
'1.end'
),
'ello'
)
delete
(
'1.0'
,
'1.1'
)
Equal
(
get
(
'1.0'
,
'1.end'
),
'llo'
)
# delete \n and combine 2 lines into 1
delete
(
'1.end'
)
Equal
(
get
(
'1.0'
,
'1.end'
),
'lloworld'
)
self
.
text
.
insert
(
'1.3'
,
'
\
n
'
)
delete
(
'1.10'
)
Equal
(
get
(
'1.0'
,
'1.end'
),
'lloworld'
)
self
.
text
.
insert
(
'1.3'
,
'
\
n
'
)
delete
(
'1.3'
,
'2.0'
)
Equal
(
get
(
'1.0'
,
'1.end'
),
'lloworld'
)
def
test_delete_slice
(
self
):
delete
=
self
.
text
.
delete
get
=
self
.
text
.
get
Equal
=
self
.
assertEqual
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
delete
(
'1.0'
,
'1.0 lineend'
)
Equal
(
get
(
'1.0'
,
'end'
),
'
\
n
world
\
n
'
)
delete
(
'1.0'
,
'end'
)
Equal
(
get
(
'1.0'
,
'end'
),
'
\
n
'
)
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
delete
(
'1.0'
,
'2.0'
)
Equal
(
get
(
'1.0'
,
'end'
),
'world
\
n
'
)
delete
(
'1.0'
,
'end'
)
Equal
(
get
(
'1.0'
,
'end'
),
'
\
n
'
)
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
delete
(
'1.2'
,
'2.3'
)
Equal
(
get
(
'1.0'
,
'end'
),
'held
\
n
'
)
def
test_multiple_lines
(
self
):
# insert and delete
self
.
text
.
insert
(
'1.0'
,
'hello'
)
self
.
text
.
insert
(
'1.3'
,
'1
\
n
2
\
n
3
\
n
4
\
n
5'
)
self
.
assertEqual
(
self
.
text
.
get
(
'1.0'
,
'end'
),
'hel1
\
n
2
\
n
3
\
n
4
\
n
5lo
\
n
'
)
self
.
text
.
delete
(
'1.3'
,
'5.1'
)
self
.
assertEqual
(
self
.
text
.
get
(
'1.0'
,
'end'
),
'hello
\
n
'
)
def
test_compare
(
self
):
compare
=
self
.
text
.
compare
Equal
=
self
.
assertEqual
# need data so indexes not squished to 1,0
self
.
text
.
insert
(
'1.0'
,
'First
\
n
Second
\
n
Third
\
n
'
)
self
.
assertRaises
(
TclError
,
compare
,
'2.2'
,
'op'
,
'2.2'
)
for
op
,
less1
,
less0
,
equal
,
greater0
,
greater1
in
(
(
'<'
,
True
,
True
,
False
,
False
,
False
),
(
'<='
,
True
,
True
,
True
,
False
,
False
),
(
'>'
,
False
,
False
,
False
,
True
,
True
),
(
'>='
,
False
,
False
,
True
,
True
,
True
),
(
'=='
,
False
,
False
,
True
,
False
,
False
),
(
'!='
,
True
,
True
,
False
,
True
,
True
),
):
Equal
(
compare
(
'1.1'
,
op
,
'2.2'
),
less1
,
op
)
Equal
(
compare
(
'2.1'
,
op
,
'2.2'
),
less0
,
op
)
Equal
(
compare
(
'2.2'
,
op
,
'2.2'
),
equal
,
op
)
Equal
(
compare
(
'2.3'
,
op
,
'2.2'
),
greater0
,
op
)
Equal
(
compare
(
'3.3'
,
op
,
'2.2'
),
greater1
,
op
)
class
MockTextTest
(
TextTest
,
unittest
.
TestCase
):
@
classmethod
def
setUpClass
(
cls
):
from
idlelib.idle_test.mock_tk
import
Text
cls
.
Text
=
Text
def
test_decode
(
self
):
# test endflags (-1, 0) not tested by test_index (which uses +1)
decode
=
self
.
text
.
_decode
Equal
=
self
.
assertEqual
self
.
text
.
insert
(
'1.0'
,
self
.
hw
)
Equal
(
decode
(
'end'
,
-
1
),
(
2
,
5
))
Equal
(
decode
(
'3.1'
,
-
1
),
(
2
,
5
))
Equal
(
decode
(
'end'
,
0
),
(
2
,
6
))
Equal
(
decode
(
'3.1'
,
0
),
(
2
,
6
))
class
TkTextTest
(
TextTest
,
unittest
.
TestCase
):
@
classmethod
def
setUpClass
(
cls
):
requires
(
'gui'
)
from
tkinter
import
Tk
,
Text
cls
.
Text
=
Text
cls
.
root
=
Tk
()
@
classmethod
def
tearDownClass
(
cls
):
cls
.
root
.
destroy
()
if
__name__
==
'__main__'
:
unittest
.
main
(
verbosity
=
2
,
exit
=
False
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment