hoodoo 1.0.2
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/bin/hoodoo +5 -0
- data/lib/hoodoo.rb +27 -0
- data/lib/hoodoo/active.rb +32 -0
- data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
- data/lib/hoodoo/active/active_record/base.rb +81 -0
- data/lib/hoodoo/active/active_record/creator.rb +134 -0
- data/lib/hoodoo/active/active_record/dated.rb +343 -0
- data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
- data/lib/hoodoo/active/active_record/finder.rb +606 -0
- data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
- data/lib/hoodoo/active/active_record/secure.rb +431 -0
- data/lib/hoodoo/active/active_record/support.rb +106 -0
- data/lib/hoodoo/active/active_record/translated.rb +87 -0
- data/lib/hoodoo/active/active_record/uuid.rb +80 -0
- data/lib/hoodoo/active/active_record/writer.rb +321 -0
- data/lib/hoodoo/client.rb +23 -0
- data/lib/hoodoo/client/augmented_array.rb +29 -0
- data/lib/hoodoo/client/augmented_base.rb +168 -0
- data/lib/hoodoo/client/augmented_hash.rb +23 -0
- data/lib/hoodoo/client/client.rb +354 -0
- data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
- data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
- data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
- data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
- data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
- data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
- data/lib/hoodoo/client/headers.rb +269 -0
- data/lib/hoodoo/communicators.rb +23 -0
- data/lib/hoodoo/communicators/fast.rb +44 -0
- data/lib/hoodoo/communicators/pool.rb +601 -0
- data/lib/hoodoo/communicators/slow.rb +84 -0
- data/lib/hoodoo/data.rb +51 -0
- data/lib/hoodoo/data/resources/caller.rb +39 -0
- data/lib/hoodoo/data/resources/errors.rb +28 -0
- data/lib/hoodoo/data/resources/log.rb +31 -0
- data/lib/hoodoo/data/resources/session.rb +26 -0
- data/lib/hoodoo/data/types/error_primitive.rb +27 -0
- data/lib/hoodoo/data/types/permissions.rb +40 -0
- data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
- data/lib/hoodoo/data/types/permissions_full.rb +28 -0
- data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
- data/lib/hoodoo/discovery.rb +20 -0
- data/lib/hoodoo/errors.rb +19 -0
- data/lib/hoodoo/errors/error_descriptions.rb +229 -0
- data/lib/hoodoo/errors/errors.rb +322 -0
- data/lib/hoodoo/generator.rb +139 -0
- data/lib/hoodoo/logger.rb +23 -0
- data/lib/hoodoo/logger/fast_writer.rb +27 -0
- data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
- data/lib/hoodoo/logger/logger.rb +387 -0
- data/lib/hoodoo/logger/slow_writer.rb +49 -0
- data/lib/hoodoo/logger/writer_mixin.rb +52 -0
- data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
- data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
- data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
- data/lib/hoodoo/middleware.rb +33 -0
- data/lib/hoodoo/presenters.rb +45 -0
- data/lib/hoodoo/presenters/base.rb +281 -0
- data/lib/hoodoo/presenters/base_dsl.rb +519 -0
- data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
- data/lib/hoodoo/presenters/embedding.rb +232 -0
- data/lib/hoodoo/presenters/types/array.rb +118 -0
- data/lib/hoodoo/presenters/types/boolean.rb +26 -0
- data/lib/hoodoo/presenters/types/date.rb +26 -0
- data/lib/hoodoo/presenters/types/date_time.rb +26 -0
- data/lib/hoodoo/presenters/types/decimal.rb +47 -0
- data/lib/hoodoo/presenters/types/enum.rb +55 -0
- data/lib/hoodoo/presenters/types/field.rb +158 -0
- data/lib/hoodoo/presenters/types/float.rb +26 -0
- data/lib/hoodoo/presenters/types/hash.rb +361 -0
- data/lib/hoodoo/presenters/types/integer.rb +26 -0
- data/lib/hoodoo/presenters/types/object.rb +117 -0
- data/lib/hoodoo/presenters/types/string.rb +53 -0
- data/lib/hoodoo/presenters/types/tags.rb +24 -0
- data/lib/hoodoo/presenters/types/text.rb +26 -0
- data/lib/hoodoo/presenters/types/uuid.rb +54 -0
- data/lib/hoodoo/services.rb +34 -0
- data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
- data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
- data/lib/hoodoo/services/discovery/discovery.rb +186 -0
- data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
- data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
- data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
- data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
- data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
- data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
- data/lib/hoodoo/services/middleware/interaction.rb +127 -0
- data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
- data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
- data/lib/hoodoo/services/services/context.rb +153 -0
- data/lib/hoodoo/services/services/implementation.rb +132 -0
- data/lib/hoodoo/services/services/interface.rb +934 -0
- data/lib/hoodoo/services/services/permissions.rb +250 -0
- data/lib/hoodoo/services/services/request.rb +189 -0
- data/lib/hoodoo/services/services/response.rb +316 -0
- data/lib/hoodoo/services/services/service.rb +141 -0
- data/lib/hoodoo/services/services/session.rb +729 -0
- data/lib/hoodoo/utilities.rb +12 -0
- data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
- data/lib/hoodoo/utilities/utilities.rb +380 -0
- data/lib/hoodoo/utilities/uuid.rb +44 -0
- data/lib/hoodoo/version.rb +17 -0
- data/spec/active/active_record/base_spec.rb +57 -0
- data/spec/active/active_record/creator_spec.rb +88 -0
- data/spec/active/active_record/dated_spec.rb +248 -0
- data/spec/active/active_record/error_mapping_spec.rb +360 -0
- data/spec/active/active_record/finder_spec.rb +744 -0
- data/spec/active/active_record/search_helper_spec.rb +384 -0
- data/spec/active/active_record/secure_spec.rb +435 -0
- data/spec/active/active_record/support_spec.rb +225 -0
- data/spec/active/active_record/translated_spec.rb +19 -0
- data/spec/active/active_record/uuid_spec.rb +72 -0
- data/spec/active/active_record/writer_spec.rb +272 -0
- data/spec/alchemy/alchemy-amq.rb +33 -0
- data/spec/client/augmented_array_spec.rb +15 -0
- data/spec/client/augmented_base_spec.rb +50 -0
- data/spec/client/augmented_hash_spec.rb +15 -0
- data/spec/client/client_spec.rb +955 -0
- data/spec/client/endpoint/endpoint_spec.rb +70 -0
- data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
- data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
- data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
- data/spec/client/headers_spec.rb +172 -0
- data/spec/communicators/fast_spec.rb +9 -0
- data/spec/communicators/pool_spec.rb +339 -0
- data/spec/communicators/slow_spec.rb +15 -0
- data/spec/data/resources/caller_spec.rb +156 -0
- data/spec/data/resources/errors_spec.rb +22 -0
- data/spec/data/resources/log_spec.rb +20 -0
- data/spec/data/resources/session_spec.rb +15 -0
- data/spec/data/types/error_primitive_spec.rb +15 -0
- data/spec/data/types/permissions_defaults_spec.rb +25 -0
- data/spec/data/types/permissions_full_spec.rb +44 -0
- data/spec/data/types/permissions_resources_spec.rb +34 -0
- data/spec/data/types/permissions_spec.rb +37 -0
- data/spec/errors/error_descriptions_spec.rb +98 -0
- data/spec/errors/errors_spec.rb +346 -0
- data/spec/integration/service_actions_spec.rb +112 -0
- data/spec/logger/fast_writer_spec.rb +18 -0
- data/spec/logger/logger_spec.rb +259 -0
- data/spec/logger/slow_writer_spec.rb +144 -0
- data/spec/logger/writers/file_writer_spec.rb +37 -0
- data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
- data/spec/logger/writers/stream_writer_spec.rb +38 -0
- data/spec/presenters/base_dsl_spec.rb +111 -0
- data/spec/presenters/base_spec.rb +871 -0
- data/spec/presenters/common_resource_fields_spec.rb +30 -0
- data/spec/presenters/embedding_spec.rb +87 -0
- data/spec/presenters/types/array_spec.rb +249 -0
- data/spec/presenters/types/boolean_spec.rb +51 -0
- data/spec/presenters/types/date_spec.rb +57 -0
- data/spec/presenters/types/date_time_spec.rb +59 -0
- data/spec/presenters/types/decimal_spec.rb +58 -0
- data/spec/presenters/types/enum_spec.rb +71 -0
- data/spec/presenters/types/field_spec.rb +77 -0
- data/spec/presenters/types/float_spec.rb +50 -0
- data/spec/presenters/types/hash_spec.rb +1069 -0
- data/spec/presenters/types/integer_spec.rb +50 -0
- data/spec/presenters/types/object_spec.rb +177 -0
- data/spec/presenters/types/string_spec.rb +65 -0
- data/spec/presenters/types/tags_spec.rb +56 -0
- data/spec/presenters/types/text_spec.rb +50 -0
- data/spec/presenters/types/uuid_spec.rb +46 -0
- data/spec/presenters/walk_spec.rb +198 -0
- data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
- data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
- data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
- data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
- data/spec/services/discovery/discovery_spec.rb +73 -0
- data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
- data/spec/services/discovery/results/for_http_spec.rb +37 -0
- data/spec/services/discovery/results/for_local_spec.rb +21 -0
- data/spec/services/discovery/results/for_remote_spec.rb +15 -0
- data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
- data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
- data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
- data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
- data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
- data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
- data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
- data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
- data/spec/services/middleware/middleware_cors_spec.rb +93 -0
- data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
- data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
- data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
- data/spec/services/middleware/middleware_logging_spec.rb +356 -0
- data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
- data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
- data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
- data/spec/services/middleware/middleware_public_spec.rb +238 -0
- data/spec/services/middleware/middleware_spec.rb +1569 -0
- data/spec/services/middleware/string_inquirer_spec.rb +30 -0
- data/spec/services/services/application_spec.rb +74 -0
- data/spec/services/services/context_spec.rb +48 -0
- data/spec/services/services/implementation_spec.rb +45 -0
- data/spec/services/services/interface_spec.rb +262 -0
- data/spec/services/services/permissions_spec.rb +249 -0
- data/spec/services/services/request_spec.rb +95 -0
- data/spec/services/services/response_spec.rb +250 -0
- data/spec/services/services/session_spec.rb +432 -0
- data/spec/spec_helper.rb +298 -0
- data/spec/utilities/utilities_spec.rb +537 -0
- data/spec/utilities/uuid_spec.rb +20 -0
- metadata +615 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::DateTime do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@inst = Hoodoo::Presenters::DateTime.new('one',:required => false)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#validate' do
|
10
|
+
it 'should return [] when valid datetime' do
|
11
|
+
expect(@inst.validate('2014-12-11T00:00:00Z').errors).to eq([])
|
12
|
+
expect(@inst.validate('2014-12-11T00:00:00.0Z').errors).to eq([])
|
13
|
+
expect(@inst.validate('2014-12-11T00:00:00.0000Z').errors).to eq([])
|
14
|
+
expect(@inst.validate('2014-12-11T00:00:00.00000000Z').errors).to eq([])
|
15
|
+
expect(@inst.validate('2014-12-11T00:00:00+12:30').errors).to eq([])
|
16
|
+
expect(@inst.validate('2014-12-11T00:00:00-12:30').errors).to eq([])
|
17
|
+
expect(@inst.validate('2014-12-11T00:00:00.0+12:30').errors).to eq([])
|
18
|
+
expect(@inst.validate('2014-12-11T00:00:00.0-12:30').errors).to eq([])
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not return error when not required and absent' do
|
22
|
+
expect(@inst.validate(nil).errors).to eq([])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return error when required and absent' do
|
26
|
+
@inst.required = true
|
27
|
+
expect(@inst.validate(nil).errors).to eq([
|
28
|
+
{'code'=>"generic.required_field_missing", 'message'=>"Field `one` is required", 'reference'=>"one"}
|
29
|
+
])
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return correct error when datetime is invalid' do
|
33
|
+
errors = @inst.validate('2014-99-99T00:00:00Z')
|
34
|
+
|
35
|
+
err = [ {'code'=>"generic.invalid_datetime", 'message'=>"Field `one` is an invalid ISO8601 datetime", 'reference'=>"one"}]
|
36
|
+
expect(errors.errors).to eq(err)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return correct error with non datetime types' do
|
40
|
+
err = [ {'code'=>"generic.invalid_datetime", 'message'=>"Field `one` is an invalid ISO8601 datetime", 'reference'=>"one"}]
|
41
|
+
|
42
|
+
expect(@inst.validate('asckn').errors).to eq(err)
|
43
|
+
expect(@inst.validate('2014-12-11').errors).to eq(err)
|
44
|
+
expect(@inst.validate(34534.234).errors).to eq(err)
|
45
|
+
expect(@inst.validate(38247).errors).to eq(err)
|
46
|
+
expect(@inst.validate(true).errors).to eq(err)
|
47
|
+
expect(@inst.validate({}).errors).to eq(err)
|
48
|
+
expect(@inst.validate([]).errors).to eq(err)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should return correct error with path' do
|
52
|
+
errors = @inst.validate('scdacs','ordinary')
|
53
|
+
expect(errors.errors).to eq([
|
54
|
+
{'code'=>"generic.invalid_datetime", 'message'=>"Field `ordinary.one` is an invalid ISO8601 datetime", 'reference'=>"ordinary.one"}
|
55
|
+
])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::Decimal do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@inst = Hoodoo::Presenters::Decimal.new('one',:precision => 20)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#initialize' do
|
10
|
+
it 'should raise an error if precision is not defined' do
|
11
|
+
expect {
|
12
|
+
Hoodoo::Presenters::Decimal.new('one',:required => false)
|
13
|
+
}.to raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#validate' do
|
18
|
+
it 'should return [] when valid decimal' do
|
19
|
+
expect(@inst.validate(BigDecimal.new(12.231,3)).errors).to eq([])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return correct error when data is not a decimal' do
|
23
|
+
errors = @inst.validate('asckn')
|
24
|
+
|
25
|
+
err = [ {'code'=>"generic.invalid_decimal", 'message'=>"Field `one` is an invalid decimal", 'reference'=>"one"}]
|
26
|
+
expect(errors.errors).to eq(err)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not return error when not required and absent' do
|
30
|
+
expect(@inst.validate(nil).errors).to eq([])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return error when required and absent' do
|
34
|
+
@inst.required = true
|
35
|
+
expect(@inst.validate(nil).errors).to eq([
|
36
|
+
{'code'=>"generic.required_field_missing", 'message'=>"Field `one` is required", 'reference'=>"one"}
|
37
|
+
])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return correct error with non decimal types' do
|
41
|
+
err = [ {'code'=>"generic.invalid_decimal", 'message'=>"Field `one` is an invalid decimal", 'reference'=>"one"}]
|
42
|
+
|
43
|
+
expect(@inst.validate('asckn').errors).to eq(err)
|
44
|
+
expect(@inst.validate(34534).errors).to eq(err)
|
45
|
+
expect(@inst.validate(true).errors).to eq(err)
|
46
|
+
expect(@inst.validate({}).errors).to eq(err)
|
47
|
+
expect(@inst.validate([]).errors).to eq(err)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return correct error with path' do
|
51
|
+
errors = @inst.validate('scdacs','ordinary')
|
52
|
+
expect(errors.errors).to eq([
|
53
|
+
{'code'=>"generic.invalid_decimal", 'message'=>"Field `ordinary.one` is an invalid decimal", 'reference'=>"ordinary.one"}
|
54
|
+
])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::Enum do
|
4
|
+
|
5
|
+
before do
|
6
|
+
class TestPresenter4 < Hoodoo::Presenters::Base
|
7
|
+
|
8
|
+
schema do
|
9
|
+
array :an_array, :required => true do
|
10
|
+
integer :an_integer
|
11
|
+
datetime :a_datetime
|
12
|
+
end
|
13
|
+
enum :an_enum, :from => [ :one, 'two', 3 ]
|
14
|
+
text :some_text
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '::schema' do
|
21
|
+
it 'should raise an error if we use :from incorrectly' do
|
22
|
+
expect {
|
23
|
+
class ErroneousEnumTest < Hoodoo::Presenters::Base
|
24
|
+
schema do
|
25
|
+
enum :from => "wrong!"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
}.to raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#validate' do
|
33
|
+
it 'should insist on string values' do
|
34
|
+
data = {
|
35
|
+
:an_array => [],
|
36
|
+
:an_enum => :one
|
37
|
+
}
|
38
|
+
|
39
|
+
data = Hoodoo::Utilities.stringify(data)
|
40
|
+
errors = TestPresenter4.validate(data)
|
41
|
+
expect(errors.errors).to eq([
|
42
|
+
{'code'=>"generic.invalid_enum", 'message'=>"Field `an_enum` does not contain an allowed reference value from this list: `[\"one\", \"two\", \"3\"]`", 'reference'=>"an_enum"}
|
43
|
+
])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should ensure only an enumerated value is given' do
|
47
|
+
data = {
|
48
|
+
:an_array => [],
|
49
|
+
:an_enum => 'hello'
|
50
|
+
}
|
51
|
+
|
52
|
+
data = Hoodoo::Utilities.stringify(data)
|
53
|
+
errors = TestPresenter4.validate(data)
|
54
|
+
expect(errors.errors).to eq([
|
55
|
+
{'code'=>"generic.invalid_enum", 'message'=>"Field `an_enum` does not contain an allowed reference value from this list: `[\"one\", \"two\", \"3\"]`", 'reference'=>"an_enum"}
|
56
|
+
])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should be happy with valid values' do
|
60
|
+
data = {
|
61
|
+
:an_array => [],
|
62
|
+
:an_enum => '3'
|
63
|
+
}
|
64
|
+
|
65
|
+
data = Hoodoo::Utilities.stringify(data)
|
66
|
+
errors = TestPresenter4.validate(data)
|
67
|
+
expect(errors.errors).to eq([])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::Field do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@inst = Hoodoo::Presenters::Field.new('one',:required => false)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#initialise' do
|
10
|
+
|
11
|
+
it 'should initialize correctly' do
|
12
|
+
inst = Hoodoo::Presenters::Field.new('one',:required => true)
|
13
|
+
expect(inst.name).to eq('one')
|
14
|
+
expect(inst.required).to eq(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should default required false' do
|
18
|
+
inst = Hoodoo::Presenters::Field.new('two')
|
19
|
+
expect(inst.name).to eq('two')
|
20
|
+
expect(inst.required).to eq(false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#validate' do
|
25
|
+
it 'should return [] when not required when data nil' do
|
26
|
+
errors = @inst.validate(nil)
|
27
|
+
expect(errors.errors).to eq([])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return [] when not required when data not nil' do
|
31
|
+
errors = @inst.validate(1)
|
32
|
+
expect(errors.errors).to eq([])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return correct error when required and data is nil' do
|
36
|
+
@inst.required = true
|
37
|
+
errors = @inst.validate(nil)
|
38
|
+
expect(errors.errors).to eq([
|
39
|
+
{'code'=>"generic.required_field_missing", 'message'=>"Field `one` is required", 'reference'=>"one"}
|
40
|
+
])
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return correct error with path' do
|
44
|
+
@inst.required = true
|
45
|
+
errors = @inst.validate(nil,'ordinary')
|
46
|
+
expect(errors.errors).to eq([
|
47
|
+
{'code'=>"generic.required_field_missing", 'message'=>"Field `ordinary.one` is required", 'reference'=>"ordinary.one"}
|
48
|
+
])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#full_path' do
|
53
|
+
|
54
|
+
it 'should return name.to_s if no path' do
|
55
|
+
expect(@inst.full_path(nil)).to eq(@inst.name)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should return name.to_s if path empty' do
|
59
|
+
expect(@inst.full_path('')).to eq(@inst.name)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should return paths if name nil' do
|
63
|
+
@inst.name = nil
|
64
|
+
expect(@inst.full_path('sdzcz')).to eq('sdzcz')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should return paths if name empty' do
|
68
|
+
@inst.name = ''
|
69
|
+
expect(@inst.full_path('sdzcz')).to eq('sdzcz')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should return path.name if path and name not nil or empty' do
|
73
|
+
expect(@inst.full_path('sdzcz')).to eq('sdzcz.one')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::Float do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@inst = Hoodoo::Presenters::Float.new('one',:required => false)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#validate' do
|
10
|
+
it 'should return [] when valid float' do
|
11
|
+
expect(@inst.validate(12.231).errors).to eq([])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should return correct error when data is not a float' do
|
15
|
+
errors = @inst.validate('asckn')
|
16
|
+
|
17
|
+
err = [ {'code'=>"generic.invalid_float", 'message'=>"Field `one` is an invalid float", 'reference'=>"one"}]
|
18
|
+
expect(errors.errors).to eq(err)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should not return error when not required and absent' do
|
22
|
+
expect(@inst.validate(nil).errors).to eq([])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return error when required and absent' do
|
26
|
+
@inst.required = true
|
27
|
+
expect(@inst.validate(nil).errors).to eq([
|
28
|
+
{'code'=>"generic.required_field_missing", 'message'=>"Field `one` is required", 'reference'=>"one"}
|
29
|
+
])
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return correct error with non float types' do
|
33
|
+
err = [ {'code'=>"generic.invalid_float", 'message'=>"Field `one` is an invalid float", 'reference'=>"one"}]
|
34
|
+
|
35
|
+
expect(@inst.validate('asckn').errors).to eq(err)
|
36
|
+
expect(@inst.validate(34534).errors).to eq(err)
|
37
|
+
expect(@inst.validate(true).errors).to eq(err)
|
38
|
+
expect(@inst.validate({}).errors).to eq(err)
|
39
|
+
expect(@inst.validate([]).errors).to eq(err)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should return correct error with path' do
|
43
|
+
errors = @inst.validate('scdacs','ordinary')
|
44
|
+
expect(errors.errors).to eq([
|
45
|
+
{'code'=>"generic.invalid_float", 'message'=>"Field `ordinary.one` is an invalid float", 'reference'=>"ordinary.one"}
|
46
|
+
])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,1069 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoodoo::Presenters::Hash do
|
4
|
+
|
5
|
+
context 'exceptions' do
|
6
|
+
it 'should complain about #key then #keys' do
|
7
|
+
expect {
|
8
|
+
class TestHashKeyKeysException < Hoodoo::Presenters::Base
|
9
|
+
schema do
|
10
|
+
hash :foo do
|
11
|
+
key :one
|
12
|
+
keys :length => 4
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
}.to raise_error( RuntimeError )
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should complain about #keys then #key' do
|
20
|
+
expect {
|
21
|
+
class TestHashKeysKeyException < Hoodoo::Presenters::Base
|
22
|
+
schema do
|
23
|
+
hash :foo do
|
24
|
+
keys :length => 4
|
25
|
+
key :one
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
}.to raise_error( RuntimeError )
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should complain about #keys twice' do
|
33
|
+
expect {
|
34
|
+
class TestHashKeysKeysException < Hoodoo::Presenters::Base
|
35
|
+
schema do
|
36
|
+
hash :foo do
|
37
|
+
keys :length => 4
|
38
|
+
keys :length => 4
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}.to raise_error( RuntimeError )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
############################################################################
|
47
|
+
|
48
|
+
class TestHashNoKeysPresenter < Hoodoo::Presenters::Base
|
49
|
+
schema do
|
50
|
+
hash :specific
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class TestHashNoKeysPresenterRequired < Hoodoo::Presenters::Base
|
55
|
+
schema do
|
56
|
+
hash :specific_required, :required => true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
############################################################################
|
61
|
+
|
62
|
+
context 'no keys' do
|
63
|
+
context '#validate' do
|
64
|
+
it 'should return [] when valid object' do
|
65
|
+
data = { 'specific' => { 'hello' => 'there' } }
|
66
|
+
expect( TestHashNoKeysPresenter.validate( data ).errors ).to eq( [] )
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return correct error when data is not an object' do
|
70
|
+
data = { 'specific' => 'hello' }
|
71
|
+
errors = [ {
|
72
|
+
'code' => 'generic.invalid_hash',
|
73
|
+
'message' => 'Field `specific` is an invalid hash',
|
74
|
+
'reference' => 'specific'
|
75
|
+
} ]
|
76
|
+
|
77
|
+
expect( TestHashNoKeysPresenter.validate( data ).errors ).to eq( errors )
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should not return error when not required and absent' do
|
81
|
+
data = { 'foo' => 'bar' }
|
82
|
+
expect( TestHashNoKeysPresenter.validate( data ).errors ).to eq( [] )
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should return error when required and absent' do
|
86
|
+
data = { 'foo' => 'bar' }
|
87
|
+
errors = [ {
|
88
|
+
'code' => 'generic.required_field_missing',
|
89
|
+
'message' => 'Field `specific_required` is required',
|
90
|
+
'reference' => 'specific_required'
|
91
|
+
} ]
|
92
|
+
|
93
|
+
expect( TestHashNoKeysPresenterRequired.validate( data ).errors ).to eq( errors )
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context '#render' do
|
98
|
+
it 'should render correctly' do
|
99
|
+
data = { 'specific' => { 'hello' => 'there' } }
|
100
|
+
result = TestHashNoKeysPresenter.render( data )
|
101
|
+
|
102
|
+
expect( result ).to eq( data )
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should render correctly when described hash is not required and absent' do
|
106
|
+
data = { 'foo' => 'bar' }
|
107
|
+
result = TestHashNoKeysPresenter.render( data )
|
108
|
+
|
109
|
+
expect( result ).to eq({})
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
############################################################################
|
115
|
+
|
116
|
+
class TestHashSpecificKeyPresenter < Hoodoo::Presenters::Base
|
117
|
+
schema do
|
118
|
+
hash :specific do
|
119
|
+
key :one
|
120
|
+
key :two do
|
121
|
+
string :foo, :length => 10
|
122
|
+
text :bar, :required => true
|
123
|
+
end
|
124
|
+
key :three do
|
125
|
+
integer :int
|
126
|
+
uuid :id
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
############################################################################
|
133
|
+
|
134
|
+
context 'specific keys' do
|
135
|
+
context '#validate' do
|
136
|
+
it 'should return [] when valid object (1)' do
|
137
|
+
data = { 'specific' => { 'one' => 'anything' } }
|
138
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should return [] when valid object (2)' do
|
142
|
+
data = { 'specific' => { 'two' => { 'foo' => 'foov', 'bar' => 'barv' } } }
|
143
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should return [] when valid object (3)' do
|
147
|
+
data = { 'specific' => { 'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } } }
|
148
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should return [] when valid object (4)' do
|
152
|
+
data = { 'specific' => { 'one' => 'anything',
|
153
|
+
'two' => { 'foo' => 'foov', 'bar' => 'barv' },
|
154
|
+
'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } } }
|
155
|
+
|
156
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should return correct error when data is not an object' do
|
160
|
+
data = { 'specific' => 'hello' }
|
161
|
+
errors = [ {
|
162
|
+
'code' => 'generic.invalid_hash',
|
163
|
+
'message' => 'Field `specific` is an invalid hash',
|
164
|
+
'reference' => 'specific'
|
165
|
+
} ]
|
166
|
+
|
167
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should return correct error when unexpected keys are present' do
|
171
|
+
data = { 'specific' => { 'hi' => 'there',
|
172
|
+
'foo' => { 'bar' => 'baz' },
|
173
|
+
'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } } }
|
174
|
+
errors = [ {
|
175
|
+
'code' => 'generic.invalid_hash',
|
176
|
+
'message' => 'Field `specific` is an invalid hash due to unrecognised keys `hi, foo`',
|
177
|
+
'reference' => 'specific'
|
178
|
+
} ]
|
179
|
+
|
180
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should return correct errors when value formats are wrong or required values are omitted' do
|
184
|
+
data = { 'specific' => { 'three' => { 'int' => 'not an int', 'id' => 'not an id' }, 'two' => {} } }
|
185
|
+
|
186
|
+
errors = [
|
187
|
+
{
|
188
|
+
'code' => 'generic.invalid_integer',
|
189
|
+
'message' => 'Field `specific.three.int` is an invalid integer',
|
190
|
+
'reference' => 'specific.three.int'
|
191
|
+
},
|
192
|
+
{
|
193
|
+
'code' => 'generic.invalid_uuid',
|
194
|
+
'message' => 'Field `specific.three.id` is an invalid UUID',
|
195
|
+
'reference' => 'specific.three.id'
|
196
|
+
},
|
197
|
+
{
|
198
|
+
'code' => 'generic.required_field_missing',
|
199
|
+
'message' => 'Field `specific.two.bar` is required',
|
200
|
+
'reference' => 'specific.two.bar'
|
201
|
+
},
|
202
|
+
]
|
203
|
+
|
204
|
+
expect( TestHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context '#render' do
|
209
|
+
it 'should render correctly (1)' do
|
210
|
+
data = { 'specific' => { 'one' => 'anything' } }
|
211
|
+
result = TestHashSpecificKeyPresenter.render( data )
|
212
|
+
|
213
|
+
expect( result ).to eq( data )
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should render correctly (2)' do
|
217
|
+
data = { 'specific' => { 'two' => { 'foo' => 'foov', 'bar' => 'barv' } } }
|
218
|
+
result = TestHashSpecificKeyPresenter.render( data )
|
219
|
+
|
220
|
+
expect( result ).to eq( data )
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should render correctly (3)' do
|
224
|
+
data = { 'specific' => { 'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } } }
|
225
|
+
result = TestHashSpecificKeyPresenter.render( data )
|
226
|
+
|
227
|
+
expect( result ).to eq( data )
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'should render correctly (4)' do
|
231
|
+
data = { 'specific' => { 'one' => 'anything',
|
232
|
+
'two' => { 'foo' => 'foov', 'bar' => 'barv' },
|
233
|
+
'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } } }
|
234
|
+
result = TestHashSpecificKeyPresenter.render( data )
|
235
|
+
|
236
|
+
expect( result ).to eq( data )
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should ignore unspecified entries' do
|
240
|
+
inner = { 'one' => 'anything',
|
241
|
+
'two' => { 'foo' => 'foov', 'bar' => 'barv' },
|
242
|
+
'three' => { 'int' => 23, 'id' => Hoodoo::UUID.generate() } }
|
243
|
+
|
244
|
+
valid = { 'specific' => inner.dup }
|
245
|
+
data = { 'specific' => inner.dup }
|
246
|
+
|
247
|
+
data[ 'generic' ] = 'hello'
|
248
|
+
data[ 'specific' ][ 'random' ] = 23
|
249
|
+
|
250
|
+
result = TestHashSpecificKeyPresenter.render( data )
|
251
|
+
|
252
|
+
expect( result ).to eq( valid )
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
############################################################################
|
258
|
+
|
259
|
+
class TestNestedHashSpecificKeyPresenter < Hoodoo::Presenters::Base
|
260
|
+
schema do
|
261
|
+
object :obj do
|
262
|
+
text :obj_text
|
263
|
+
hash :specific do
|
264
|
+
key :two do
|
265
|
+
string :two_key_string, :length => 10
|
266
|
+
hash :two_key_hash do
|
267
|
+
key :inner
|
268
|
+
key :inner_2 do
|
269
|
+
string :inner_2_string, :length => 4
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
############################################################################
|
279
|
+
|
280
|
+
context 'nested specific keys' do
|
281
|
+
context '#validate' do
|
282
|
+
it 'should return [] when valid object (1)' do
|
283
|
+
data = { 'obj' => { 'specific' => {} } }
|
284
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'should return [] when valid object (2)' do
|
288
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => {} } } }
|
289
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should return error with incorrect nested keys (1)' do
|
293
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'three' => {} } } }
|
294
|
+
errors = [
|
295
|
+
{
|
296
|
+
'code' => 'generic.invalid_hash',
|
297
|
+
'message' => 'Field `obj.specific` is an invalid hash due to unrecognised keys `three`',
|
298
|
+
'reference' => 'obj.specific'
|
299
|
+
}
|
300
|
+
]
|
301
|
+
|
302
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'should return [] when valid object (3)' do
|
306
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => { 'two_key_hash' => {} } } } }
|
307
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should return [] when valid object (4)' do
|
311
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => { 'two_key_hash' => { 'inner' => true } } } } }
|
312
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( [] )
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'should return error with incorrect nested keys (2)' do
|
316
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => { 'two_key_hash' => { 'madeup' => true } } } } }
|
317
|
+
errors = [
|
318
|
+
{
|
319
|
+
'code' => 'generic.invalid_hash',
|
320
|
+
'message' => 'Field `obj.specific.two.two_key_hash` is an invalid hash due to unrecognised keys `madeup`',
|
321
|
+
'reference' => 'obj.specific.two.two_key_hash'
|
322
|
+
}
|
323
|
+
]
|
324
|
+
|
325
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'should return error with incorrect nested values' do
|
329
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => { 'two_key_hash' => { 'inner_2' => { 'inner_2_string' => 'too-long-for-here' } } } } } }
|
330
|
+
errors = [
|
331
|
+
{
|
332
|
+
'code' => 'generic.invalid_string',
|
333
|
+
'message' => 'Field `obj.specific.two.two_key_hash.inner_2.inner_2_string` is longer than maximum length `4`',
|
334
|
+
'reference' => 'obj.specific.two.two_key_hash.inner_2.inner_2_string'
|
335
|
+
}
|
336
|
+
]
|
337
|
+
|
338
|
+
expect( TestNestedHashSpecificKeyPresenter.validate( data ).errors ).to eq( errors )
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context '#render' do
|
343
|
+
it 'should render complex entity correctly' do
|
344
|
+
valid = { 'obj' => { 'obj_text' => 'hello', 'specific' => { 'two' => { 'two_key_hash' => { 'inner' => 42, 'inner_2' => { 'inner_2_string' => 'ok' } } } } } }
|
345
|
+
data = { 'obj' => { 'obj_text' => 'hello', 'random' => true, 'specific' => { 'two' => { 'two_key_hash' => { 'inner' => 42, 'inner_2' => { 'inner_2_string' => 'ok' } } } } } }
|
346
|
+
|
347
|
+
result = TestNestedHashSpecificKeyPresenter.render( data )
|
348
|
+
expect( result ).to eq( valid )
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
############################################################################
|
354
|
+
|
355
|
+
class TestHashSpecificKeyPresenterWithRequirements < Hoodoo::Presenters::Base
|
356
|
+
schema do
|
357
|
+
hash :specific do
|
358
|
+
key :one, :required => true
|
359
|
+
key :two, :required => true do
|
360
|
+
string :foo, :length => 10
|
361
|
+
text :bar, :required => true
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
############################################################################
|
368
|
+
|
369
|
+
context 'specific keys with requirements' do
|
370
|
+
context '#validate' do
|
371
|
+
it 'should return correct errors when keys are omitted (1)' do
|
372
|
+
data = { 'specific' => {} }
|
373
|
+
errors = [
|
374
|
+
{
|
375
|
+
'code' => 'generic.required_field_missing',
|
376
|
+
'message' => 'Field `specific.one` is required',
|
377
|
+
'reference' => 'specific.one'
|
378
|
+
},
|
379
|
+
{
|
380
|
+
'code' => 'generic.required_field_missing',
|
381
|
+
'message' => 'Field `specific.two` is required',
|
382
|
+
'reference' => 'specific.two'
|
383
|
+
},
|
384
|
+
]
|
385
|
+
|
386
|
+
expect( TestHashSpecificKeyPresenterWithRequirements.validate( data ).errors ).to eq( errors )
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'should return correct errors when keys are omitted (2)' do
|
390
|
+
data = { 'specific' => { 'two' => { 'foo' => 'foov' } } }
|
391
|
+
errors = [
|
392
|
+
{
|
393
|
+
'code' => 'generic.required_field_missing',
|
394
|
+
'message' => 'Field `specific.two.bar` is required',
|
395
|
+
'reference' => 'specific.two.bar'
|
396
|
+
},
|
397
|
+
{
|
398
|
+
'code' => 'generic.required_field_missing',
|
399
|
+
'message' => 'Field `specific.one` is required',
|
400
|
+
'reference' => 'specific.one'
|
401
|
+
}
|
402
|
+
]
|
403
|
+
|
404
|
+
expect( TestHashSpecificKeyPresenterWithRequirements.validate( data ).errors ).to eq( errors )
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
############################################################################
|
410
|
+
|
411
|
+
class TestHashSpecificKeyPresenterWithDefaults < Hoodoo::Presenters::Base
|
412
|
+
schema do
|
413
|
+
hash :specific_defaults, :default => { 'one' => 'anything', 'two' => { 'foo' => 'valid' }, 'ignoreme' => 'invalid' } do
|
414
|
+
key :one, :default => { 'foo' => { 'bar' => 'baz' } }
|
415
|
+
key :two do
|
416
|
+
string :foo, :length => 10
|
417
|
+
text :bar, :default => 'this is the text field for "bar"'
|
418
|
+
integer :baz, :default => 42
|
419
|
+
end
|
420
|
+
key :three, :default => { 'bar' => 'for_key_three' } do
|
421
|
+
string :foo, :length => 10
|
422
|
+
text :bar, :default => 'this is the text field for "bar"'
|
423
|
+
integer :baz, :default => 42
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
class TestHashSpecificKeyPresenterWithDefaultsExceptHash < Hoodoo::Presenters::Base
|
430
|
+
schema do
|
431
|
+
hash :specific_defaults do
|
432
|
+
key :one, :default => { 'foo' => { 'bar' => 'baz' } }
|
433
|
+
key :two do
|
434
|
+
string :foo, :length => 10
|
435
|
+
text :bar, :default => 'this is the text field for "bar"'
|
436
|
+
integer :baz, :default => 42
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
############################################################################
|
443
|
+
|
444
|
+
context 'specific keys with defaults' do
|
445
|
+
context '#render' do
|
446
|
+
|
447
|
+
# The hash itself has a default set, so if the hash key is omitted we
|
448
|
+
# expect to get the canned default hash instead.
|
449
|
+
#
|
450
|
+
it 'should render with correct default for whole hash (1)' do
|
451
|
+
result = TestHashSpecificKeyPresenterWithDefaults.render( {} )
|
452
|
+
|
453
|
+
expect( result ).to eq({
|
454
|
+
'specific_defaults' => {
|
455
|
+
'one' => 'anything',
|
456
|
+
'two' => { 'foo' => 'valid', 'bar' => 'this is the text field for "bar"', 'baz' => 42 },
|
457
|
+
'three' => { 'bar' => 'for_key_three', 'baz' => 42 }
|
458
|
+
}
|
459
|
+
})
|
460
|
+
end
|
461
|
+
|
462
|
+
# Should behave the same with 'nil'.
|
463
|
+
#
|
464
|
+
it 'should render with correct default for whole hash (2)' do
|
465
|
+
result = TestHashSpecificKeyPresenterWithDefaults.render( nil )
|
466
|
+
|
467
|
+
expect( result ).to eq({
|
468
|
+
'specific_defaults' => {
|
469
|
+
'one' => 'anything',
|
470
|
+
'two' => { 'foo' => 'valid', 'bar' => 'this is the text field for "bar"', 'baz' => 42 },
|
471
|
+
'three' => { 'bar' => 'for_key_three', 'baz' => 42 }
|
472
|
+
}
|
473
|
+
})
|
474
|
+
end
|
475
|
+
|
476
|
+
# Empty objects gain default fields, just like at the root level;
|
477
|
+
# and key-level defaults (one is specified for key 'three') also end
|
478
|
+
# up with field-level defaults merged (almost by accident, but it
|
479
|
+
# makes sense to do so) - integer 'baz' has a default value of 42 as
|
480
|
+
# a field-level default.
|
481
|
+
#
|
482
|
+
it 'renders an explicit empty hash with default fields' do
|
483
|
+
data = { 'specific_defaults' => {} }
|
484
|
+
result = TestHashSpecificKeyPresenterWithDefaults.render( data )
|
485
|
+
expect( result ).to eq({
|
486
|
+
'specific_defaults' => {
|
487
|
+
'one' => { 'foo' => { 'bar' => 'baz' } },
|
488
|
+
'three' => { 'bar' => 'for_key_three', 'baz' => 42 }
|
489
|
+
}
|
490
|
+
})
|
491
|
+
end
|
492
|
+
|
493
|
+
# ...but explicit nil means nil.
|
494
|
+
#
|
495
|
+
it 'renders an explicit nil' do
|
496
|
+
data = { 'specific_defaults' => nil }
|
497
|
+
result = TestHashSpecificKeyPresenterWithDefaults.render( data )
|
498
|
+
expect( result ).to eq(data)
|
499
|
+
end
|
500
|
+
|
501
|
+
# One of the hash's specific keys has a defined block with some default
|
502
|
+
# values, so if we specify an empty hash for that key, we expect it to
|
503
|
+
# be filled in with defaults.
|
504
|
+
#
|
505
|
+
it 'should render with correct defaults for hash value keys' do
|
506
|
+
data = { 'specific_defaults' => { 'two' => {} } }
|
507
|
+
result = TestHashSpecificKeyPresenterWithDefaults.render( data )
|
508
|
+
|
509
|
+
expect( result ).to eq({
|
510
|
+
'specific_defaults' => {
|
511
|
+
'one' => { 'foo' => { 'bar' => 'baz' } },
|
512
|
+
'two' => {
|
513
|
+
'bar' => 'this is the text field for "bar"',
|
514
|
+
'baz' => 42
|
515
|
+
},
|
516
|
+
'three' => { 'bar' => 'for_key_three', 'baz' => 42 }
|
517
|
+
}
|
518
|
+
})
|
519
|
+
end
|
520
|
+
|
521
|
+
# Take away the hash-level full default value; we expect an omitted hash
|
522
|
+
# to be rendered with default contents.
|
523
|
+
#
|
524
|
+
it 'should render with correct default for keys when hash itself has no default (1)' do
|
525
|
+
result = TestHashSpecificKeyPresenterWithDefaultsExceptHash.render( {} )
|
526
|
+
|
527
|
+
expect( result ).to eq({
|
528
|
+
'specific_defaults' => {
|
529
|
+
'one' => { 'foo' => { 'bar' => 'baz' } }
|
530
|
+
}
|
531
|
+
})
|
532
|
+
end
|
533
|
+
|
534
|
+
# Should behave the same with 'nil'.
|
535
|
+
#
|
536
|
+
it 'should render with correct default for keys when hash itself has no default (2)' do
|
537
|
+
result = TestHashSpecificKeyPresenterWithDefaultsExceptHash.render( nil )
|
538
|
+
|
539
|
+
expect( result ).to eq({
|
540
|
+
'specific_defaults' => {
|
541
|
+
'one' => { 'foo' => { 'bar' => 'baz' } }
|
542
|
+
}
|
543
|
+
})
|
544
|
+
end
|
545
|
+
|
546
|
+
# We also expect the same result if an empty hash is provided, as with the
|
547
|
+
# case where the hash itself had a default value.
|
548
|
+
#
|
549
|
+
it 'should render with correct defaults for hash keys (3)' do
|
550
|
+
data = { 'specific_defaults' => {} }
|
551
|
+
result = TestHashSpecificKeyPresenterWithDefaultsExceptHash.render( data )
|
552
|
+
|
553
|
+
expect( result ).to eq({
|
554
|
+
'specific_defaults' => {
|
555
|
+
'one' => { 'foo' => { 'bar' => 'baz' } }
|
556
|
+
}
|
557
|
+
})
|
558
|
+
end
|
559
|
+
|
560
|
+
# Once more, explicit nil means nil.
|
561
|
+
#
|
562
|
+
it 'should render with correct defaults for hash keys (4)' do
|
563
|
+
data = { 'specific_defaults' => nil }
|
564
|
+
result = TestHashSpecificKeyPresenterWithDefaultsExceptHash.render( data )
|
565
|
+
|
566
|
+
expect( result ).to eq(data)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
############################################################################
|
572
|
+
|
573
|
+
class TestHashGenericKeyPresenterNoValues < Hoodoo::Presenters::Base
|
574
|
+
schema do
|
575
|
+
hash :generic do
|
576
|
+
keys :length => 6
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
############################################################################
|
582
|
+
|
583
|
+
context 'generic keys no values' do
|
584
|
+
context '#validate' do
|
585
|
+
it 'should return [] when valid object' do
|
586
|
+
data = { 'generic' => { 'one' => 'anything' } }
|
587
|
+
expect( TestHashGenericKeyPresenterNoValues.validate( data ).errors ).to eq( [] )
|
588
|
+
end
|
589
|
+
|
590
|
+
it 'should return correct errors with invalid keys' do
|
591
|
+
data = { 'generic' => { 'one' => 'anything',
|
592
|
+
'two' => 'anything',
|
593
|
+
'toolong' => 'anything',
|
594
|
+
'evenlonger' => 'anything' } }
|
595
|
+
errors = [
|
596
|
+
{
|
597
|
+
'code' => 'generic.invalid_string',
|
598
|
+
'message' => 'Field `generic.toolong` is longer than maximum length `6`',
|
599
|
+
'reference' => 'generic.toolong'
|
600
|
+
},
|
601
|
+
{
|
602
|
+
'code' => 'generic.invalid_string',
|
603
|
+
'message' => 'Field `generic.evenlonger` is longer than maximum length `6`',
|
604
|
+
'reference' => 'generic.evenlonger'
|
605
|
+
}
|
606
|
+
]
|
607
|
+
|
608
|
+
expect( TestHashGenericKeyPresenterNoValues.validate( data ).errors ).to eq( errors )
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
context '#render' do
|
613
|
+
it 'should render correctly' do
|
614
|
+
|
615
|
+
# Use of "values" is important as it tests for a collision with
|
616
|
+
# an internal same-named property. It's an implementation detail
|
617
|
+
# which the code should deal with internally correctly, leading
|
618
|
+
# to no disernable alteration in expected rendering for callers.
|
619
|
+
|
620
|
+
data = { 'generic' => { 'one' => 'anything 1',
|
621
|
+
'values' => 'should not be overwritten',
|
622
|
+
'two' => 'anything 2' } }
|
623
|
+
|
624
|
+
result = TestHashGenericKeyPresenterNoValues.render( data )
|
625
|
+
expect( result ).to eq( data )
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
############################################################################
|
631
|
+
|
632
|
+
class TestHashGenericKeyPresenterWithValues < Hoodoo::Presenters::Base
|
633
|
+
schema do
|
634
|
+
hash :generic do
|
635
|
+
keys :length => 4 do
|
636
|
+
string :foo, :length => 10
|
637
|
+
text :bar
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
############################################################################
|
644
|
+
|
645
|
+
context 'generic keys with values' do
|
646
|
+
context '#validate' do
|
647
|
+
it 'should return [] when valid object' do
|
648
|
+
data = { 'generic' => { 'one' => { 'foo' => 'foov' } } }
|
649
|
+
expect( TestHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( [] )
|
650
|
+
end
|
651
|
+
|
652
|
+
it 'should return correct errors with invalid keys' do
|
653
|
+
data = { 'generic' => { 'one' => { 'foo' => 'foov' },
|
654
|
+
'two' => { 'bar' => 'barv' },
|
655
|
+
'toolong' => { 'foo' => 'foov' },
|
656
|
+
'evenlonger' => { 'bar' => 'barv' } } }
|
657
|
+
errors = [
|
658
|
+
{
|
659
|
+
'code' => 'generic.invalid_string',
|
660
|
+
'message' => 'Field `generic.toolong` is longer than maximum length `4`',
|
661
|
+
'reference' => 'generic.toolong'
|
662
|
+
},
|
663
|
+
{
|
664
|
+
'code' => 'generic.invalid_string',
|
665
|
+
'message' => 'Field `generic.evenlonger` is longer than maximum length `4`',
|
666
|
+
'reference' => 'generic.evenlonger'
|
667
|
+
}
|
668
|
+
]
|
669
|
+
|
670
|
+
expect( TestHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( errors )
|
671
|
+
end
|
672
|
+
|
673
|
+
it 'should return correct errors with invalid values' do
|
674
|
+
data = { 'generic' => { 'one' => { 'foo' => 'foov' },
|
675
|
+
'two' => 'not-an-object' } }
|
676
|
+
errors = [
|
677
|
+
{
|
678
|
+
'code' => 'generic.invalid_object',
|
679
|
+
'message' => 'Field `generic.two` is an invalid object',
|
680
|
+
'reference' => 'generic.two'
|
681
|
+
}
|
682
|
+
]
|
683
|
+
|
684
|
+
expect( TestHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( errors )
|
685
|
+
end
|
686
|
+
|
687
|
+
it 'should return correct errors with invalid keys and values' do
|
688
|
+
data = { 'generic' => { 'one' => 'not-an-object',
|
689
|
+
'two' => { 'bar' => 'barv' },
|
690
|
+
'toolong' => 'not-an-object',
|
691
|
+
'evenlonger' => { 'bar' => 'barv' } } }
|
692
|
+
errors = [
|
693
|
+
{
|
694
|
+
'code' => 'generic.invalid_object',
|
695
|
+
'message' => 'Field `generic.one` is an invalid object',
|
696
|
+
'reference' => 'generic.one'
|
697
|
+
},
|
698
|
+
{
|
699
|
+
'code' => 'generic.invalid_string',
|
700
|
+
'message' => 'Field `generic.toolong` is longer than maximum length `4`',
|
701
|
+
'reference' => 'generic.toolong'
|
702
|
+
},
|
703
|
+
{
|
704
|
+
'code' => 'generic.invalid_object',
|
705
|
+
'message' => 'Field `generic.toolong` is an invalid object',
|
706
|
+
'reference' => 'generic.toolong'
|
707
|
+
},
|
708
|
+
{
|
709
|
+
'code' => 'generic.invalid_string',
|
710
|
+
'message' => 'Field `generic.evenlonger` is longer than maximum length `4`',
|
711
|
+
'reference' => 'generic.evenlonger'
|
712
|
+
}
|
713
|
+
]
|
714
|
+
|
715
|
+
expect( TestHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( errors )
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
context '#render' do
|
720
|
+
it 'should only render expected fields' do
|
721
|
+
|
722
|
+
valid = { 'generic' => { 'one' => { 'foo' => '<= 10 long' }, 'values' => { 'foo' => '<= 10 2', 'bar' => 'barv' }, 'two' => { 'bar' => 'barv 2' } } }
|
723
|
+
data = { 'generic' => { 'one' => { 'random' => 'ignore', 'foo' => '<= 10 long' }, 'values' => { 'foo' => '<= 10 2', 'bar' => 'barv', 'hello' => 'there' }, 'two' => { 'bar' => 'barv 2' } } }
|
724
|
+
|
725
|
+
result = TestHashGenericKeyPresenterWithValues.render( data )
|
726
|
+
expect( result ).to eq( valid )
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
context 'generic keys no values' do
|
732
|
+
context '#validate' do
|
733
|
+
it 'should return [] when valid object' do
|
734
|
+
data = { 'generic' => { 'one' => 'anything' } }
|
735
|
+
expect( TestHashGenericKeyPresenterNoValues.validate( data ).errors ).to eq( [] )
|
736
|
+
end
|
737
|
+
|
738
|
+
it 'should return correct errors with invalid keys' do
|
739
|
+
data = { 'generic' => { 'one' => 'anything',
|
740
|
+
'two' => 'anything',
|
741
|
+
'toolong' => 'anything',
|
742
|
+
'evenlonger' => 'anything' } }
|
743
|
+
errors = [
|
744
|
+
{
|
745
|
+
'code' => 'generic.invalid_string',
|
746
|
+
'message' => 'Field `generic.toolong` is longer than maximum length `6`',
|
747
|
+
'reference' => 'generic.toolong'
|
748
|
+
},
|
749
|
+
{
|
750
|
+
'code' => 'generic.invalid_string',
|
751
|
+
'message' => 'Field `generic.evenlonger` is longer than maximum length `6`',
|
752
|
+
'reference' => 'generic.evenlonger'
|
753
|
+
}
|
754
|
+
]
|
755
|
+
|
756
|
+
expect( TestHashGenericKeyPresenterNoValues.validate( data ).errors ).to eq( errors )
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
context '#render' do
|
761
|
+
it 'should render correctly' do
|
762
|
+
|
763
|
+
# Use of "values" is important as it tests for a collision with
|
764
|
+
# an internal same-named property. It's an implementation detail
|
765
|
+
# which the code should deal with internally correctly, leading
|
766
|
+
# to no disernable alteration in expected rendering for callers.
|
767
|
+
|
768
|
+
data = { 'generic' => { 'one' => 'anything 1',
|
769
|
+
'values' => 'should not be overwritten',
|
770
|
+
'two' => 'anything 2' } }
|
771
|
+
|
772
|
+
result = TestHashGenericKeyPresenterNoValues.render( data )
|
773
|
+
expect( result ).to eq( data )
|
774
|
+
end
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
############################################################################
|
779
|
+
|
780
|
+
class TestNestedHashGenericKeyPresenterWithValues < Hoodoo::Presenters::Base
|
781
|
+
schema do
|
782
|
+
object :obj do
|
783
|
+
hash :generic do
|
784
|
+
keys :length => 4 do
|
785
|
+
string :foo, :length => 10
|
786
|
+
text :bar
|
787
|
+
hash :baz do
|
788
|
+
keys do
|
789
|
+
string :inner_string, :length => 5
|
790
|
+
end
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
############################################################################
|
799
|
+
|
800
|
+
context 'nested generic keys with values' do
|
801
|
+
context '#validate' do
|
802
|
+
it 'should return [] when valid object' do
|
803
|
+
data = { 'obj' => { 'generic' => { 'one' => { 'foo' => 'foov' } } } }
|
804
|
+
expect( TestNestedHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( [] )
|
805
|
+
end
|
806
|
+
|
807
|
+
it 'should return correct errors with invalid keys' do
|
808
|
+
data = { 'obj' => { 'generic' => { 'one' => { 'foo' => 'foov' },
|
809
|
+
'two' => { 'bar' => 'barv' },
|
810
|
+
'toolong' => { 'foo' => 'foov' },
|
811
|
+
'evenlonger' => { 'bar' => 'barv' },
|
812
|
+
'ok' => { 'baz' => { 'anything' => { 'inner_string' => 'toolong' } } } } } }
|
813
|
+
errors = [
|
814
|
+
{
|
815
|
+
'code' => 'generic.invalid_string',
|
816
|
+
'message' => 'Field `obj.generic.toolong` is longer than maximum length `4`',
|
817
|
+
'reference' => 'obj.generic.toolong'
|
818
|
+
},
|
819
|
+
{
|
820
|
+
'code' => 'generic.invalid_string',
|
821
|
+
'message' => 'Field `obj.generic.evenlonger` is longer than maximum length `4`',
|
822
|
+
'reference' => 'obj.generic.evenlonger'
|
823
|
+
},
|
824
|
+
{
|
825
|
+
'code' => 'generic.invalid_string',
|
826
|
+
'message' => 'Field `obj.generic.ok.baz.anything.inner_string` is longer than maximum length `5`',
|
827
|
+
'reference' => 'obj.generic.ok.baz.anything.inner_string'
|
828
|
+
}
|
829
|
+
]
|
830
|
+
|
831
|
+
expect( TestNestedHashGenericKeyPresenterWithValues.validate( data ).errors ).to eq( errors )
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
context '#render' do
|
836
|
+
it 'should only render expected fields' do
|
837
|
+
|
838
|
+
valid = { 'obj' => { 'generic' => { 'one' => { 'foo' => '<= 10 long' }, 'values' => { 'foo' => '<= 10 2', 'bar' => 'barv', 'baz' => { 'any' => { 'inner_string' => 'hi' } } }, 'two' => { 'bar' => 'barv 2' } } } }
|
839
|
+
data = { 'number' => 42, 'obj' => { 'generic' => { 'one' => { 'random' => 'ignore', 'foo' => '<= 10 long' }, 'values' => { 'foo' => '<= 10 2', 'bar' => 'barv', 'baz' => { 'any' => { 'hi' => 'there', 'inner_string' => 'hi' } }, 'hello' => 'there' }, 'two' => { 'bar' => 'barv 2' } } } }
|
840
|
+
|
841
|
+
result = TestNestedHashGenericKeyPresenterWithValues.render( data )
|
842
|
+
expect( result ).to eq( valid )
|
843
|
+
end
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
############################################################################
|
848
|
+
|
849
|
+
class TestHashGenericKeyPresenterWithRequirements < Hoodoo::Presenters::Base
|
850
|
+
schema do
|
851
|
+
hash :generic do
|
852
|
+
keys :length => 4, :required => true do
|
853
|
+
string :foo, :length => 10
|
854
|
+
text :bar, :required => true
|
855
|
+
end
|
856
|
+
end
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
############################################################################
|
861
|
+
|
862
|
+
context 'generic keys with requirements' do
|
863
|
+
context '#validate' do
|
864
|
+
it 'should return [] when valid object with keys' do
|
865
|
+
data = { 'generic' => { 'one' => { 'foo' => 'foov', 'bar' => 'hello' } } }
|
866
|
+
expect( TestHashGenericKeyPresenterWithRequirements.validate( data ).errors ).to eq( [] )
|
867
|
+
end
|
868
|
+
|
869
|
+
# The Hash itself isn't required; only its keys are, so if 'nil' that
|
870
|
+
# should not cause an error.
|
871
|
+
#
|
872
|
+
it 'should return [] with valid missing hash' do
|
873
|
+
data = { 'generic' => nil }
|
874
|
+
expect( TestHashGenericKeyPresenterWithRequirements.validate( data ).errors ).to eq( [] )
|
875
|
+
end
|
876
|
+
|
877
|
+
# The Hash itself isn't required; only its keys are, so if present but
|
878
|
+
# empty (no keys), that should cause an error.
|
879
|
+
#
|
880
|
+
it 'should return correct errors with missing hash' do
|
881
|
+
data = { 'generic' => {} }
|
882
|
+
errors = [
|
883
|
+
{
|
884
|
+
'code' => 'generic.required_field_missing',
|
885
|
+
'message' => 'Field `generic` is required (Hash, if present, must contain at least one key)',
|
886
|
+
'reference' => 'generic'
|
887
|
+
}
|
888
|
+
]
|
889
|
+
|
890
|
+
expect( TestHashGenericKeyPresenterWithRequirements.validate( data ).errors ).to eq( errors )
|
891
|
+
end
|
892
|
+
|
893
|
+
it 'should return correct errors with missing keys in hash' do
|
894
|
+
data = { 'generic' => { 'one' => { 'foo' => 'foov' } } }
|
895
|
+
errors = [
|
896
|
+
{
|
897
|
+
'code' => 'generic.required_field_missing',
|
898
|
+
'message' => 'Field `generic.one.bar` is required',
|
899
|
+
'reference' => 'generic.one.bar'
|
900
|
+
}
|
901
|
+
]
|
902
|
+
|
903
|
+
expect( TestHashGenericKeyPresenterWithRequirements.validate( data ).errors ).to eq( errors )
|
904
|
+
end
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
############################################################################
|
909
|
+
|
910
|
+
it 'complains about generic default keys as they are meaningless' do
|
911
|
+
expect {
|
912
|
+
class TestHashGenericKeyPresenterWithMeaninglessDefaults < Hoodoo::Presenters::Base
|
913
|
+
schema do
|
914
|
+
hash :generic_defaults do
|
915
|
+
keys :length => 4, :default => { 'meaningless' => 'complain' } do
|
916
|
+
text :baz
|
917
|
+
end
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
}.to raise_error(RuntimeError)
|
922
|
+
end
|
923
|
+
|
924
|
+
class TestHashGenericKeyPresenterWithDefaults < Hoodoo::Presenters::Base
|
925
|
+
schema do
|
926
|
+
hash :generic_defaults, :default => { 'a_default_key' => { 'baz' => 'merge' }, 'a_nil_key' => nil } do
|
927
|
+
keys :length => 4 do
|
928
|
+
string :foo, :length => 10
|
929
|
+
text :bar, :default => 'default for text field'
|
930
|
+
text :baz
|
931
|
+
end
|
932
|
+
end
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
class TestHashGenericKeyPresenterWithDefaultsExceptHash < Hoodoo::Presenters::Base
|
937
|
+
schema do
|
938
|
+
hash :generic_defaults do
|
939
|
+
keys :length => 4 do
|
940
|
+
string :foo, :length => 10
|
941
|
+
text :bar, :default => 'default for text field'
|
942
|
+
text :baz
|
943
|
+
end
|
944
|
+
end
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
############################################################################
|
949
|
+
|
950
|
+
context 'generic keys with defaults' do
|
951
|
+
context '#render' do
|
952
|
+
|
953
|
+
# The hash itself has a default set, so if the hash key is omitted we
|
954
|
+
# expect to get the canned default hash instead. This outer default is
|
955
|
+
# rendered, so the key(s) it specifies get individually run through
|
956
|
+
# the renderer. If the value is nil, it'll gain the whole-value default.
|
957
|
+
# Otherwise, it gains in-block defaults (if any).
|
958
|
+
#
|
959
|
+
it 'should render with correct default for whole hash (1)' do
|
960
|
+
result = TestHashGenericKeyPresenterWithDefaults.render( {} )
|
961
|
+
|
962
|
+
expect( result ).to eq({
|
963
|
+
'generic_defaults' => {
|
964
|
+
'a_default_key' => { 'bar' => 'default for text field', 'baz' => 'merge' },
|
965
|
+
'a_nil_key' => nil
|
966
|
+
}
|
967
|
+
})
|
968
|
+
end
|
969
|
+
|
970
|
+
# Explicit nil means nil, but at the top level we have to treat it as an
|
971
|
+
# empty hash so it'll give the same result.
|
972
|
+
#
|
973
|
+
it 'should render with correct default for whole hash (2)' do
|
974
|
+
result = TestHashGenericKeyPresenterWithDefaults.render( nil )
|
975
|
+
|
976
|
+
expect( result ).to eq({
|
977
|
+
'generic_defaults' => {
|
978
|
+
'a_default_key' => { 'bar' => 'default for text field', 'baz' => 'merge' },
|
979
|
+
'a_nil_key' => nil
|
980
|
+
}
|
981
|
+
})
|
982
|
+
end
|
983
|
+
|
984
|
+
# If we explicitly give a value for the hash, then that should override
|
985
|
+
# the hash-wide default, even if empty...
|
986
|
+
#
|
987
|
+
it 'should render with correct defaults for hash keys (1)' do
|
988
|
+
data = { 'generic_defaults' => {} }
|
989
|
+
result = TestHashGenericKeyPresenterWithDefaults.render( data )
|
990
|
+
|
991
|
+
expect( result ).to eq({
|
992
|
+
'generic_defaults' => {}
|
993
|
+
})
|
994
|
+
end
|
995
|
+
|
996
|
+
# ...However explicit nil means nil...
|
997
|
+
#
|
998
|
+
it 'should render with correct defaults for hash keys (2)' do
|
999
|
+
data = { 'generic_defaults' => nil }
|
1000
|
+
result = TestHashGenericKeyPresenterWithDefaults.render( data )
|
1001
|
+
expect( result ).to eq(data)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
# ...and explicitly defined keys with nil values should be nil too.
|
1005
|
+
#
|
1006
|
+
it 'should render with correct defaults for hash keys (3)' do
|
1007
|
+
data = { 'generic_defaults' => { 'hello' => nil, 'goodbye' => {}, 'another' => { 'foo' => 'present', 'bar' => 'also present' } } }
|
1008
|
+
result = TestHashGenericKeyPresenterWithDefaults.render( data )
|
1009
|
+
|
1010
|
+
expect( result ).to eq({
|
1011
|
+
'generic_defaults' => {
|
1012
|
+
'hello' => nil,
|
1013
|
+
'goodbye' => { 'bar' => 'default for text field' },
|
1014
|
+
'another' => { 'foo' => 'present', 'bar' => 'also present' }
|
1015
|
+
}
|
1016
|
+
})
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
# No hash default now. An empty hash can only be rendered as an empty
|
1020
|
+
# hash, because we don't have any default key names or hash-wide default
|
1021
|
+
# to use as a template.
|
1022
|
+
#
|
1023
|
+
it 'should render with correct default for whole hash (1)' do
|
1024
|
+
result = TestHashGenericKeyPresenterWithDefaultsExceptHash.render( {} )
|
1025
|
+
expect( result ).to eq({})
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
# Should behave the same with 'nil'.
|
1029
|
+
#
|
1030
|
+
it 'should render with correct default for whole hash (2)' do
|
1031
|
+
result = TestHashGenericKeyPresenterWithDefaultsExceptHash.render( nil )
|
1032
|
+
expect( result ).to eq({})
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
# If we explicitly give a value for the hash, should get the empty hash
|
1036
|
+
# recorded...
|
1037
|
+
#
|
1038
|
+
it 'should render with correct defaults for hash keys (1)' do
|
1039
|
+
data = { 'generic_defaults' => {} }
|
1040
|
+
result = TestHashGenericKeyPresenterWithDefaultsExceptHash.render( data )
|
1041
|
+
expect( result ).to eq({ 'generic_defaults' => {} })
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
# ...explicit nil means nil...
|
1045
|
+
#
|
1046
|
+
it 'should render with correct defaults for hash keys (2)' do
|
1047
|
+
data = { 'generic_defaults' => nil }
|
1048
|
+
result = TestHashGenericKeyPresenterWithDefaultsExceptHash.render( data )
|
1049
|
+
expect( result ).to eq({ 'generic_defaults' => nil })
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
# ...and when we have keys supplied, the usual default rules should apply.
|
1053
|
+
#
|
1054
|
+
it 'should render with correct defaults for hash keys (3)' do
|
1055
|
+
data = { 'generic_defaults' => { 'hello' => nil, 'goodbye' => {}, 'another' => { 'foo' => 'present', 'bar' => 'also present' } } }
|
1056
|
+
result = TestHashGenericKeyPresenterWithDefaultsExceptHash.render( data )
|
1057
|
+
|
1058
|
+
expect( result ).to eq({
|
1059
|
+
'generic_defaults' => {
|
1060
|
+
'hello' => nil,
|
1061
|
+
'goodbye' => { 'bar' => 'default for text field' },
|
1062
|
+
'another' => { 'foo' => 'present', 'bar' => 'also present' }
|
1063
|
+
}
|
1064
|
+
})
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
end
|