optimism 3.1__tar.gz → 3.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {optimism-3.1 → optimism-3.1.2}/PKG-INFO +3 -3
- optimism-3.1.2/optimism/__init__.py +21 -0
- optimism-3.1.2/optimism/examples/a.txt +2 -0
- optimism-3.1.2/optimism/examples/b.txt +3 -0
- optimism-3.1.2/optimism/examples/bad.py +6 -0
- optimism-3.1.2/optimism/examples/basic.py +72 -0
- optimism-3.1.2/optimism/examples/bits.py +28 -0
- optimism-3.1.2/optimism/examples/block.py +30 -0
- optimism-3.1.2/optimism/examples/catch_and_release.py +44 -0
- optimism-3.1.2/optimism/examples/code.py +96 -0
- optimism-3.1.2/optimism/examples/core.py +40 -0
- optimism-3.1.2/optimism/examples/doc_example.py +34 -0
- optimism-3.1.2/optimism/examples/doctests.py +396 -0
- optimism-3.1.2/optimism/examples/errors.py +6 -0
- optimism-3.1.2/optimism/examples/files.py +50 -0
- optimism-3.1.2/optimism/examples/fragments.py +23 -0
- optimism-3.1.2/optimism/examples/io_example.py +5 -0
- optimism-3.1.2/optimism/examples/literals.py +54 -0
- optimism-3.1.2/optimism/examples/memoryReports.py +9 -0
- optimism-3.1.2/optimism/examples/multi.py +16 -0
- optimism-3.1.2/optimism/examples/reverse_tracing.py +303 -0
- optimism-3.1.2/optimism/examples/runfile.py +58 -0
- optimism-3.1.2/optimism/examples/skip.py +38 -0
- optimism-3.1.2/optimism/examples/structure.py +114 -0
- optimism-3.1.2/optimism/examples/suites.py +67 -0
- optimism-3.1.2/optimism/examples/tracing.py +12 -0
- {optimism-3.1 → optimism-3.1.2/optimism}/optimism.py +68 -38
- optimism-3.1.2/optimism/py.typed +1 -0
- optimism-3.1.2/optimism/test_examples.py +1396 -0
- {optimism-3.1 → optimism-3.1.2}/optimism.egg-info/PKG-INFO +3 -3
- optimism-3.1.2/optimism.egg-info/SOURCES.txt +37 -0
- {optimism-3.1 → optimism-3.1.2}/setup.cfg +7 -3
- optimism-3.1/optimism.egg-info/SOURCES.txt +0 -10
- {optimism-3.1 → optimism-3.1.2}/LICENSE.txt +0 -0
- {optimism-3.1 → optimism-3.1.2}/README.md +0 -0
- {optimism-3.1 → optimism-3.1.2}/optimism.egg-info/dependency_links.txt +0 -0
- {optimism-3.1 → optimism-3.1.2}/optimism.egg-info/requires.txt +0 -0
- {optimism-3.1 → optimism-3.1.2}/optimism.egg-info/top_level.txt +0 -0
- {optimism-3.1 → optimism-3.1.2}/pyproject.toml +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: optimism
|
|
3
|
-
Version: 3.1
|
|
4
|
-
Summary: Very simple testing framework suitable for beginner programmers, with easy functions for accomplishing most common testing tasks like providing input.
|
|
3
|
+
Version: 3.1.2
|
|
4
|
+
Summary: Very simple testing framework suitable for beginner programmers, with easy functions for accomplishing most common testing tasks like providing input. Requires Python 3.8+.
|
|
5
5
|
Home-page: https://cs.wellesley.edu/~pmwh/optimism/docs/optimism.html
|
|
6
6
|
Author: Peter Mawhorter
|
|
7
7
|
Author-email: pmawhort@wellesley.edu
|
|
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: BSD License
|
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Natural Language :: English
|
|
16
16
|
Classifier: Topic :: Education
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE.txt
|
|
20
20
|
Provides-Extra: test
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This package init just imports everything from optimism.py, including
|
|
3
|
+
explicitly the version number (which otherwise would be skipped since it
|
|
4
|
+
starts with '_'). That way, importing optimism-the-package is the same as
|
|
5
|
+
importing optimism-the-file, except that private variables are not
|
|
6
|
+
exported by the package. So you can distribute the package OR just the
|
|
7
|
+
optimism.py file and both should work the same.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .optimism import *
|
|
11
|
+
|
|
12
|
+
# Setuptools versions on Python 3.10 won't allow us to just import the
|
|
13
|
+
# version from optimism, but we want the version to be defined in that
|
|
14
|
+
# file so that a single-file distribution is equivalent to this packaged
|
|
15
|
+
# distribution. So we define a version here as well, but...
|
|
16
|
+
__version__ = "3.1.2"
|
|
17
|
+
|
|
18
|
+
# ...then we assert it matches so testing will catch it if I forget to
|
|
19
|
+
# keep them in sync before a release. T_T
|
|
20
|
+
from .optimism import __version__ as match
|
|
21
|
+
assert __version__ == match
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic demonstration of optimism core testing functionality.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import optimism
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Simple example function
|
|
9
|
+
def f(x, y):
|
|
10
|
+
"Example function"
|
|
11
|
+
return x + y + 1
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Simple test for that function
|
|
15
|
+
t = optimism.testFunction(f)
|
|
16
|
+
t.case(1, 2).checkReturnValue(4) # line 16
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Function that prints multiple lines of output
|
|
20
|
+
def display(message):
|
|
21
|
+
print("The message is:")
|
|
22
|
+
print('-' + message + '-')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Multi-line output test
|
|
26
|
+
t = optimism.testFunction(display)
|
|
27
|
+
t.case('hello').checkPrintedLines('The message is:', '-hello-') # line 27
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def askNameAge():
|
|
31
|
+
"A function that uses input."
|
|
32
|
+
name = input("What is your name? ")
|
|
33
|
+
age = input("How old are you? ")
|
|
34
|
+
return (name, age)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# One test case with specific inputs that checks both the return value
|
|
38
|
+
# and what is printed
|
|
39
|
+
test = optimism.testFunction(askNameAge) # line 39
|
|
40
|
+
case = test.case()
|
|
41
|
+
case.provideInputs("Name", "thirty")
|
|
42
|
+
case.checkReturnValue(('Name', 'thirty')) # line 42
|
|
43
|
+
case.checkPrintedLines( # line 43
|
|
44
|
+
'What is your name? Name',
|
|
45
|
+
'How old are you? thirty' # line 45
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
optimism.showSummary()
|
|
49
|
+
|
|
50
|
+
# These checks will show details about the expressions used (like the
|
|
51
|
+
# value of x):
|
|
52
|
+
x = 3
|
|
53
|
+
y = 4
|
|
54
|
+
optimism.testFunction(f).case(x + x, y).checkReturnValue(10) # fails (is 11)
|
|
55
|
+
optimism.expect(f(x + x, y), 10) # fails; shows x
|
|
56
|
+
|
|
57
|
+
# Increase detail level
|
|
58
|
+
optimism.detailLevel(1)
|
|
59
|
+
|
|
60
|
+
c = optimism.testFunction(display).case('nope')
|
|
61
|
+
c.checkReturnValue(False) # fails (result is None)
|
|
62
|
+
c.checkPrintedLines('The message is:', '-nope-') # succeeds
|
|
63
|
+
|
|
64
|
+
optimism.detailLevel(0)
|
|
65
|
+
c.checkPrintedLines('The message is:', '-yep-') # fails
|
|
66
|
+
|
|
67
|
+
# For loop test
|
|
68
|
+
for x in range(3):
|
|
69
|
+
t = optimism.testFunction(f).case(x, x).checkReturnValue(5)
|
|
70
|
+
# fails except when x == 2
|
|
71
|
+
|
|
72
|
+
optimism.showSummary()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import optimism as opt
|
|
2
|
+
|
|
3
|
+
x = [1, 2, 3]
|
|
4
|
+
y = [4, 5, 6]
|
|
5
|
+
x.append(y)
|
|
6
|
+
|
|
7
|
+
opt.detailLevel(1)
|
|
8
|
+
|
|
9
|
+
opt.expect(x, [1, 2, 3, [4, 5, 6]])
|
|
10
|
+
|
|
11
|
+
y.pop()
|
|
12
|
+
opt.expect(x, [1, 2, 3, [4, 5]])
|
|
13
|
+
opt.expect(x[3], y)
|
|
14
|
+
opt.expect(x[3][-1], 5)
|
|
15
|
+
|
|
16
|
+
x.pop()
|
|
17
|
+
opt.expect(x, [1, 2, 3])
|
|
18
|
+
opt.expect(x[1], 2)
|
|
19
|
+
|
|
20
|
+
opt.expect(x, [1, 2, 3])
|
|
21
|
+
x.pop()
|
|
22
|
+
opt.expect(x, [1, 2])
|
|
23
|
+
|
|
24
|
+
# This... doesn't work
|
|
25
|
+
opt.expect(x[-1], x.pop())
|
|
26
|
+
|
|
27
|
+
opt.expectType(x, list)
|
|
28
|
+
opt.expectType(x[0], int)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import optimism as opt
|
|
2
|
+
|
|
3
|
+
x = 3
|
|
4
|
+
|
|
5
|
+
m = opt.testBlock(
|
|
6
|
+
"""\
|
|
7
|
+
print(x)
|
|
8
|
+
x += 1
|
|
9
|
+
print(x)"""
|
|
10
|
+
)
|
|
11
|
+
c = m.case()
|
|
12
|
+
c.checkPrintedLines('3', '4')
|
|
13
|
+
c.checkVariableValue('x', 5)
|
|
14
|
+
c = m.case(x=5)
|
|
15
|
+
c.checkPrintedLines('5', '6')
|
|
16
|
+
c.checkVariableValue('x', 6)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
m = opt.testBlock(
|
|
20
|
+
"""\
|
|
21
|
+
x = 3
|
|
22
|
+
print(x)
|
|
23
|
+
x += 1
|
|
24
|
+
print(x)
|
|
25
|
+
x += 1"""
|
|
26
|
+
)
|
|
27
|
+
c = m.case()
|
|
28
|
+
c.checkPrintedLines('3', '4')
|
|
29
|
+
c.checkVariableValue('x', 5)
|
|
30
|
+
c.checkVariableValue('x', 6)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import optimism as opt
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def interactive():
|
|
5
|
+
"""
|
|
6
|
+
An interactive function for testing purposes.
|
|
7
|
+
"""
|
|
8
|
+
x = input('Y?')
|
|
9
|
+
print(x + ' Z!')
|
|
10
|
+
return x
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Call it once before testing
|
|
14
|
+
interactive()
|
|
15
|
+
|
|
16
|
+
m = opt.testFunction(interactive)
|
|
17
|
+
c = m.case()
|
|
18
|
+
c.provideInputs('Q')
|
|
19
|
+
c.checkPrintedLines('Y?Q', 'Q Z!')
|
|
20
|
+
c.checkReturnValue('Q')
|
|
21
|
+
|
|
22
|
+
c = m.case()
|
|
23
|
+
c.provideInputs('A')
|
|
24
|
+
c.checkPrintedLines('Y?A', 'A Z!')
|
|
25
|
+
c.checkReturnValue('A')
|
|
26
|
+
|
|
27
|
+
c = m.case()
|
|
28
|
+
c.provideInputs('A')
|
|
29
|
+
c.provideInputs('B') # this is okay, and redefines the inputs
|
|
30
|
+
c.checkPrintedLines('Y?B', 'B Z!')
|
|
31
|
+
c.checkReturnValue('B')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# This isn't allowed
|
|
35
|
+
try:
|
|
36
|
+
c.provideInputs('N')
|
|
37
|
+
except opt.TestError:
|
|
38
|
+
print("Re-providing input was blocked.")
|
|
39
|
+
|
|
40
|
+
# Does input/output capturing mess with this?
|
|
41
|
+
print("Hello")
|
|
42
|
+
|
|
43
|
+
# Call it again after releasing input & output
|
|
44
|
+
interactive()
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Basic demonstration of optimism code-structure checking functionality.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import optimism
|
|
6
|
+
|
|
7
|
+
optimism.skipChecksAfterFail(None)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def askNameAge():
|
|
11
|
+
"A function that uses input."
|
|
12
|
+
name = input("What is your name? ")
|
|
13
|
+
age = input("How old are you? ")
|
|
14
|
+
return (name, age)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Test manager for that function
|
|
18
|
+
tester = optimism.testFunction(askNameAge)
|
|
19
|
+
|
|
20
|
+
# A structural check to ensure that the above function uses `input`
|
|
21
|
+
tester.checkCodeContains(optimism.Call('input'))
|
|
22
|
+
|
|
23
|
+
# Checks with bounds on the number of use sites
|
|
24
|
+
tester.checkCodeContains(optimism.Call('input', min=2))
|
|
25
|
+
tester.checkCodeContains(optimism.Call('input', n=2))
|
|
26
|
+
tester.checkCodeContains(optimism.Call('input', max=2))
|
|
27
|
+
|
|
28
|
+
# A simple loop that uses print multiple times
|
|
29
|
+
for x in range(4):
|
|
30
|
+
print(x)
|
|
31
|
+
|
|
32
|
+
# Some operators
|
|
33
|
+
if x < 3:
|
|
34
|
+
print(x not in (1, 2, 3))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Tester for this file
|
|
38
|
+
fileTester = optimism.testFile(__file__)
|
|
39
|
+
|
|
40
|
+
fileTester.checkCodeContains(optimism.Def()) # succeeds
|
|
41
|
+
fileTester.checkCodeContains(optimism.Def('askNameAge')) # succeeds
|
|
42
|
+
fileTester.checkCodeContains(optimism.Def('functionName')) # fails
|
|
43
|
+
|
|
44
|
+
fileTester.checkCodeContains(optimism.Def().contains(optimism.Return())) # ✓
|
|
45
|
+
fileTester.checkCodeContains(optimism.Def().contains(optimism.Loop())) # ✗
|
|
46
|
+
fileTester.checkCodeContains(optimism.Loop().contains(optimism.Def())) # ✗
|
|
47
|
+
fileTester.checkCodeContains(optimism.Loop(only="while")) # ✗
|
|
48
|
+
fileTester.checkCodeContains(optimism.Loop(only="for")) # ✓
|
|
49
|
+
|
|
50
|
+
fileTester.checkCodeContains(
|
|
51
|
+
optimism.Loop().contains(optimism.Call('print'))
|
|
52
|
+
) # ✓
|
|
53
|
+
fileTester.checkCodeContains(
|
|
54
|
+
optimism.Loop().contains(optimism.Call('range'))
|
|
55
|
+
) # ✓
|
|
56
|
+
fileTester.checkCodeContains(
|
|
57
|
+
optimism.Loop().contains(optimism.Call('print', n=1))
|
|
58
|
+
) # ✓
|
|
59
|
+
fileTester.checkCodeContains(
|
|
60
|
+
optimism.Loop().contains(optimism.Call('print', n=4))
|
|
61
|
+
) # ✗
|
|
62
|
+
fileTester.checkCodeContains(
|
|
63
|
+
optimism.Loop().contains(optimism.Call('print', min=4))
|
|
64
|
+
) # ✗
|
|
65
|
+
fileTester.checkCodeContains(
|
|
66
|
+
optimism.Loop().contains(optimism.Call('print', max=1))
|
|
67
|
+
) # ✓
|
|
68
|
+
fileTester.checkCodeContains(
|
|
69
|
+
optimism.Loop().contains(optimism.Call('print', max=0))
|
|
70
|
+
) # ✗
|
|
71
|
+
fileTester.checkCodeContains(
|
|
72
|
+
optimism.Loop().contains(optimism.Call('notCalled', min=0))
|
|
73
|
+
) # ✓
|
|
74
|
+
|
|
75
|
+
fileTester.checkCodeContains(
|
|
76
|
+
optimism.IfElse().contains(optimism.Operator('<'))
|
|
77
|
+
) # ✓
|
|
78
|
+
fileTester.checkCodeContains(
|
|
79
|
+
optimism.IfElse().contains(optimism.Operator('>'))
|
|
80
|
+
) # ✗
|
|
81
|
+
fileTester.checkCodeContains(
|
|
82
|
+
optimism.IfElse().contains(optimism.Operator('in'))
|
|
83
|
+
) # ✓
|
|
84
|
+
fileTester.checkCodeContains(
|
|
85
|
+
optimism.IfElse().contains(optimism.Operator('not in'))
|
|
86
|
+
) # ✓
|
|
87
|
+
|
|
88
|
+
# Testing constant matching w/ types/values
|
|
89
|
+
('a', 2, 5.0)
|
|
90
|
+
fileTester.checkCodeContains(optimism.Constant('a')) # ✓
|
|
91
|
+
fileTester.checkCodeContains(optimism.Constant(2)) # ✓
|
|
92
|
+
fileTester.checkCodeContains(optimism.Constant(4.0 / 2)) # ✓
|
|
93
|
+
fileTester.checkCodeContains(optimism.Constant(4.0 / 2, float)) # ✗
|
|
94
|
+
fileTester.checkCodeContains(optimism.Constant(4.0 / 2, int)) # ✓
|
|
95
|
+
fileTester.checkCodeContains(optimism.Constant(5.0, int)) # ✗
|
|
96
|
+
fileTester.checkCodeContains(optimism.Constant(5.0, float)) # ✓
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from optimism import *
|
|
2
|
+
|
|
3
|
+
# Simple example function
|
|
4
|
+
def f(x, y):
|
|
5
|
+
"Example function"
|
|
6
|
+
return x + y + 1
|
|
7
|
+
|
|
8
|
+
# Simple test for that function
|
|
9
|
+
test = testFunction(f) # line 9
|
|
10
|
+
case = test.case(1, 2)
|
|
11
|
+
case.checkReturnValue(3) # line 11
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Function that prints multiple lines of output
|
|
15
|
+
def display(message):
|
|
16
|
+
print("The message is:")
|
|
17
|
+
print('-' + message + '-')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# One test case with two lines of output
|
|
21
|
+
test = testFunction(display) # line 20
|
|
22
|
+
case = test.case('hello')
|
|
23
|
+
case.checkPrintedLines('The message is:', '-hello-') # line 22
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# A function that uses input
|
|
27
|
+
def askNameAge():
|
|
28
|
+
name = input("What is your name? ")
|
|
29
|
+
age = input("How old are you? ")
|
|
30
|
+
return (name, age)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
test = testFunction(askNameAge) # line 31
|
|
34
|
+
case = test.case()
|
|
35
|
+
case.provideInputs("Name", "thirty")
|
|
36
|
+
case.checkReturnValue(('Name', 'thirty')) # line 34
|
|
37
|
+
case.checkPrintedLines(
|
|
38
|
+
'What is your name? Name',
|
|
39
|
+
'How old are you? thirty' # line 37
|
|
40
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module docstring.
|
|
3
|
+
|
|
4
|
+
>>> 5
|
|
5
|
+
5
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
def f():
|
|
9
|
+
"""
|
|
10
|
+
Inner docstring.
|
|
11
|
+
|
|
12
|
+
>>> f()
|
|
13
|
+
5
|
|
14
|
+
"""
|
|
15
|
+
return 5
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class C:
|
|
19
|
+
"""
|
|
20
|
+
Class docstring.
|
|
21
|
+
|
|
22
|
+
>>> C().c(10)
|
|
23
|
+
5
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def c(self, n):
|
|
27
|
+
"""
|
|
28
|
+
Method docstring.
|
|
29
|
+
|
|
30
|
+
>>> c = C() # counts as an example
|
|
31
|
+
>>> c.c(10) # not a duplicate; different AST
|
|
32
|
+
5
|
|
33
|
+
"""
|
|
34
|
+
return n // 2
|