respect 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +289 -0
- data/RELATED_WORK.md +40 -0
- data/RELEASE_NOTES.md +23 -0
- data/Rakefile +31 -0
- data/STATUS_MATRIX.html +137 -0
- data/lib/respect.rb +231 -0
- data/lib/respect/any_schema.rb +22 -0
- data/lib/respect/array_def.rb +28 -0
- data/lib/respect/array_schema.rb +203 -0
- data/lib/respect/boolean_schema.rb +32 -0
- data/lib/respect/composite_schema.rb +86 -0
- data/lib/respect/core_statements.rb +206 -0
- data/lib/respect/datetime_schema.rb +27 -0
- data/lib/respect/def_without_name.rb +6 -0
- data/lib/respect/divisible_by_validator.rb +20 -0
- data/lib/respect/doc_helper.rb +24 -0
- data/lib/respect/doc_parser.rb +37 -0
- data/lib/respect/dsl_dumper.rb +181 -0
- data/lib/respect/equal_to_validator.rb +20 -0
- data/lib/respect/fake_name_proxy.rb +116 -0
- data/lib/respect/float_schema.rb +27 -0
- data/lib/respect/format_validator.rb +136 -0
- data/lib/respect/global_def.rb +79 -0
- data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/greater_than_validator.rb +19 -0
- data/lib/respect/has_constraints.rb +34 -0
- data/lib/respect/hash_def.rb +40 -0
- data/lib/respect/hash_schema.rb +218 -0
- data/lib/respect/in_validator.rb +19 -0
- data/lib/respect/integer_schema.rb +27 -0
- data/lib/respect/ip_addr_schema.rb +23 -0
- data/lib/respect/ipv4_addr_schema.rb +27 -0
- data/lib/respect/ipv6_addr_schema.rb +27 -0
- data/lib/respect/items_def.rb +21 -0
- data/lib/respect/json_schema_html_formatter.rb +143 -0
- data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/less_than_validator.rb +19 -0
- data/lib/respect/match_validator.rb +19 -0
- data/lib/respect/max_length_validator.rb +20 -0
- data/lib/respect/min_length_validator.rb +20 -0
- data/lib/respect/multiple_of_validator.rb +10 -0
- data/lib/respect/null_schema.rb +26 -0
- data/lib/respect/numeric_schema.rb +33 -0
- data/lib/respect/org3_dumper.rb +213 -0
- data/lib/respect/regexp_schema.rb +19 -0
- data/lib/respect/schema.rb +285 -0
- data/lib/respect/schema_def.rb +16 -0
- data/lib/respect/string_schema.rb +21 -0
- data/lib/respect/unit_test_helper.rb +37 -0
- data/lib/respect/uri_schema.rb +23 -0
- data/lib/respect/utc_time_schema.rb +17 -0
- data/lib/respect/validator.rb +51 -0
- data/lib/respect/version.rb +3 -0
- data/test/any_schema_test.rb +79 -0
- data/test/array_def_test.rb +113 -0
- data/test/array_schema_test.rb +487 -0
- data/test/boolean_schema_test.rb +89 -0
- data/test/composite_schema_test.rb +30 -0
- data/test/datetime_schema_test.rb +83 -0
- data/test/doc_helper_test.rb +34 -0
- data/test/doc_parser_test.rb +109 -0
- data/test/dsl_dumper_test.rb +395 -0
- data/test/fake_name_proxy_test.rb +138 -0
- data/test/float_schema_test.rb +146 -0
- data/test/format_validator_test.rb +224 -0
- data/test/hash_def_test.rb +126 -0
- data/test/hash_schema_test.rb +613 -0
- data/test/integer_schema_test.rb +142 -0
- data/test/ip_addr_schema_test.rb +78 -0
- data/test/ipv4_addr_schema_test.rb +71 -0
- data/test/ipv6_addr_schema_test.rb +71 -0
- data/test/json_schema_html_formatter_test.rb +214 -0
- data/test/null_schema_test.rb +46 -0
- data/test/numeric_schema_test.rb +294 -0
- data/test/org3_dumper_test.rb +784 -0
- data/test/regexp_schema_test.rb +54 -0
- data/test/respect_test.rb +108 -0
- data/test/schema_def_test.rb +405 -0
- data/test/schema_test.rb +290 -0
- data/test/string_schema_test.rb +209 -0
- data/test/support/circle.rb +11 -0
- data/test/support/color.rb +24 -0
- data/test/support/point.rb +11 -0
- data/test/support/respect/circle_schema.rb +16 -0
- data/test/support/respect/color_def.rb +19 -0
- data/test/support/respect/color_schema.rb +33 -0
- data/test/support/respect/point_schema.rb +19 -0
- data/test/support/respect/rgba_schema.rb +20 -0
- data/test/support/respect/universal_validator.rb +25 -0
- data/test/support/respect/user_macros.rb +12 -0
- data/test/support/rgba.rb +11 -0
- data/test/test_helper.rb +90 -0
- data/test/uri_schema_test.rb +54 -0
- data/test/utc_time_schema_test.rb +63 -0
- data/test/validator_test.rb +22 -0
- metadata +288 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
class Color
|
2
|
+
class FormatError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def from_string(str)
|
7
|
+
if str.to_s =~ /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/
|
8
|
+
Color.new($1.to_i(16), $2.to_i(16), $3.to_i(16), $4.to_i(16))
|
9
|
+
else
|
10
|
+
raise FormatError, "'#{str}' does not match color regexp"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(red, green, blue, alpha)
|
16
|
+
@red, @green, @blue, @alpha = red, green, blue, alpha
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :red, :green, :blue, :alpha
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
@red == other.red && @green == other.green && @blue == other.blue && @alpha == other.alpha
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a custom type based on another custom type.
|
4
|
+
class CircleSchema < CompositeSchema
|
5
|
+
def schema_definition
|
6
|
+
HashSchema.define do |s|
|
7
|
+
s.point "center"
|
8
|
+
s.float "radius", greater_than: 0.0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def sanitize(doc)
|
13
|
+
Circle.new(doc[:center], doc[:radius])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Respect
|
2
|
+
class ColorDef < GlobalDef
|
3
|
+
def initialize(options = {})
|
4
|
+
@color_schema = ColorSchema.new(options)
|
5
|
+
end
|
6
|
+
|
7
|
+
[ :red, :green, :blue, :alpha ].each do |name|
|
8
|
+
define_method(name) do |value|
|
9
|
+
@color_schema.send("#{name}=", value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def evaluation_result
|
16
|
+
@color_schema
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Respect
|
2
|
+
class ColorSchema < Schema
|
3
|
+
|
4
|
+
public_class_method :new
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
super
|
8
|
+
@red, @green, @blue, @alpha = 0, 0, 0, 0
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :red, :green, :blue, :alpha
|
12
|
+
|
13
|
+
def validate(doc)
|
14
|
+
color = nil
|
15
|
+
begin
|
16
|
+
color = Color.from_string(doc.to_s)
|
17
|
+
rescue Color::FormatError => e
|
18
|
+
raise ValidationError, "invalid color: #{e.message}"
|
19
|
+
end
|
20
|
+
[ :red, :green, :blue, :alpha ].each do |part|
|
21
|
+
if expected = send(part)
|
22
|
+
value = color.send(part)
|
23
|
+
unless value == expected
|
24
|
+
raise ValidationError, "color part #{part} is #{value} but should be #{expected}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self.sanitized_object = color
|
29
|
+
end
|
30
|
+
|
31
|
+
end # class ColorSchema
|
32
|
+
|
33
|
+
end # module Respect
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a custom type providing both a composition macro and a
|
4
|
+
# sanitizer block.
|
5
|
+
class PointSchema < CompositeSchema
|
6
|
+
|
7
|
+
def schema_definition
|
8
|
+
HashSchema.define do |s|
|
9
|
+
s.float "x"
|
10
|
+
s.float "y"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sanitize(doc)
|
15
|
+
Point.new(doc["x"], doc["y"])
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the schema hierarchy
|
3
|
+
# with a composite schema based on an array schema.
|
4
|
+
class RgbaSchema < CompositeSchema
|
5
|
+
def schema_definition
|
6
|
+
ArraySchema.define do |s|
|
7
|
+
s.items do |s|
|
8
|
+
s.color_channel # red
|
9
|
+
s.color_channel # green
|
10
|
+
s.color_channel # blue
|
11
|
+
s.color_channel # alpha
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def sanitize(doc)
|
17
|
+
Rgba.new(doc[0], doc[1], doc[2], doc[3])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test class proving that users can easily extend the validator hierarchy
|
3
|
+
# with their own ones.
|
4
|
+
class UniversalValidator < Validator
|
5
|
+
|
6
|
+
def initialize(enabled)
|
7
|
+
@enabled = enabled
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate(value)
|
11
|
+
if @enabled
|
12
|
+
unless value == 42
|
13
|
+
raise ValidationError, "#{value} is not a universal value"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def to_h_org3
|
21
|
+
{ "minimum" => 42, "maximum" => 42 }
|
22
|
+
end
|
23
|
+
|
24
|
+
end # class UniversalValidator
|
25
|
+
end # module Respect
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Respect
|
2
|
+
# Test module proving that users can easily extend the definition DSL
|
3
|
+
# with their own macros bundled in their own modules organized as they
|
4
|
+
# want.
|
5
|
+
module UserMacros
|
6
|
+
def color_channel(name)
|
7
|
+
float name, in: 0.0..1.0
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
extend_dsl_with(UserMacros)
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Rgba
|
2
|
+
def initialize(red, green, blue, alpha)
|
3
|
+
@red, @green, @blue, @alpha = red, green, blue, alpha
|
4
|
+
end
|
5
|
+
|
6
|
+
attr_reader :red, :green, :blue, :alpha
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
@red == other.red && @green == other.green && @blue == other.blue && @alpha == other.alpha
|
10
|
+
end
|
11
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'debugger'
|
3
|
+
|
4
|
+
require 'respect'
|
5
|
+
|
6
|
+
# Test that "hash" methods has been removed from GlabelDef as soon as we load "respect".
|
7
|
+
# We cannot do it in HashSchema since the "hash" method maybe call before hand.
|
8
|
+
if Respect::GlobalDef.new.respond_to? :hash
|
9
|
+
raise "'hash' method should have been removed before Respect::HashSchema class is loaded."
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'respect/unit_test_helper'
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
# Similar to assert_raises but return the exception object caught.
|
16
|
+
def assert_exception(exception_class, message = nil, &block)
|
17
|
+
begin
|
18
|
+
block.call
|
19
|
+
assert false, message
|
20
|
+
rescue exception_class => e
|
21
|
+
e
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Load support files
|
27
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
28
|
+
|
29
|
+
# It *MUST* be defined before EndUserDSLStatement.
|
30
|
+
module Respect
|
31
|
+
# A class to test DSL extension.
|
32
|
+
class CoreDef < GlobalDef
|
33
|
+
include_core_statements
|
34
|
+
include DefWithoutName
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A module to test statement extension helper.
|
39
|
+
module EndUserDSLStatement
|
40
|
+
|
41
|
+
def id(name = "id")
|
42
|
+
integer name, greater_than: 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def call_to_kernel
|
46
|
+
# The point is to call an instance method of the Kernel module.
|
47
|
+
integer "kernel", equal_to: Integer(0)
|
48
|
+
end
|
49
|
+
|
50
|
+
def call_to_object
|
51
|
+
# The point is to call an instance method of the Object class.
|
52
|
+
string "object", equal_to: self.class.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
Respect.extend_dsl_with(EndUserDSLStatement)
|
58
|
+
|
59
|
+
FORMAT_HELPER_STATEMENTS_LIST = [
|
60
|
+
:phone_number,
|
61
|
+
:hostname,
|
62
|
+
:email,
|
63
|
+
]
|
64
|
+
|
65
|
+
PRIMITIVE_STATEMENTS_LIST = [
|
66
|
+
:integer,
|
67
|
+
:string,
|
68
|
+
:any,
|
69
|
+
:boolean,
|
70
|
+
:null,
|
71
|
+
:float,
|
72
|
+
:numeric,
|
73
|
+
:uri,
|
74
|
+
:regexp,
|
75
|
+
:datetime,
|
76
|
+
:ipv4_addr,
|
77
|
+
:ipv6_addr,
|
78
|
+
:ip_addr,
|
79
|
+
]
|
80
|
+
|
81
|
+
TERMINAL_STATEMENTS_LIST = FORMAT_HELPER_STATEMENTS_LIST + PRIMITIVE_STATEMENTS_LIST
|
82
|
+
|
83
|
+
COMPOSITE_STATEMENTS_LIST = [
|
84
|
+
:hash,
|
85
|
+
:array,
|
86
|
+
]
|
87
|
+
|
88
|
+
BASIC_STATEMENTS_LIST = TERMINAL_STATEMENTS_LIST + COMPOSITE_STATEMENTS_LIST
|
89
|
+
|
90
|
+
require "mocha/setup"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class URISchemaTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_uri_schema_creates_uri_object
|
6
|
+
s = Respect::URISchema.new
|
7
|
+
assert_nil s.sanitized_object
|
8
|
+
assert_schema_validate s, "http://foo.com"
|
9
|
+
assert s.sanitized_object.is_a?(URI::Generic)
|
10
|
+
assert_equal "http://foo.com", s.sanitized_object.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_uri_schema_relies_on_format_validator
|
14
|
+
doc = "http://foo.com"
|
15
|
+
Respect::FormatValidator.any_instance.stubs(:validate_uri).with(doc).at_least_once
|
16
|
+
Respect::URISchema.new.validate(doc)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_failed_validation_reset_sanitized_object
|
20
|
+
s = Respect::URISchema.new
|
21
|
+
assert_schema_validate(s, "http://foo.com")
|
22
|
+
assert_not_nil(s.sanitized_object)
|
23
|
+
assert_schema_invalidate(s, "<")
|
24
|
+
assert_nil(s.sanitized_object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_allow_nil
|
28
|
+
s = Respect::URISchema.new(allow_nil: true)
|
29
|
+
assert s.allow_nil?
|
30
|
+
assert_schema_validate s, nil
|
31
|
+
assert_equal(nil, s.sanitized_object)
|
32
|
+
assert_schema_validate s, "http://foo.com"
|
33
|
+
assert_not_nil(s.sanitized_object)
|
34
|
+
assert_schema_invalidate(s, "<")
|
35
|
+
assert_nil(s.sanitized_object)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_disallow_nil
|
39
|
+
s = Respect::URISchema.new
|
40
|
+
assert !s.allow_nil?
|
41
|
+
exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
|
42
|
+
assert_match exception.message, /\bURISchema\b/
|
43
|
+
assert_equal(nil, s.sanitized_object)
|
44
|
+
assert_schema_validate s, "http://foo.com"
|
45
|
+
assert_not_nil(s.sanitized_object)
|
46
|
+
assert_schema_invalidate(s, "<")
|
47
|
+
assert_nil(s.sanitized_object)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_validate_uri_object
|
51
|
+
s = Respect::URISchema.new
|
52
|
+
assert_schema_validate(s, URI.parse("http://foo.com"))
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class UTCTimeSchemaTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_utc_time_schema_creates_time_object
|
6
|
+
s = Respect::UTCTimeSchema.new
|
7
|
+
assert_nil s.sanitized_object
|
8
|
+
t = Time.now.to_i
|
9
|
+
assert_schema_validate s, t.to_s
|
10
|
+
assert_equal Time, s.sanitized_object.class
|
11
|
+
assert_equal(t, s.sanitized_object.to_i)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_utc_time_schema_accept_float
|
15
|
+
s = Respect::UTCTimeSchema.new
|
16
|
+
assert_nil s.sanitized_object
|
17
|
+
t = Time.now.to_f
|
18
|
+
assert_schema_validate s, t.to_s
|
19
|
+
assert_equal Time, s.sanitized_object.class
|
20
|
+
assert_equal(t, s.sanitized_object.to_f)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_utc_time_schema_do_not_accept_negative
|
24
|
+
s = Respect::UTCTimeSchema.new
|
25
|
+
begin
|
26
|
+
s.validate(-1)
|
27
|
+
assert false
|
28
|
+
rescue Respect::ValidationError => e
|
29
|
+
assert_match(/-1/, e.message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_failed_validation_reset_sanitized_object
|
34
|
+
s = Respect::UTCTimeSchema.new
|
35
|
+
assert_schema_validate(s, 42)
|
36
|
+
assert_not_nil(s.sanitized_object)
|
37
|
+
assert_schema_invalidate(s, "*")
|
38
|
+
assert_nil(s.sanitized_object)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_allow_nil
|
42
|
+
s = Respect::UTCTimeSchema.new(allow_nil: true)
|
43
|
+
assert s.allow_nil?
|
44
|
+
assert_schema_validate s, nil
|
45
|
+
assert_equal(nil, s.sanitized_object)
|
46
|
+
assert_schema_validate s, 42
|
47
|
+
assert_not_nil(s.sanitized_object)
|
48
|
+
assert_schema_invalidate(s, "wrong")
|
49
|
+
assert_nil(s.sanitized_object)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_disallow_nil
|
53
|
+
s = Respect::UTCTimeSchema.new
|
54
|
+
assert !s.allow_nil?
|
55
|
+
exception = assert_exception(Respect::ValidationError) { s.validate(nil) }
|
56
|
+
assert_match exception.message, /\bUTCTimeSchema\b/
|
57
|
+
assert_equal(nil, s.sanitized_object)
|
58
|
+
assert_schema_validate s, 42
|
59
|
+
assert_not_nil(s.sanitized_object)
|
60
|
+
assert_schema_invalidate(s, "wrong")
|
61
|
+
assert_nil(s.sanitized_object)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ValidatorTest < Test::Unit::TestCase
|
4
|
+
def test_constraint_name
|
5
|
+
assert_equal "equal_to", Respect::EqualToValidator.constraint_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_end_user_validator
|
9
|
+
s = Respect::IntegerSchema.new(universal: true)
|
10
|
+
assert_schema_invalidate s, 52
|
11
|
+
assert_schema_validate s, 42
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_end_user_validate_get_called
|
15
|
+
value = 1664
|
16
|
+
v = Respect::UniversalValidator.new(true)
|
17
|
+
Respect::UniversalValidator.expects(:new).with(true).returns(v)
|
18
|
+
v.stubs(:validate).with(value).at_least_once
|
19
|
+
Respect::IntegerSchema.new(universal: true).validate(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|