emery 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/emery.rb +6 -0
- data/lib/emery/dataclass.rb +86 -0
- data/lib/emery/enum.rb +101 -0
- data/lib/emery/jsoner.rb +188 -0
- data/lib/emery/tod.rb +262 -0
- data/lib/emery/type.rb +176 -0
- data/test/dataclass_test.rb +115 -0
- data/test/enum_test.rb +47 -0
- data/test/jsoner_test.rb +239 -0
- data/test/tod_test.rb +41 -0
- data/test/type_test.rb +185 -0
- metadata +67 -0
data/lib/emery/type.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
module Emery
|
2
|
+
module T
|
3
|
+
def T.check_not_nil(type, value)
|
4
|
+
if value == nil
|
5
|
+
raise TypeError.new("Type #{type.to_s} does not allow nil value")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class UntypedType
|
10
|
+
def to_s
|
11
|
+
"Untyped"
|
12
|
+
end
|
13
|
+
def check(value)
|
14
|
+
T.check_not_nil(self, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Nilable
|
19
|
+
attr_reader :type
|
20
|
+
def initialize(type)
|
21
|
+
@type = type
|
22
|
+
end
|
23
|
+
def to_s
|
24
|
+
"Nilable[#{type.to_s}]"
|
25
|
+
end
|
26
|
+
def check(value)
|
27
|
+
if value != nil
|
28
|
+
T.check(type, value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def ==(other)
|
32
|
+
T.instance_of?(Nilable, other) and self.type == other.type
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class AnyType
|
37
|
+
attr_reader :types
|
38
|
+
def initialize(*types)
|
39
|
+
@types = types
|
40
|
+
end
|
41
|
+
def to_s
|
42
|
+
"Any[#{types.map { |t| t.to_s}.join(', ')}]"
|
43
|
+
end
|
44
|
+
def check(value)
|
45
|
+
types.each do |type|
|
46
|
+
begin
|
47
|
+
T.check(type, value)
|
48
|
+
return
|
49
|
+
rescue TypeError
|
50
|
+
end
|
51
|
+
end
|
52
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - any of #{@types.map { |t| t.to_s}.join(', ')} required")
|
53
|
+
end
|
54
|
+
def ==(other)
|
55
|
+
T.instance_of?(AnyType, other) and (self.types - other.types).empty?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ArrayType
|
60
|
+
attr_reader :item_type
|
61
|
+
def initialize(item_type)
|
62
|
+
@item_type = item_type
|
63
|
+
end
|
64
|
+
def to_s
|
65
|
+
"Array[#{item_type.to_s}]"
|
66
|
+
end
|
67
|
+
def check(value)
|
68
|
+
T.check_not_nil(self, value)
|
69
|
+
if !value.is_a? Array
|
70
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Array is required")
|
71
|
+
end
|
72
|
+
value.each { |item_value| T.check(item_type, item_value) }
|
73
|
+
end
|
74
|
+
def ==(other)
|
75
|
+
T.instance_of?(ArrayType, other) and self.item_type == other.item_type
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class HashType
|
80
|
+
attr_reader :key_type
|
81
|
+
attr_reader :value_type
|
82
|
+
def initialize(key_type, value_type)
|
83
|
+
@key_type = key_type
|
84
|
+
@value_type = value_type
|
85
|
+
end
|
86
|
+
def to_s
|
87
|
+
"Hash[#{@key_type.to_s}, #{@value_type.to_s}]"
|
88
|
+
end
|
89
|
+
def check(value)
|
90
|
+
T.check_not_nil(self, value)
|
91
|
+
if !value.is_a? Hash
|
92
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Hash is required")
|
93
|
+
end
|
94
|
+
value.each do |item_key, item_value|
|
95
|
+
T.check(@key_type, item_key)
|
96
|
+
T.check(@value_type, item_value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
def ==(other)
|
100
|
+
T.instance_of?(HashType, other) and self.key_type == other.key_type and self.value_type == other.value_type
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class StringFormatted
|
105
|
+
attr_reader :regex
|
106
|
+
def initialize(regex)
|
107
|
+
@regex = regex
|
108
|
+
end
|
109
|
+
def to_s
|
110
|
+
"String<#@regex>"
|
111
|
+
end
|
112
|
+
def check(value)
|
113
|
+
T.check_not_nil(self, value)
|
114
|
+
if !value.is_a? String
|
115
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - String is required for StringFormatted")
|
116
|
+
end
|
117
|
+
if !@regex.match?(value)
|
118
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' is not in required format '#{@regex}'")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def T.check(type, value)
|
124
|
+
if type.methods.include? :check
|
125
|
+
type.check(value)
|
126
|
+
else
|
127
|
+
if type != NilClass
|
128
|
+
T.check_not_nil(type, value)
|
129
|
+
end
|
130
|
+
if !value.is_a? type
|
131
|
+
raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - #{type} is required")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
return value
|
135
|
+
end
|
136
|
+
|
137
|
+
def T.instance_of?(type, value)
|
138
|
+
begin
|
139
|
+
T.check(type, value)
|
140
|
+
true
|
141
|
+
rescue TypeError
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def T.nilable(value_type)
|
147
|
+
Nilable.new(value_type)
|
148
|
+
end
|
149
|
+
|
150
|
+
def T.array(item_type)
|
151
|
+
ArrayType.new(item_type)
|
152
|
+
end
|
153
|
+
|
154
|
+
def T.hash(key_type, value_type)
|
155
|
+
HashType.new(key_type, value_type)
|
156
|
+
end
|
157
|
+
|
158
|
+
def T.any(*typdefs)
|
159
|
+
AnyType.new(*typdefs)
|
160
|
+
end
|
161
|
+
|
162
|
+
def T.check_var(var_name, type, value)
|
163
|
+
begin
|
164
|
+
check(type, value)
|
165
|
+
return value
|
166
|
+
rescue TypeError => e
|
167
|
+
raise TypeError.new("Variable #{var_name} type check failed, expected type: #{type.to_s}, value: #{value}")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
Boolean = T.any(TrueClass, FalseClass)
|
173
|
+
Untyped = T::UntypedType.new
|
174
|
+
NilableUntyped = T.nilable(Untyped)
|
175
|
+
UUID = T::StringFormatted.new(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
|
176
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require "test/unit/runner/junitxml"
|
2
|
+
|
3
|
+
require 'emery/dataclass'
|
4
|
+
require 'emery/jsoner'
|
5
|
+
|
6
|
+
module Emery
|
7
|
+
class DataClassTypeEquality < Test::Unit::TestCase
|
8
|
+
def test_equals
|
9
|
+
assert_true TheClass == TheClass
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_not_equals
|
13
|
+
assert_false TheClass == TheClassWithNested
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class DataClassFields < Test::Unit::TestCase
|
18
|
+
def test_fields_meta
|
19
|
+
assert_equal ({:string => String, :int => Integer}), TheClass.json_attributes, "Attributes with types should be available on data class"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_read
|
23
|
+
obj = TheClass.new(string: "the string", int: 123)
|
24
|
+
assert_equal "the string", obj.string, "Immutable field should be readable"
|
25
|
+
assert_equal 123, obj.int, "Mutable field should be readable"
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_write_mutable
|
29
|
+
obj = TheClass.new(string: "the string", int: 123)
|
30
|
+
obj.int = 124
|
31
|
+
assert_equal 124, obj.int, "Mutable field should be writable"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_write_immutable
|
35
|
+
obj = TheClass.new(string: "the string", int: 123)
|
36
|
+
assert_raise NoMethodError do
|
37
|
+
obj.string = "the other string"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class DataClassEquality < Test::Unit::TestCase
|
43
|
+
def test_nil
|
44
|
+
assert_not_equal nil, TheClass.new(string: "the string", int: 123), "Object should not be equal to nil"
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_same_fields_values
|
48
|
+
assert_equal TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string", int: 123), "Objects with same fields should be equal"
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_different_fields_values
|
52
|
+
assert_not_equal TheClass.new(string: "the string 2", int: 123), TheClass.new(string: "the string", int: 123), "Objects with different fields should not be equal"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class DataClassDeserialization < Test::Unit::TestCase
|
57
|
+
def test_deserialize_object
|
58
|
+
data = Jsoner.from_json(TheClass, '{"string": "the string", "int": 123}')
|
59
|
+
T.check(TheClass, data)
|
60
|
+
assert_equal TheClass.new(string: "the string", int: 123), data, "Should parse data class object"
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_deserialize_nested_object
|
64
|
+
data = Jsoner.from_json(TheClassWithNested, '{"nested": {"string": "the string", "int": 123}}')
|
65
|
+
T.check(TheClassWithNested, data)
|
66
|
+
assert_equal TheClassWithNested.new(nested: TheClass.new(string: "the string", int: 123)), data, "Should parse nested data class object"
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_deserialize_object_fail
|
70
|
+
assert_raise JsonerError do
|
71
|
+
Jsoner.from_json(TheClass, '"string"')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
class DataClassSerialization < Test::Unit::TestCase
|
78
|
+
def test_serialize_object
|
79
|
+
assert_equal '{"string":"the string","int":123}', Jsoner.to_json(TheClass, TheClass.new(string: "the string", int: 123)), "nil should be serializable to JSON"
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_serialize_array_of_objects
|
83
|
+
assert_equal '[{"string":"the string","int":123},{"string":"the string 2","int":456}]', Jsoner.to_json(T.array(TheClass), [TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string 2", int: 456)]), "Array of objects should be serializable to JSON"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class DataClassCopy < Test::Unit::TestCase
|
88
|
+
def test_copy
|
89
|
+
a = TheClass.new(string: "the string", int: 123)
|
90
|
+
b = a.copy(string: "the other string")
|
91
|
+
assert_equal "the string", a.string
|
92
|
+
assert_equal "the other string", b.string
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_copy_non_existing_field
|
96
|
+
assert_raise TypeError do
|
97
|
+
a = TheClass.new(string: "the string", int: 123)
|
98
|
+
a.copy(non_existing: "the other string")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class TheClass
|
104
|
+
include DataClass
|
105
|
+
|
106
|
+
val :string, String
|
107
|
+
var :int, Integer
|
108
|
+
end
|
109
|
+
|
110
|
+
class TheClassWithNested
|
111
|
+
include DataClass
|
112
|
+
|
113
|
+
val :nested, TheClass
|
114
|
+
end
|
115
|
+
end
|
data/test/enum_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "test/unit/runner/junitxml"
|
2
|
+
|
3
|
+
require 'emery/type'
|
4
|
+
require 'emery/enum'
|
5
|
+
require 'emery/jsoner'
|
6
|
+
|
7
|
+
module Emery
|
8
|
+
class TypeCheckEnum < Test::Unit::TestCase
|
9
|
+
def test_success
|
10
|
+
assert_equal SomeEnum::one, T.check(SomeEnum, SomeEnum::one), "Plain enum type should pass type check"
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_fail
|
14
|
+
assert_raise TypeError do
|
15
|
+
T.check(SomeEnum, "non existing")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class EnumDeserialization < Test::Unit::TestCase
|
21
|
+
def test_deserialize_enum
|
22
|
+
data = Jsoner.from_json(SomeEnum, '"two"')
|
23
|
+
T.check(SomeEnum, data)
|
24
|
+
assert_equal SomeEnum::two, data, "Enum should be parsable from JSON"
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_deserialize_enum_non_existing_item
|
28
|
+
assert_raise JsonerError do
|
29
|
+
Jsoner.from_json(SomeEnum, '"non_existing"')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class EnumSerialization < Test::Unit::TestCase
|
35
|
+
def test_serialize_enum
|
36
|
+
json_str = Jsoner.to_json(SomeEnum, SomeEnum::two)
|
37
|
+
assert_equal '"two"', json_str, "Enum should be serializable to JSON"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class SomeEnum
|
42
|
+
include Enum
|
43
|
+
|
44
|
+
define :one, 'one'
|
45
|
+
define :two, 'two'
|
46
|
+
end
|
47
|
+
end
|
data/test/jsoner_test.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
require "test/unit/runner/junitxml"
|
2
|
+
|
3
|
+
require 'emery/type'
|
4
|
+
require 'emery/jsoner'
|
5
|
+
|
6
|
+
module Emery
|
7
|
+
class PlainTypesDeserialization < Test::Unit::TestCase
|
8
|
+
def test_deserialize_integer
|
9
|
+
data = Jsoner.from_json(Integer, '123')
|
10
|
+
T.check(Integer, data)
|
11
|
+
assert_equal 123, data, "Integer should be parsable from JSON"
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_deserialize_integer_fail
|
15
|
+
assert_raise JsonerError do
|
16
|
+
Jsoner.from_json(Integer, '"abc"')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_deserialize_float
|
21
|
+
data = Jsoner.from_json(Float, '1.23')
|
22
|
+
T.check(Float, data)
|
23
|
+
assert_equal 1.23, data, "Float should be parsable from JSON"
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_deserialize_float_from_integer
|
27
|
+
data = Jsoner.from_json(Float, '123')
|
28
|
+
T.check(Float, data)
|
29
|
+
assert_equal 123.0, data, "Float should be parsable from JSON"
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_deserialize_float_fail
|
33
|
+
assert_raise JsonerError do
|
34
|
+
Jsoner.from_json(Float, '"abc"')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_deserialize_boolean
|
39
|
+
data = Jsoner.from_json(Boolean, 'true')
|
40
|
+
T.check(Boolean, data)
|
41
|
+
assert_equal true, data, "Boolean should be parsable from JSON"
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_deserialize_boolean_fail
|
45
|
+
assert_raise JsonerError do
|
46
|
+
Jsoner.from_json(Boolean, '1')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_deserialize_string
|
51
|
+
data = Jsoner.from_json(String, '"the string"')
|
52
|
+
T.check(String, data)
|
53
|
+
assert_equal "the string", data, "String should be parsable from JSON"
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_deserialize_string_fail
|
57
|
+
assert_raise JsonerError do
|
58
|
+
Jsoner.from_json(String, '123')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_deserialize_uuid
|
63
|
+
data = Jsoner.from_json(UUID, '"58d5e212-165b-4ca0-909b-c86b9cee0111"')
|
64
|
+
T.check(UUID, data)
|
65
|
+
assert_equal "58d5e212-165b-4ca0-909b-c86b9cee0111", data, "String should be parsable from JSON"
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_deserialize_uuid_fail
|
69
|
+
assert_raise JsonerError do
|
70
|
+
Jsoner.from_json(UUID, '"abc"')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_deserialize_date
|
75
|
+
data = Jsoner.from_json(Date, '"2019-11-30"')
|
76
|
+
T.check(Date, data)
|
77
|
+
assert_equal Date.new(2019, 11, 30), data, "Date should be parsable from JSON"
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_deserialize_date_wrong_format
|
81
|
+
assert_raise JsonerError do
|
82
|
+
Jsoner.from_json(Date, '"11/30/2019"')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_deserialize_datetime
|
87
|
+
data = Jsoner.from_json(DateTime, '"2019-11-30T17:45:55+00:00"')
|
88
|
+
T.check(DateTime, data)
|
89
|
+
assert_equal DateTime.new(2019, 11, 30, 17, 45, 55), data, "DateTime should be parsable from JSON"
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_deserialize_datetime_wrong_format
|
93
|
+
assert_raise JsonerError do
|
94
|
+
Jsoner.from_json(DateTime, '"2019-11-30 17:45:55"')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_deserialize_nilable_nil
|
99
|
+
data = Jsoner.from_json(T.nilable(String), 'null')
|
100
|
+
T.check(T.nilable(String), data)
|
101
|
+
assert_equal nil, data, "Nilable null value should be parsable from JSON"
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_deserialize_nilable_string
|
105
|
+
data = Jsoner.from_json(T.nilable(String), '"some string"')
|
106
|
+
T.check(T.nilable(String), data)
|
107
|
+
assert_equal "some string", data, "Nilable non-null value should be parsable from JSON"
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_deserialize_non_nilable
|
111
|
+
assert_raise JsonerError do
|
112
|
+
Jsoner.from_json(String, 'null')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class PlainTypesSerialization < Test::Unit::TestCase
|
118
|
+
def test_serialize_integer
|
119
|
+
assert_equal "123", Jsoner.to_json(Integer,123), "Integer should be serializable to JSON"
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_serialize_integer_fail
|
123
|
+
assert_raise JsonerError do
|
124
|
+
Jsoner.to_json(Integer,123.4)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_serialize_float
|
129
|
+
assert_equal "12.3", Jsoner.to_json(Float,12.3), "Float should be serializable to JSON"
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_serialize_float_fail
|
133
|
+
assert_raise JsonerError do
|
134
|
+
Jsoner.to_json(Float,123)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_serialize_boolean
|
139
|
+
assert_equal "true", Jsoner.to_json(Boolean, true), "Boolean should be serializable to JSON"
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_serialize_string
|
143
|
+
assert_equal '"the string"', Jsoner.to_json(String,"the string"), "String should be serializable to JSON"
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_serialize_date
|
147
|
+
assert_equal '"2019-11-30"', Jsoner.to_json(Date, Date.new(2019, 11, 30)), "Date should be serializable to JSON"
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_serialize_date_fail
|
151
|
+
assert_raise JsonerError do
|
152
|
+
Jsoner.to_json(Date, 123)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_serialize_datetime
|
157
|
+
assert_equal '"2019-11-30T17:45:55"', Jsoner.to_json(DateTime, DateTime.new(2019, 11, 30, 17, 45, 55)), "DateTime should be serializable to JSON"
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_serialize_nil
|
161
|
+
json_str = Jsoner.to_json(T.nilable(Untyped), nil)
|
162
|
+
assert_equal "null", json_str, "nil should be serializable to JSON"
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_serialize_uuid
|
166
|
+
assert_equal '"58d5e212-165b-4ca0-909b-c86b9cee0111"', Jsoner.to_json(UUID, "58d5e212-165b-4ca0-909b-c86b9cee0111"), "UUID should be serializable to JSON"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class ArrayDeserialization < Test::Unit::TestCase
|
171
|
+
def test_deserialize_array
|
172
|
+
data = Jsoner.from_json(T.array(String), '["the string", "the other string"]')
|
173
|
+
T.check(T.array(String), data)
|
174
|
+
assert_equal ["the string", "the other string"], data, "Should parse array of strings"
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_deserialize_array_of_datetime
|
178
|
+
data = Jsoner.from_json(T.array(DateTime), '["2019-11-30T17:45:55+00:00"]')
|
179
|
+
T.check(T.array(DateTime), data)
|
180
|
+
assert_equal [DateTime.new(2019, 11, 30, 17, 45, 55)], data, "Should parse array of DateTime"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class ArraySerialization < Test::Unit::TestCase
|
185
|
+
def test_serialize_array
|
186
|
+
assert_equal '["the string","the other string"]', Jsoner.to_json(T.array(String), ["the string", "the other string"]), "Array should be serializable to JSON"
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_serialize_array_of_datetime
|
190
|
+
assert_equal '["2019-11-30T17:45:55"]', Jsoner.to_json(T.array(DateTime), [DateTime.new(2019, 11, 30, 17, 45, 55)]), "Array should be serializable to JSON"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class HashDeserialization < Test::Unit::TestCase
|
195
|
+
def test_deserialize_hash
|
196
|
+
data = Jsoner.from_json(T.hash(String, Integer), '{"one": 123, "two": 456}')
|
197
|
+
T.check(T.hash(String, Integer), data)
|
198
|
+
assert_equal ({"one" => 123, "two" => 456}), data, "Should parse hash"
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_deserialize_hash_string_to_datetime
|
202
|
+
data = Jsoner.from_json(T.hash(String, DateTime), '{"one": "2019-11-30T17:45:55+00:00"}')
|
203
|
+
T.check(T.hash(String, DateTime), data)
|
204
|
+
assert_equal ({"one" => DateTime.new(2019, 11, 30, 17, 45, 55)}), data, "Should parse hash"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class HashSerialization < Test::Unit::TestCase
|
209
|
+
def test_serialize_hash
|
210
|
+
assert_equal '{"one":123,"two":456}', Jsoner.to_json(T.hash(String, Integer), {"one" => 123, "two" => 456}), "Hash should be serializable to JSON"
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_serialize_hash_string_to_datetime
|
214
|
+
assert_equal '{"one":"2019-11-30T17:45:55"}', Jsoner.to_json(T.hash(String, DateTime), {"one" => DateTime.new(2019, 11, 30, 17, 45, 55)}), "Hash should be serializable to JSON"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class AnyDeserialization < Test::Unit::TestCase
|
219
|
+
def test_deserialize_any
|
220
|
+
data = Jsoner.from_json(T.any(String, Integer), '"the string"')
|
221
|
+
T.check(T.any(String, Integer), data)
|
222
|
+
assert_equal "the string", data, "Should parse any type"
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_deserialize_any_fail
|
226
|
+
assert_raise JsonerError do
|
227
|
+
Jsoner.from_json(T.any(Integer, Float), '"the string"')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class AnySerialization < Test::Unit::TestCase
|
233
|
+
def test_serialize_any
|
234
|
+
data = Jsoner.to_json(T.any(String, Integer), "the string")
|
235
|
+
T.check(T.any(String, Integer), data)
|
236
|
+
assert_equal '"the string"', data, "Should serialize any type"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|