Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
asn1-value-editor
Commits
0a457745
Commit
0a457745
authored
Aug 16, 2016
by
Maxime Perrotin
Browse files
ValueGenerator fills up ctypes instances
parent
cdcfd4e8
Changes
3
Hide whitespace changes
Inline
Side-by-side
asn1_value_editor/ValueGenerator.py
View file @
0a457745
...
...
@@ -17,6 +17,7 @@
__all__
=
[
'compute_random_value'
,
'compute_combinations'
]
import
sys
import
random
import
itertools
import
opengeode
...
...
@@ -84,73 +85,105 @@ def compute_random_sequenceof(asn1_ty, pool):
# Set of functions used by the simulator to compute the combination input
# parameters for each ASN.1 data type. Yield ASN.1 Value Notation strings
# ASN.1 types must be in the format generated by ASN1SCC Python backend
def
compute_combinations
(
asn1_ty
,
pool
):
# dest is a ctypes instance of the corresponding ASN.1 type
# offset is an optional state to apply to dest using the Reset(offset)
def
compute_combinations
(
asn1_ty
,
pool
,
dest
,
offset
=
None
):
''' Top-level, type-dispatching function
"pool" is the set of types, found in the process.dataview attribute '''
basic
=
opengeode
.
ogParser
.
find_basic_type
(
asn1_ty
.
type
,
pool
)
state
=
dest
.
GetState
()
if
offset
:
dest
.
Reset
(
offset
)
# Python2 has no "yield from"...
if
basic
.
kind
.
startswith
(
'Integer'
):
for
each
in
compute_integer_combinations
(
basic
):
for
each
in
compute_integer_combinations
(
basic
,
dest
=
dest
):
yield
each
elif
basic
.
kind
==
'BooleanType'
:
for
each
in
compute_boolean_combinations
(
basic
):
for
each
in
compute_boolean_combinations
(
basic
,
dest
):
yield
each
elif
basic
.
kind
.
startswith
(
'Real'
):
for
each
in
compute_real_combinations
(
basic
):
for
each
in
compute_real_combinations
(
basic
,
dest
):
yield
each
elif
basic
.
kind
==
'EnumeratedType'
:
for
each
in
compute_enumerated_combinations
(
basic
):
for
each
in
compute_enumerated_combinations
(
basic
,
dest
):
yield
each
elif
basic
.
kind
==
'ChoiceType'
:
for
each
in
compute_choice_combinations
(
basic
,
pool
):
for
each
in
compute_choice_combinations
(
basic
,
pool
,
dest
):
yield
each
elif
basic
.
kind
in
(
'SequenceType'
,
'SetType'
):
for
each
in
compute_sequence_combinations
(
basic
,
pool
):
for
each
in
compute_sequence_combinations
(
basic
,
pool
,
dest
):
yield
each
elif
basic
.
kind
in
(
'SequenceOfType'
,
'SetOfType'
):
for
each
in
compute_sequenceof_combinations
(
basic
,
pool
):
for
each
in
compute_sequenceof_combinations
(
basic
,
pool
,
dest
):
yield
each
elif
basic
.
kind
.
endswith
(
'StringType'
):
# Strings
for
n
in
xrange
(
int
(
basic
.
Min
),
int
(
basic
.
Max
)
+
1
):
yield
'"'
+
'X'
*
n
+
'"'
dest
.
Reset
(
state
)
def
compute_integer_combinations
(
asn1_ty
,
max_iter
=
0
):
def
compute_integer_combinations
(
asn1_ty
,
dest
,
max_iter
=
0
):
''' Generator returning all integer values, with optional limit '''
state
=
dest
.
GetState
()
# Do not use xrange, it needs a value that fits in a C long
max_iter
=
(
long
(
asn1_ty
.
Min
)
+
max_iter
)
if
max_iter
!=
0
else
long
(
asn1_ty
.
Max
)
for
each
in
itertools
.
count
(
long
(
asn1_ty
.
Min
)):
if
each
>
max_iter
:
break
dest
.
Set
(
each
)
yield
str
(
each
)
dest
.
Reset
(
state
)
def
compute_real_combinations
(
asn1_ty
):
def
compute_real_combinations
(
asn1_ty
,
dest
):
''' Generator returning three real values only (set is infinite) '''
state
=
dest
.
GetState
()
dest
.
Set
(
float
(
asn1_ty
.
Min
))
yield
asn1_ty
.
Min
dest
.
Reset
(
state
)
dest
.
Set
((
float
(
asn1_ty
.
Max
)
+
float
(
asn1_ty
.
Min
))
/
2.0
)
yield
str
((
float
(
asn1_ty
.
Max
)
+
float
(
asn1_ty
.
Min
))
/
2.0
)
dest
.
Reset
(
state
)
dest
.
Set
(
float
(
asn1_ty
.
Max
))
yield
asn1_ty
.
Max
dest
.
Reset
(
state
)
def
compute_boolean_combinations
(
asn1_ty
):
def
compute_boolean_combinations
(
asn1_ty
,
dest
):
''' Generator returning all combinations of boolean '''
state
=
dest
.
GetState
()
dest
.
Set
(
True
)
yield
'TRUE'
dest
.
Reset
(
state
)
dest
.
Set
(
False
)
yield
'FALSE'
dest
.
Reset
(
state
)
def
compute_enumerated_combinations
(
asn1_ty
):
def
compute_enumerated_combinations
(
asn1_ty
,
dest
):
''' Generator returning all combinations of enumerated '''
DV
=
sys
.
modules
[
dest
.
__module__
].
DV
state
=
dest
.
GetState
()
for
each
in
asn1_ty
.
EnumValues
.
viewkeys
():
enum_id
=
asn1_ty
.
EnumValues
[
each
].
EnumID
dest
.
Set
(
getattr
(
DV
,
enum_id
.
replace
(
'-'
,
'_'
)))
dest
.
Reset
(
state
)
yield
each
def
compute_choice_combinations
(
asn1_ty
,
pool
):
def
compute_choice_combinations
(
asn1_ty
,
pool
,
dest
):
''' Generator returning all combinations of choice components '''
state
=
dest
.
GetState
()
DV
=
sys
.
modules
[
dest
.
__module__
].
DV
for
discr
,
value_ty
in
asn1_ty
.
Children
.
viewitems
():
for
each
in
compute_combinations
(
value_ty
,
pool
):
enum_id
=
asn1_ty
.
Children
[
discr
].
EnumID
dest
.
kind
.
Set
(
getattr
(
DV
,
enum_id
.
replace
(
'-'
,
'_'
)))
dest
=
getattr
(
dest
,
discr
.
replace
(
'-'
,
'_'
))
for
each
in
compute_combinations
(
value_ty
,
pool
,
dest
):
yield
'{}: {}'
.
format
(
discr
,
each
)
dest
.
Reset
(
state
)
def
myproduct
(
*
iterables
):
...
...
@@ -164,12 +197,21 @@ def myproduct(*iterables):
for
items
in
myproduct
(
*
iterables
[
1
:]):
yield
(
item
,
)
+
items
def
compute_sequence_combinations
(
asn1_ty
,
pool
):
def
compute_sequence_combinations
(
asn1_ty
,
pool
,
dest
):
''' Generator returning all combinations of SEQUENCE types '''
# Prepare generators to compute combinations of each field
# Using partial (closure) here allows to have "resettable" generators
elems
=
[
partial
(
compute_combinations
,
sort
,
pool
)
for
sort
in
asn1_ty
.
Children
.
viewvalues
()]
state
=
dest
.
GetState
()
# elems = [partial(compute_combinations, sort, pool, dest)
# for sort in asn1_ty.Children.viewvalues()]
elems
=
[]
for
field
,
sort
in
asn1_ty
.
Children
.
viewitems
():
# move the ctypes pointer to the position of the field
getattr
(
dest
,
field
.
replace
(
'-'
,
'_'
))
offset
=
dest
.
GetState
()
dest
.
Reset
(
state
)
elems
.
append
(
partial
(
compute_combinations
,
sort
,
pool
,
dest
,
offset
))
for
each
in
myproduct
(
*
elems
):
# each is a tuple with values for the sequence, join with fieldnames
...
...
@@ -177,13 +219,26 @@ def compute_sequence_combinations(asn1_ty, pool):
res
=
(
'{} {}'
.
format
(
name
,
value
)
for
name
,
value
in
pairs
)
res_yield
=
'{{ {} }}'
.
format
(
', '
.
join
(
res
))
yield
res_yield
dest
.
Reset
(
state
)
def
compute_sequenceof_combinations
(
asn1_ty
,
pool
):
def
compute_sequenceof_combinations
(
asn1_ty
,
pool
,
dest
):
''' Generator returning all combinations of arrays '''
state
=
dest
.
GetState
()
for
size
in
xrange
(
int
(
asn1_ty
.
Min
),
int
(
asn1_ty
.
Max
)
+
1
):
elems
=
[
partial
(
compute_combinations
,
asn1_ty
,
pool
)
for
_
in
xrange
(
size
)]
dest
.
SetLength
(
size
)
dest
.
Reset
(
state
)
# elems = [partial(compute_combinations, asn1_ty, pool, dest)
# for _ in xrange(size)]
elems
=
[]
for
idx
in
xrange
(
size
):
# move the ctypes pointer to the right position in the array
dest
[
idx
]
offset
=
dest
.
GetState
()
dest
.
Reset
(
state
)
elems
.
append
(
partial
(
compute_combinations
,
asn1_ty
,
pool
,
dest
,
offset
))
for
each
in
myproduct
(
*
elems
):
res
=
'{{ {} }}'
.
format
(
', '
.
join
(
each
))
yield
res
dest
.
Reset
(
state
)
asn1_value_editor/sdlHandler.py
View file @
0a457745
...
...
@@ -669,16 +669,18 @@ class sdlHandler(QObject):
the resulting state hash plus the transition that caused it
This function does not filter out the states that were already
visited - it is exhaustive. '''
def
exhaust_interface
(
name
,
asn1_ty
):
def
exhaust_interface
(
name
,
asn1_ty
=
None
,
asn1_inst
=
None
):
''' For all combinations of a given interface parameter, execute
the PI, save the resulting state, undo, and yield the state '''
if
asn1_ty
:
print
'Exhausting'
,
name
for
arg
in
compute_combinations
(
asn1_ty
,
self
.
proc
.
dataview
):
self
.
click_tc
(
name
,
arg
)
for
arg_gser
in
compute_combinations
(
asn1_ty
,
self
.
proc
.
dataview
,
asn1_inst
):
self
.
click_tc
(
name
,
arg_gser
)
new_hash
=
self
.
current_hash
self
.
undo
()
yield
new_hash
,
(
name
,
arg
)
yield
new_hash
,
(
name
,
arg
_gser
)
else
:
self
.
click_tc
(
name
)
new_hash
=
self
.
current_hash
...
...
@@ -686,13 +688,15 @@ class sdlHandler(QObject):
yield
new_hash
,
(
name
,
None
)
for
name
in
self
.
active_tc
:
# Start from the current state
asn1_ty
=
None
asn1_ty
,
asn1_inst
=
None
,
None
for
inp
in
self
.
proc
.
input_signals
:
if
inp
[
'name'
].
lower
()
==
name
.
lower
():
sort
=
inp
.
get
(
'type'
,
None
)
if
sort
:
asn1_ty
=
self
.
proc
.
dataview
[
sort
.
ReferencedTypeName
]
for
each
in
exhaust_interface
(
name
,
asn1_ty
):
asn1_inst
=
getattr
(
ASN1
,
sort
.
ReferencedTypeName
.
replace
(
'-'
,
'_'
))()
for
each
in
exhaust_interface
(
name
,
asn1_ty
,
asn1_inst
):
yield
each
def
breadth_first
(
self
,
max_states
=
1000
):
...
...
test/pytest/test_valuegenerator.py
View file @
0a457745
...
...
@@ -10,10 +10,7 @@ from asn1_value_editor.ValueGenerator import (compute_random_value,
from
asn1_value_editor.vn
import
fromValueNotationToPySide
as
parse_gser
from
opengeode
import
Asn1scc
as
asn1scc
'''
Use py.test-2.7 to run these tests
'''
asn1scc
.
LOG
.
setLevel
(
asn1scc
.
logging
.
DEBUG
)
TEST
=
[
'data/dv1.asn'
]
...
...
@@ -22,7 +19,9 @@ dataview = asn1scc.parse_asn1(TEST,
ast_version
=
asn1scc
.
ASN1
.
UniqueEnumeratedNames
,
flags
=
[
asn1scc
.
ASN1
.
AstOnly
])
pool
=
dataview
.
types
ASN1
=
asn1scc
.
asn2dataModel
(
*
TEST
)
CName
=
lambda
name
:
name
.
replace
(
'-'
,
'_'
)
Inst
=
lambda
name
:
getattr
(
ASN1
,
CName
(
name
))()
def
test_random_bool
():
''' Test boolean values '''
...
...
@@ -37,7 +36,7 @@ def test_random_bool():
def
test_exhaustive_bool
():
''' Test boolean values '''
typeName
=
"Type-SingleBool"
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
))
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
))
assert
result
==
[
'TRUE'
,
'FALSE'
]
def
test_random_int
():
...
...
@@ -50,7 +49,7 @@ def test_random_int():
def
test_exhaustive_int
():
''' Test integer value '''
typeName
=
"Type-SingleInt"
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
))
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
))
assert
result
==
[
str
(
i
)
for
i
in
range
(
256
)]
def
test_random_real
():
...
...
@@ -63,7 +62,7 @@ def test_random_real():
def
test_exhaustive_real
():
''' Test float value '''
typeName
=
"Type-SingleReal"
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
))
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
))
asFloat
=
[
float
(
i
)
for
i
in
result
]
assert
asFloat
==
[
-
5.0
,
0.0
,
5.0
]
...
...
@@ -80,7 +79,7 @@ def test_random_enum():
def
test_exhaustive_enum
():
''' Test enumerated value '''
typeName
=
"Type-SingleEnum"
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
))
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
))
assert
result
==
[
'enum-one'
,
'enum-two'
]
def
test_random_string
():
...
...
@@ -93,7 +92,7 @@ def test_random_string():
def
test_exhaustive_string
():
''' Test octet string value '''
typeName
=
"Type-SingleString"
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
))
result
=
list
(
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
))
expected_len
=
[
i
+
2
for
i
in
range
(
21
)]
assert
result
[
0
]
==
'""'
assert
result
[
1
]
==
'"X"'
...
...
@@ -114,7 +113,7 @@ def test_exhaustive_tinysequence():
typeName
=
"Type-TinySeq"
expected
=
[{
'a'
:
1
,
'b'
:
True
},
{
'a'
:
1
,
'b'
:
False
},
{
'a'
:
2
,
'b'
:
True
},
{
'a'
:
2
,
'b'
:
False
}]
for
each
in
compute_combinations
(
pool
[
typeName
],
pool
):
for
each
in
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
):
value
=
parse_gser
(
'result'
,
each
)[
'result'
]
assert
value
in
expected
expected
.
remove
(
value
)
...
...
@@ -138,7 +137,7 @@ def test_random_simplechoice():
def
test_exhaustive_simplechoice
():
''' Test simple choice (only made of basic types, not sequences '''
typeName
=
"Type-SingleChoice"
result
=
compute_combinations
(
pool
[
typeName
],
pool
)
result
=
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
)
choiceA
=
choiceB
=
choiceC
=
0
expected
=
{
'choice-A'
:
range
(
256
),
'choice-B'
:
[
True
,
False
],
...
...
@@ -165,7 +164,7 @@ def test_random_simpleseqof():
def
test_exhaustive_tinyseqof
():
''' Test SEQOF '''
typeName
=
"Type-TinySeqOf"
# Size-2 seq of boolean -> 00 01 10 11
result
=
compute_combinations
(
pool
[
typeName
],
pool
)
result
=
compute_combinations
(
pool
[
typeName
],
pool
,
Inst
(
typeName
)
)
expected
=
[[
False
,
False
],
[
False
,
True
],
[
True
,
False
],
[
True
,
True
]]
for
each
in
result
:
value
=
parse_gser
(
'result'
,
each
)[
'result'
]
...
...
Write
Preview
Supports
Markdown
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