emery 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|