Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ matrix:
include:
- python: 2.7
env: TOX_ENV=py27
- python: 3.3
env: TOX_ENV=py33
- python: 3.4
env: TOX_ENV=py34
- python: 3.5
env: TOX_ENV=py35
install:
- "pip install tox coveralls"
script:
Expand Down
2 changes: 1 addition & 1 deletion dice/client/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _dispatch_events(self):
elif ch == ord('l'):
app.show_log = not app.show_log
elif ch == ord('s'):
app.last_item.save('saved_item.txt')
app.last_item.save('./saved_item.txt')
elif ch == ord('\t'):
cur_idx = self.panels.index(self.active_panel)
next_idx = (cur_idx + 1) % len(self.panels)
Expand Down
37 changes: 30 additions & 7 deletions dice/core/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import random
import re
import yaml
import shutil

from . import trace

Expand Down Expand Up @@ -89,14 +90,27 @@ def constrain(self, item):
self.item = item
self.status = {c.name: 'untouched'
for c in self.constraints}
cst_temp = self.constraints[:]
path_temp = None
while any(s == 'untouched' for s in self.status.values()):
for constraint in self.constraints:
if self._assumption_valid(constraint):
result = constraint.apply(item)
while len(cst_temp) > 0:
if self._assumption_valid(cst_temp[0]):
result = cst_temp[0].apply(item)
if result == "success":
if cst_temp[0].child is not None:
path_temp = os.path.join(self.provider.path,
'oracles',
cst_temp[0].child)
cst_temp += self._load_constraints(path_temp)

else:
result = 'skipped'

self.status[constraint.name] = result
self.status[cst_temp[0].name] = result
cst_temp.remove(cst_temp[0])
if path_temp is not None:
if os.path.isdir(path_temp):
shutil.rmtree(path_temp)


class Constraint(object):
Expand All @@ -106,7 +120,8 @@ class Constraint(object):
path_prefix = 'DPATH'

def __init__(self, name, provider,
depends_on=None, require=None, oracle=None):
depends_on=None, require=None, child=None, oracle=None,
fail_ratio=0.1, alpha=20, beta=1.8):
"""
:param name: Unique string name of the constraint.
:param depends_on: A logical expression shows prerequisite to apply
Expand All @@ -118,8 +133,11 @@ def __init__(self, name, provider,
self.provider = provider
self.depends_on = depends_on
self.require = require
self.child = child
self.oracle = oracle
self.fail_ratio = 0.1
self.fail_ratio = fail_ratio
self.alpha = alpha
self.beta = beta
self.traces = self._oracle2traces(oracle)

@classmethod
Expand Down Expand Up @@ -202,6 +220,9 @@ def _parse_if(node):
def _parse_assert(node):
cur_trace.append(node.test)

def _parse_expr(node):
cur_trace.append(node.value)

def _parse_block(nodes):
for node in nodes:
if isinstance(node, ast.If):
Expand All @@ -212,6 +233,8 @@ def _parse_block(nodes):
cur_trace.append(node)
traces.append(trace.Trace(self.provider, cur_trace))
cur_trace.pop()
elif isinstance(node, ast.Expr):
_parse_expr(node)
else:
raise ConstraintError(
'Unknown node type: %s' % node.__class__.__name__)
Expand Down Expand Up @@ -290,7 +313,7 @@ def _name2path(name):
return name[len(self.path_prefix):].replace('_', '/')

t = self._choose()
sols = t.solve(item)
sols = t.solve(item, self.alpha, self.beta)
for name, sol in sols.items():
item.set(_name2path(name), sol)

Expand Down
3 changes: 3 additions & 0 deletions dice/core/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ def get(self, path):
:return: Option value got.
"""
return getattr(self, path, None)

def save(self, path="./saved_item.txt"):
pass # TODO
31 changes: 15 additions & 16 deletions dice/core/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ def __init__(self, scope=None, excs=None, exc_types=None):
self.excs = excs
self.exc_types = exc_types

def generate(self):
def generate(self, alpha=20, beta=1.8):
"""
Generate a random instance of this symbol without considering scope,
excs or exc_types. Must be overridden.
"""
raise NotImplementedError("Method 'generate' not implemented for %s" %
self.__class__.__name__)

def model(self):
def model(self, alpha=20, beta=1.8):
"""
Generate a random instance of this symbol.
"""
if self.scope is None:
res = self.generate()
if self.excs is not None:
while res in self.excs:
res = self.generate()
res = self.generate(alpha, beta)
return res
else:
res = random.choice(self.scope)
Expand All @@ -49,35 +49,35 @@ class Bytes(SymbolBase):
"""
Symbol class for a string contains random bytes (1~255).
"""
def generate(self):
def generate(self, alpha=20, beta=1.8):
"""
Generate a random bytes string.
"""
cnt = int(random.weibullvariate(65535, 1))
cnt = int(random.weibullvariate(alpha, beta))
return ''.join(bt for bt in os.urandom(cnt) if bt != b'\x00')


class NonEmptyBytes(Bytes):
"""
Symbol class for a random byte(1-255) string except empty string.
"""
def generate(self):
def generate(self, alpha=20, beta=1.8):
"""
Generate a random non-empty bytes string.
"""
cnt = int(random.weibullvariate(65535, 1)) + 1
cnt = int(random.weibullvariate(alpha, beta)) + 1
return ''.join(bt for bt in os.urandom(cnt) if bt != b'\x00')


class String(Bytes):
"""
Symbol class for a random printable string.
"""
def generate(self):
def generate(self, alpha=20, beta=1.8):
"""
Generate a random printable string.
"""
cnt = int(random.weibullvariate(20, 1.8))
cnt = int(random.weibullvariate(alpha, beta))
return ''.join(random.choice(string.printable) for _ in range(cnt))


Expand All @@ -94,18 +94,18 @@ def __init__(self, scope=None, excs=None, exc_types=None):
super(StringList, self).__init__()
self.scopes = []

def generate(self):
def generate(self, alpha=20, beta=1.8):
"""
Generate a random printable strings.
"""
cnt = int(random.weibullvariate(20, 1.8))
cnt = int(random.weibullvariate(alpha, beta))
return ''.join(random.choice(string.printable) for _ in range(cnt))

def model(self):
def model(self, alpha=3, beta=1.8):
"""
Generate a random-numbered list contains random printable strings.
"""
cnt = int(random.weibullvariate(20, 1.8))
cnt = int(random.weibullvariate(alpha, beta))
res = set()
for _ in range(cnt):
entry = None
Expand Down Expand Up @@ -146,16 +146,15 @@ def __repr__(self):
minimum = '-Inf'
return '<%s %s~%s>' % (self.__class__.__name__, minimum, maximum)

def generate(self):
def generate(self, alpha=30, beta=1.1):
"""
Generate a random integer.
"""
scale = 50.0
maximum = self.maximum
minimum = self.minimum
while True:
sign = 1.0 if random.random() > 0.5 else -1.0
res = sign * (2.0 ** (random.expovariate(1.0 / scale)) - 1.0)
res = sign * (2.0 ** (random.weibullvariate(alpha, beta)) - 1.0)
if maximum is not None:
if maximum >= 0 and res > maximum + 1:
continue
Expand Down
16 changes: 10 additions & 6 deletions dice/core/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def __init__(self, provider, trace_list):
assert isinstance(ret, ast.Return)
self.result = ret.value.func.id.lower()
args = ret.value.args

self.result_patts = None
if args:
self.result_patts = args[0].s
Expand All @@ -55,7 +54,7 @@ def __repr__(self):
def _exec_call(self, node):
func_name = node.func.attr
pkg_name = node.func.value.id
mod_name = '.'.join([self.provider.name, 'utils', pkg_name])
mod_name = '.'.join([self.provider.name + '_utils', pkg_name])
mod = sys.modules[mod_name]
func = getattr(mod, func_name)
args = []
Expand Down Expand Up @@ -160,7 +159,10 @@ def _proc_compare(self, node):

def _proc_call(self, node):
func_name = node.func.id
assert func_name in ['any', 'all']
assert func_name in ['any', 'all', 'build']
if func_name == 'build':
self._exec_call(node.args[0])
return
assert isinstance(node.args[0], ast.Compare)
comp = node.args[0]
op = comp.ops[0].__class__.__name__
Expand Down Expand Up @@ -189,7 +191,7 @@ def _proc_call(self, node):
left = self._exec_call(left)
if func_name == 'all':
if op == 'In':
raise Exception('TODO')
pass # TODO
elif op == 'NotIn':
sym_right.excludes = left
elif func_name == 'any':
Expand All @@ -198,10 +200,12 @@ def _proc_call(self, node):
else:
raise TraceError('Unknown left type %s' % left)

def solve(self, item):
def solve(self, item, alpha=20, beta=1.8):
"""
Generate a satisfiable random option according to this trace.
:param item: Item to which generated option applies.
:param alpha: Alpha to Weibull distribution.
:param beta: Beta to Weibull distribution.
:return: Generated random option.
"""
self.item = item
Expand All @@ -215,7 +219,7 @@ def solve(self, item):
elif isinstance(node, ast.Return):
result = {}
for name, sym in self.symbols.items():
result[name] = sym.model()
result[name] = sym.model(alpha, beta)
return result
else:
raise TraceError('Unknown node type: %s' % type(node))
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# and then run "tox" from this directory.

[tox]
envlist = py27, py33, py34, pep8, pylint, docs
envlist = py27, py34, py35, pep8, pylint, docs

[testenv]
commands =
Expand Down