import unittest
from stone.frontend.ast import (
AstExample,
AstExampleField,
AstExampleRef,
)
from stone.ir import (
ApiNamespace,
Boolean,
Float32,
Float64,
Int32,
Int64,
InvalidSpec,
List,
Map,
ParameterError,
String,
Timestamp,
UInt32,
UInt64,
Void,
)
from stone.ir import (
Struct,
StructField,
Union,
UnionField,
)
class TestStoneInternal(unittest.TestCase):
def test_check_example(self):
s = String(min_length=1, max_length=5)
s.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value='hello',
))
with self.assertRaises(InvalidSpec) as cm:
s.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value='',
))
self.assertIn("'' has fewer than 1 character(s)", cm.exception.msg)
l1 = List(String(min_length=1), min_items=1, max_items=3)
l1.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value=['asd'],
))
with self.assertRaises(InvalidSpec) as cm:
l1.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value=[],
))
self.assertIn("has fewer than 1 item(s)", cm.exception.msg)
l1 = List(List(String(min_length=1), min_items=1))
l1.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value=[['asd']],
))
with self.assertRaises(InvalidSpec) as cm:
l1.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value=[[]],
))
self.assertIn("has fewer than 1 item(s)", cm.exception.msg)
m = Map(String(), String())
m.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value={"foo": "bar"}
)
)
with self.assertRaises(InvalidSpec):
m.check_example(
AstExampleField(
path='test.stone',
lineno=1,
lexpos=0,
name='v',
value={1: "bar"}
)
)
with self.assertRaises(ParameterError):
Map(Int32(), String())
s = Struct('S', None, None)
s.set_attributes(
"Docstring",
[
StructField('a', UInt64(), 'a field', None),
StructField('b', List(String()), 'a field', None),
],
)
s._add_example(
AstExample(
'test.stone',
lineno=1,
lexpos=0,
label='default',
text='Default example',
fields={
'a': AstExampleField(
path='test.stone',
lineno=2,
lexpos=0,
name='a',
value=132,
),
'b': AstExampleField(
path='test.stone',
lineno=2,
lexpos=0,
name='b',
value=['a'],
),
}
))
def test_string(self):
s = String(min_length=1, max_length=3)
s.check('1')
s.check('\u2650')
with self.assertRaises(ValueError) as cm:
s.check(99)
self.assertIn('not a valid string', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
s.check('12345')
self.assertIn('more than 3 character(s)', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
s.check('')
self.assertIn('fewer than 1 character(s)', cm.exception.args[0])
def test_int(self):
i = Int32()
i.check(42)
with self.assertRaises(ValueError) as cm:
i.check(2**31)
self.assertIn('not within range', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
i.check(-2**31 - 1)
self.assertIn('not within range', cm.exception.args[0])
i = UInt32()
with self.assertRaises(ValueError) as cm:
i.check(2**32)
self.assertIn('not within range', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
i.check(-1)
self.assertIn('not within range', cm.exception.args[0])
i = Int64()
with self.assertRaises(ValueError) as cm:
i.check(2**63)
self.assertIn('not within range', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
i.check(-2**63 - 1)
self.assertIn('not within range', cm.exception.args[0])
i = UInt64()
with self.assertRaises(ValueError) as cm:
i.check(2**64)
self.assertIn('not within range', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
i.check(-1)
self.assertIn('not within range', cm.exception.args[0])
i = Int64(min_value=0, max_value=10)
with self.assertRaises(ValueError) as cm:
i.check(20)
self.assertIn('20 is greater than 10', cm.exception.args[0])
with self.assertRaises(ValueError) as cm:
i.check(-5)
self.assertIn('-5 is less than 0', cm.exception.args[0])
self.assertRaises(ParameterError, lambda: Int64(min_value=0.1))
self.assertRaises(ParameterError, lambda: Int64(max_value='10'))
def test_boolean(self):
b = Boolean()
b.check(True)
with self.assertRaises(ValueError) as cm:
b.check('true')
self.assertIn('not a valid boolean', cm.exception.args[0])
def test_float(self):
f = Float32()
f.check(3.14)
with self.assertRaises(ValueError) as cm:
f.check('1.1')
self.assertIn('not a valid real', cm.exception.args[0])
f = Float64(min_value=0, max_value=100)
with self.assertRaises(ValueError) as cm:
f.check(101)
self.assertIn('is greater than', cm.exception.args[0])
with self.assertRaises(ParameterError) as cm:
Float64(min_value=0, max_value=10**330)
self.assertIn('too large for a float', cm.exception.args[0])
with self.assertRaises(ParameterError) as cm:
Float32(min_value=0, max_value=10**50)
self.assertIn('greater than the maximum value', cm.exception.args[0])
self.assertRaises(ParameterError, lambda: Float64(min_value=1j))
self.assertRaises(ParameterError, lambda: Float64(max_value='10'))
def test_timestamp(self):
t = Timestamp('%a, %d %b %Y %H:%M:%S')
t.check('Sat, 21 Aug 2010 22:31:20')
with self.assertRaises(ValueError) as cm:
t.check('Sat, 21 Aug 2010')
self.assertIn('does not match format', cm.exception.args[0])
def test_struct(self):
ns = ApiNamespace('test')
quota_info = Struct(
'QuotaInfo',
None,
ns,
)
quota_info.set_attributes(
"Information about a user's space quota.",
[
StructField('quota', UInt64(), 'Total amount of space.', None),
],
)
with self.assertRaises(InvalidSpec) as cm:
quota_info._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='default',
text=None,
fields={
'bad_field': AstExampleField(
None,
None,
None,
'bad_field',
'xyz123')}))
self.assertIn('has unknown field', cm.exception.msg)
quota_info._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='default',
text=None,
fields={
'quota': AstExampleField(
None,
None,
None,
'quota',
64000)}))
with self.assertRaises(InvalidSpec) as cm:
quota_info._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='null',
text=None,
fields={
'quota': AstExampleField(
None,
None,
None,
'quota',
None)}))
self.assertEqual(
"Bad example for field 'quota': null is not a valid integer",
cm.exception.msg)
self.assertTrue(quota_info._has_example('default'))
quota_info.nullable = True
account_info = Struct(
'AccountInfo',
None,
ns,
)
account_info.set_attributes(
"Information about an account.",
[
StructField('account_id', String(), 'Unique identifier for account.', None),
StructField('quota_info', quota_info, 'Quota', None)
],
)
account_info._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='default',
text=None,
fields={
'account_id': AstExampleField(
None,
None,
None,
'account_id',
'xyz123'),
'quota_info': AstExampleField(
None,
None,
None,
'quota_info',
AstExampleRef(
None,
None,
None,
'default'))})
)
account_info._compute_examples()
self.assertIn('quota_info', account_info.get_examples()['default'].value)
def test_union(self):
ns = ApiNamespace('files')
update_parent_rev = Struct(
'UpdateParentRev',
None,
ns,
)
update_parent_rev.set_attributes(
"Overwrite existing file if the parent rev matches.",
[
StructField('parent_rev', String(), 'The revision to be updated.', None)
],
)
update_parent_rev._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='default',
text=None,
fields={
'parent_rev': AstExampleField(
None,
None,
None,
'parent_rev',
'xyz123')}))
conflict = Union(
'WriteConflictPolicy',
None,
ns,
True,
)
conflict.set_attributes(
'Policy for managing write conflicts.',
[
UnionField(
'reject', Void(),
'On a write conflict, reject the new file.', None),
UnionField(
'overwrite', Void(),
'On a write conflict, overwrite the existing file.', None),
UnionField(
'update_if_matching_parent_rev', update_parent_rev,
'On a write conflict, overwrite the existing file.', None),
],
)
conflict._add_example(
AstExample(
path=None,
lineno=None,
lexpos=None,
label='default',
text=None,
fields={
'update_if_matching_parent_rev': AstExampleField(
None,
None,
None,
'update_if_matching_parent_rev',
AstExampleRef(None, None, None, 'default'))}))
conflict._compute_examples()
self.assertEqual(conflict.get_examples()['reject'].value, {'.tag': 'reject'})
self.assertEqual(conflict.get_examples()['default'].value,
{'.tag': 'update_if_matching_parent_rev', 'parent_rev': 'xyz123'})
if __name__ == '__main__':
unittest.main()