Skip to content

Commit 4dc2970

Browse files
committed
Added safer type handling
1 parent f22dc43 commit 4dc2970

File tree

3 files changed

+93
-55
lines changed

3 files changed

+93
-55
lines changed

test/tck/steps/bolt_compability_steps.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,30 @@
2424
from behave import *
2525

2626
from neo4j.v1 import GraphDatabase
27-
from test.tck import tck_util
28-
from test.tck.tck_util import to_unicode
27+
from test.tck.tck_util import to_unicode, Type, send_string, send_parameters, string_to_type
2928

3029
from neo4j.v1 import compat
3130
use_step_matcher("re")
3231

3332

3433
@given("A running database")
3534
def step_impl(context):
36-
tck_util.send_string("RETURN 1")
35+
send_string("RETURN 1")
3736

3837

3938
@given("a value (?P<input>.+) of type (?P<bolt_type>.+)")
4039
def step_impl(context, input, bolt_type):
41-
context.expected = get_bolt_value(bolt_type, input)
40+
context.expected = get_bolt_value(string_to_type(bolt_type), input)
4241

4342

4443
@given("a value of type (?P<bolt_type>.+)")
4544
def step_impl(context, bolt_type):
46-
context.expected = get_bolt_value(bolt_type, u' ')
45+
context.expected = get_bolt_value(string_to_type(bolt_type), u' ')
4746

4847

4948
@given("a list value (?P<input>.+) of type (?P<bolt_type>.+)")
5049
def step_impl(context, input, bolt_type):
51-
context.expected = get_list_from_feature_file(input, bolt_type)
50+
context.expected = get_list_from_feature_file(input, string_to_type(bolt_type))
5251

5352

5453
@given("an empty list L")
@@ -68,12 +67,12 @@ def step_impl(context, size):
6867

6968
@given("a List of size (?P<size>\d+) and type (?P<type>.+)")
7069
def step_impl(context, size, type):
71-
context.expected = get_list_of_random_type(int(size), type)
70+
context.expected = get_list_of_random_type(int(size), string_to_type(type))
7271

7372

7473
@given("a Map of size (?P<size>\d+) and type (?P<type>.+)")
7574
def step_impl(context, size, type):
76-
context.expected = get_dict_of_random_type(int(size), type)
75+
context.expected = get_dict_of_random_type(int(size), string_to_type(type))
7776

7877

7978
@step("adding a table of lists to the list L")
@@ -112,25 +111,22 @@ def step_impl(context):
112111

113112
@when("the driver asks the server to echo this value back")
114113
def step_impl(context):
115-
context.results = {}
116-
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
117-
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
114+
context.results = {"as_string": send_string("RETURN " + as_cypher_text(context.expected)),
115+
"as_parameters": send_parameters("RETURN {input}", {'input': context.expected})}
118116

119117

120118
@when("the driver asks the server to echo this list back")
121119
def step_impl(context):
122120
context.expected = context.L
123-
context.results = {}
124-
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
125-
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
121+
context.results = {"as_string": send_string("RETURN " + as_cypher_text(context.expected)),
122+
"as_parameters": send_parameters("RETURN {input}", {'input': context.expected})}
126123

127124

128125
@when("the driver asks the server to echo this map back")
129126
def step_impl(context):
130127
context.expected = context.M
131-
context.results = {}
132-
context.results["as_string"] = tck_util.send_string("RETURN " + as_cypher_text(context.expected))
133-
context.results["as_parameters"] = tck_util.send_parameters("RETURN {input}", {'input': context.expected})
128+
context.results = {"as_string": send_string("RETURN " + as_cypher_text(context.expected)),
129+
"as_parameters": send_parameters("RETURN {input}", {'input': context.expected})}
134130

135131

136132
@step("the value given in the result should be the same as what was sent")
@@ -178,15 +174,15 @@ def step_impl(context):
178174

179175

180176
def get_bolt_value(type, value):
181-
if type == 'Integer':
177+
if type == Type.INTEGER:
182178
return int(value)
183-
if type == 'Float':
179+
if type == Type.FLOAT:
184180
return float(value)
185-
if type == 'String':
181+
if type == Type.STRING:
186182
return to_unicode(value)
187-
if type == 'Null':
183+
if type == Type.NULL:
188184
return None
189-
if type == 'Boolean':
185+
if type == Type.BOOLEAN:
190186
return bool(value)
191187
raise ValueError('No such type : %s' % type)
192188

@@ -242,19 +238,19 @@ def _get_random_func(type):
242238
def get_none():
243239
return None
244240

245-
if type == 'Integer':
241+
if type == Type.INTEGER:
246242
fu = random.randint
247243
args = [-9223372036854775808, 9223372036854775808]
248-
elif type == 'Float':
244+
elif type == Type.FLOAT:
249245
fu = random.random
250246
args = []
251-
elif type == 'String':
247+
elif type == Type.STRING:
252248
fu = get_random_string
253249
args = [3]
254-
elif type == 'Null':
250+
elif type == Type.NULL:
255251
fu = get_none
256252
args = []
257-
elif type == 'Boolean':
253+
elif type == Type.BOOLEAN:
258254
fu = get_random_bool
259255
args = []
260256
else:

test/tck/steps/cypher_compability_steps.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,19 @@
2323
from behave import *
2424

2525
from neo4j.v1 import compat, Node, Relationship, Path
26-
from test.tck import tck_util
27-
from test.tck.tck_util import Value
26+
from test.tck.tck_util import Value, Type, string_to_type, send_string, send_parameters
2827

2928
use_step_matcher("re")
3029

3130

3231
@given("init: (?P<statement>.+);")
3332
def step_impl(context, statement):
34-
tck_util.send_string(statement)
33+
send_string(statement)
3534

3635

3736
@when("running: (?P<statement>.+);")
3837
def step_impl(context, statement):
39-
context.results = {"as_string": tck_util.send_string(statement)}
38+
context.results = {"as_string": send_string(statement)}
4039

4140

4241
@then("result should be (?P<type>.+)\(s\)")
@@ -55,12 +54,18 @@ def step_impl(context):
5554
assert len(result) == 0
5655

5756

58-
@then("result should be mixed: (?P<types>.+)")
59-
def step_impl(context, types):
57+
@then("result should map to types")
58+
def step_impl(context):
59+
keys = context.table.headings
60+
values = context.table.rows[0]
61+
context.types = {keys[i]: values[i] for i in range(len(keys))}
62+
63+
64+
@then("result should be mixed")
65+
def step_impl(context):
6066
result = context.results["as_string"]
6167
given = driver_result_to_comparable_result(result)
62-
types = get_properties(types)[0]
63-
expected = table_to_comparable_result(context.table, types)
68+
expected = table_to_comparable_result(context.table, context.types)
6469
if given != expected:
6570
raise Exception("Mixed response does not match given: %s expected: %s" % (given, expected))
6671

@@ -78,7 +83,7 @@ def step_impl(context, statement):
7883
val = int(v)
7984
parameters[keys[i]] = val
8085

81-
context.results = {"as_string": tck_util.send_parameters(statement, parameters)}
86+
context.results = {"as_string": send_parameters(statement, parameters)}
8287

8388

8489
def get_properties(prop):
@@ -181,15 +186,15 @@ def get_path(string_path):
181186

182187
def _string_value_to_comparable(val, type):
183188
def get_val(v):
184-
if type == "integer":
189+
if type == Type.INTEGER:
185190
return Value(int(v))
186-
elif type == "string":
191+
elif type == Type.STRING:
187192
return Value(v)
188-
elif type == "node":
193+
elif type == Type.NODE:
189194
return Value(get_node(v)[0])
190-
elif type == "relationship":
195+
elif type == Type.RELATIONSHIP:
191196
return Value(get_relationship(v)[0])
192-
elif type == "path":
197+
elif type == Type.PATH:
193198
return Value(get_path(v)[0])
194199
else:
195200
raise ValueError("Not recognized type: %s" % type)
@@ -198,7 +203,7 @@ def get_val(v):
198203
if val == 'null':
199204
return Value(None)
200205
if val[0] == '[':
201-
if type != "relationship" or (type == "relationship" and val[1] == '['):
206+
if type != Type.RELATIONSHIP or (type == Type.RELATIONSHIP and val[1] == '['):
202207
val = val[1:-1].split(", ")
203208
if isinstance(val, list):
204209
return tuple([get_val(v) for v in val])
@@ -217,14 +222,15 @@ def table_to_comparable_result(table, types):
217222
result = []
218223
keys = table.headings
219224
if isinstance(types, compat.string):
220-
types = {key: types for key in keys}
225+
types = {key: string_to_type(types) for key in keys}
221226
elif isinstance(types, dict):
222227
assert set(types.keys()) == set(keys)
223228
else:
224229
raise ValueError("types must be either string of single type or map of types corresponding to result keys Got:"
225230
" %s" % types)
226231
for row in table:
227-
result.append({keys[i]: _string_value_to_comparable(row[i], types[keys[i]]) for i in range(len(row))})
232+
result.append(
233+
{keys[i]: _string_value_to_comparable(row[i], string_to_type(types[keys[i]])) for i in range(len(row))})
228234
return result
229235

230236

test/tck/tck_util.py

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,39 @@ def to_unicode(val):
4646
return str(val)
4747

4848

49+
def string_to_type(str):
50+
str = str.upper()
51+
if str == Type.INTEGER.upper():
52+
return Type.INTEGER
53+
elif str == Type.FLOAT.upper():
54+
return Type.FLOAT
55+
elif str == Type.BOOLEAN.upper():
56+
return Type.BOOLEAN
57+
elif str == Type.NULL.upper():
58+
return Type.NULL
59+
elif str == Type.STRING.upper():
60+
return Type.STRING
61+
elif str == Type.NODE.upper():
62+
return Type.NODE
63+
elif str == Type.RELATIONSHIP.upper():
64+
return Type.RELATIONSHIP
65+
elif str == Type.PATH.upper():
66+
return Type.PATH
67+
else:
68+
raise ValueError("Not recognized type: %s" % str)
69+
70+
71+
class Type:
72+
INTEGER = "Integer"
73+
FLOAT = "Float"
74+
BOOLEAN = "Boolean"
75+
STRING = "String"
76+
NODE = "Node"
77+
RELATIONSHIP = "Relationship"
78+
PATH = "Path"
79+
NULL = "Null"
80+
81+
4982
class Value:
5083
content = None
5184

@@ -57,10 +90,11 @@ def __init__(self, entity):
5790
self.content = self.create_relationship(entity)
5891
elif isinstance(entity, Path):
5992
self.content = self.create_path(entity)
60-
elif isinstance(entity, int) or isinstance(entity, float) or isinstance(entity, (str, compat.string)) or entity is None:
93+
elif isinstance(entity, int) or isinstance(entity, float) or isinstance(entity,
94+
(str, compat.string)) or entity is None:
6195
self.content['value'] = entity
6296
else:
63-
raise ValueError("Do not support object type: %s" %entity)
97+
raise ValueError("Do not support object type: %s" % entity)
6498

6599
def __hash__(self):
66100
return hash(repr(self))
@@ -72,38 +106,40 @@ def __eq__(self, other):
72106
def __repr__(self):
73107
return str(self.content)
74108

75-
def create_node(self,entity):
109+
def create_node(self, entity):
76110
content = {'properties': entity.properties, 'labels': entity.labels, 'obj': "node"}
77111

78112
return content
79113

80-
def create_path(self,entity):
114+
def create_path(self, entity):
81115
content = {}
82116
prev_id = entity.start.identity
83117
p = []
84118
for i, rel in enumerate(list(entity)):
85-
n = entity.nodes[i+1]
119+
n = entity.nodes[i + 1]
86120
current_id = n.identity
87121
if rel.start == prev_id and rel.end == current_id:
88122
rel.start = i
89-
rel.end = i+1
123+
rel.end = i + 1
90124
elif rel.start == current_id and rel.end == prev_id:
91-
rel.start = i+1
125+
rel.start = i + 1
92126
rel.end = i
93127
else:
94-
raise ValueError("Relationships end and start should point to surrounding nodes. Rel: %s N1id: %s N2id: %s. At entity#%s" % (rel, current_id, prev_id, i))
95-
p += [self.create_relationship(rel, True),self.create_node(n)]
128+
raise ValueError(
129+
"Relationships end and start should point to surrounding nodes. Rel: %s N1id: %s N2id: %s. At entity#%s" % (
130+
rel, current_id, prev_id, i))
131+
p += [self.create_relationship(rel, True), self.create_node(n)]
96132
prev_id = current_id
97133
content['path'] = p
98134
content['obj'] = "path"
99135
content['start'] = self.create_node(entity.start)
100136
return content
101137

102-
def create_relationship(self,entity, include_start_end=False):
138+
def create_relationship(self, entity, include_start_end=False):
103139
content = {'obj': "relationship"}
104140
if include_start_end:
105141
self.content['start'] = entity.start
106142
self.content['end'] = entity.end
107143
content['type'] = entity.type
108144
content['properties'] = entity.properties
109-
return content
145+
return content

0 commit comments

Comments
 (0)