wsdsl 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.4.0
@@ -0,0 +1,83 @@
1
+ # include this module in WSDSL
2
+ # to add response verification methods.
3
+ #
4
+ module JSONResponseVerification
5
+
6
+ # Validates a hash against the service's response description.
7
+ #
8
+ # @return [Array<TrueClass, FalseClass, Array<String>>] True/false and an array of errors.
9
+ def validate_hash_response(hash)
10
+ errors = []
11
+ response.nodes.each do |node|
12
+ if node.name
13
+ # Verify that the named node exists in the hash
14
+ unless hash.has_key?(node.name.to_s)
15
+ errors << json_response_error(node, hash)
16
+ return [false, errors]
17
+ end
18
+ end
19
+ errors += validate_hash_against_template_node(hash, node)
20
+ end
21
+
22
+ [errors.empty?, errors]
23
+ end
24
+
25
+ private
26
+
27
+ # Recursively validates a hash representing a json response.
28
+ #
29
+ # @param [Hash>] hash the hash to verify.
30
+ # @param [WDSL::Response::Element>] node the reference element defined in the response description.
31
+ # @param [<TrueClass, FalseClass>] nested if the node/hash to verify is nested or not. If nested, the method expects to get the subhash
32
+ # & won't verify that the name exists since it was done a level higher.
33
+ # @param [Arrays<String>] errors the list of errors encountered while verifying.
34
+ #
35
+ # @return [<TrueClass, FalseClass>]
36
+ def validate_hash_against_template_node(hash, node, nested=false, errors=[])
37
+ if hash.nil?
38
+ errors << json_response_error(node, hash)
39
+ return errors
40
+ end
41
+
42
+ if node.name && !nested
43
+ if hash.has_key?(node.name.to_s)
44
+ subhash = hash[node.name.to_s]
45
+ else
46
+ errors << json_response_error(node, hash) unless hash.has_key?(node.name.to_s)
47
+ end
48
+ end
49
+
50
+ node.properties.each do |prop|
51
+ subhash ||= hash
52
+ errors << json_response_error(prop, subhash) unless subhash.has_key?(prop.name.to_s)
53
+ errors << json_response_error(prop, subhash, true) unless valid_hash_type?(subhash, prop)
54
+ end
55
+
56
+ node.objects.each do |obj|
57
+ # recursive call
58
+ validate_hash_against_template_node(subhash[obj.name.to_s], obj, true, errors)
59
+ end if node.objects
60
+
61
+ errors
62
+ end
63
+
64
+ def json_response_error(el_or_attr, hash, type_error=false)
65
+ if el_or_attr.is_a?(WSDSL::Response::Element)
66
+ "#{el_or_attr.name || 'top level'} Node/Object/Element is missing"
67
+ elsif type_error
68
+ "#{el_or_attr.name || el_or_attr.inspect} was of wrong type"
69
+ else
70
+ "#{el_or_attr.name || el_or_attr.inspect} is missing in #{hash.inspect}"
71
+ end
72
+ end
73
+
74
+ def valid_hash_type?(hash, prop_template)
75
+ type = prop_template.type
76
+ return true if type.nil?
77
+ rule = ParamsVerification.type_validations[type.to_sym]
78
+ return true if rule.nil?
79
+ attribute = hash[prop_template.name.to_s]
80
+ attribute.to_s =~ rule
81
+ end
82
+
83
+ end
@@ -120,6 +120,7 @@ module ParamsVerification
120
120
  elsif rule.options[:type]
121
121
  verify_cast(param_name, param_value, rule.options[:type])
122
122
  end
123
+
123
124
  if rule.options[:options] || rule.options[:in]
124
125
  choices = rule.options[:options] || rule.options[:in]
125
126
  if rule.options[:type]
@@ -127,9 +128,10 @@ module ParamsVerification
127
128
  param_value = params[param_name] = type_cast_value(rule.options[:type], param_value)
128
129
  end
129
130
  raise InvalidParamValue, "Value for parameter '#{param_name}' (#{param_value}) is not in the allowed set of values." unless choices.include?(param_value)
131
+ # You can have a "in" rule that also applies a min value since they are mutually exclusive
130
132
  elsif rule.options[:minvalue]
131
133
  min = rule.options[:minvalue]
132
- raise InvalidParamValue, "Value for parameter '#{param_name}' is lower than the min accepted value (#{min})." if param_value.to_i >= min
134
+ raise InvalidParamValue, "Value for parameter '#{param_name}' is lower than the min accepted value (#{min})." if param_value.to_i < min
133
135
  end
134
136
  # Returns the updated params
135
137
 
@@ -19,6 +19,9 @@ class WSDSL
19
19
  @arrays = []
20
20
  end
21
21
 
22
+ # Lists all top level simple elements and array elements.
23
+ #
24
+ # @return [Array<WSDSL::Response::Element, WSDSL::Response::Array>]
22
25
  def nodes
23
26
  elements + arrays
24
27
  end
@@ -48,7 +51,7 @@ class WSDSL
48
51
  # response.element(:name => "my_stats", :type => 'Leaderboard')
49
52
  # end
50
53
  #
51
- # @return [Array<WSDSL::Response::Element>]
54
+ # @return [WSDSL::Response::Element]
52
55
  # @api public
53
56
  def element(opts={})
54
57
  el = Element.new(opts[:name], opts[:type])
@@ -57,6 +60,14 @@ class WSDSL
57
60
  el
58
61
  end
59
62
 
63
+ # Defines an anonymous element
64
+ # Useful for JSON response description
65
+ #
66
+ # @return [WSDSL::Response::Element]
67
+ def object
68
+ yield element
69
+ end
70
+
60
71
  # Returns a response element object based on its name
61
72
  # @param [String, Symbol] The element name we want to match
62
73
  #
@@ -102,5 +102,23 @@ describe "WSDSL JSON response description" do
102
102
  name = @root_node.properties.find{|prop| prop.name == :name}
103
103
  name.opts[:mock].should == "test"
104
104
  end
105
+
106
+ it "should allow an anonymous object at the root of the response" do
107
+ service = describe_service "json_anonymous_obj" do |service|
108
+ service.formats :json
109
+ service.response do |response|
110
+ response.object do |obj|
111
+ obj.integer :id
112
+ obj.string :foo
113
+ end
114
+ end
115
+ end
116
+ response = service.response
117
+ response.nodes.should_not be_empty
118
+ obj = response.nodes.first
119
+ obj.should_not be_nil
120
+ obj.properties.find{|prop| prop.name == :id}.should_not be_nil
121
+ obj.properties.find{|prop| prop.name == :foo}.should_not be_nil
122
+ end
105
123
 
106
124
  end
@@ -0,0 +1,92 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+ require File.expand_path("../lib/json_response_verification", File.dirname(__FILE__))
3
+
4
+ WSDSL.send(:include, JSONResponseVerification)
5
+
6
+ describe "JSON response verification" do
7
+
8
+ before :all do
9
+ @service = describe_service "json_response_verification" do |service|
10
+ service.response do |response|
11
+ response.element(:name => :user) do |user|
12
+ user.integer :id
13
+ user.string :name
14
+ user.datetime :created_at
15
+ user.object :creds do |creds|
16
+ creds.integer :id
17
+ creds.float :price
18
+ creds.boolean :enabled
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ @second_service = describe_service "anonym_obj_json_response_verification" do |service|
25
+ service.response do |response|
26
+ response.object do |user|
27
+ user.integer :id
28
+ user.string :name
29
+ user.datetime :created_at
30
+ user.object :creds do |creds|
31
+ creds.integer :id
32
+ creds.float :price
33
+ creds.boolean :enabled
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ def valid_response(namespaced=true)
42
+ response = {
43
+ "id" => 1,
44
+ "name" => "matt",
45
+ "created_at" => "2011-09-22T16:32:46-07:00",
46
+ "creds" => { "id" => 42, "price" => 2010.07, "enabled" => false }
47
+ }
48
+ namespaced ? {"user" => response} : response
49
+ end
50
+
51
+ it "should validate the response" do
52
+ valid, errors = @service.validate_hash_response(valid_response)
53
+ valid.should be_true
54
+ errors.should be_empty
55
+ end
56
+
57
+ it "should detect that the response is missing the top level object" do
58
+ response = valid_response
59
+ response.delete("user")
60
+ valid, errors = @service.validate_hash_response(response)
61
+ valid.should be_false
62
+ errors.should_not be_empty
63
+ end
64
+
65
+ it "should detect that a property type is wrong" do
66
+ response = valid_response
67
+ response["user"]["id"] = 'test'
68
+ valid, errors = @service.validate_hash_response(response)
69
+ valid.should be_false
70
+ errors.should_not be_empty
71
+ errors.first.should match(/id/)
72
+ errors.first.should match(/wrong type/)
73
+ end
74
+
75
+ it "should detect that a nested object is missing" do
76
+ response = valid_response
77
+ response["user"].delete("creds")
78
+ valid, errors = @service.validate_hash_response(response)
79
+ valid.should be_false
80
+ errors.should_not be_empty
81
+ errors.first.should match(/creds/)
82
+ errors.first.should match(/missing/)
83
+ end
84
+
85
+ it "should validate non namespaced responses" do
86
+ valid, errors = @second_service.validate_hash_response(valid_response(false))
87
+ valid.should be_true
88
+ errors.should be_empty
89
+ end
90
+
91
+
92
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{wsdsl}
8
- s.version = "0.3.3"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Matt Aimonetti}]
12
- s.date = %q{2011-09-12}
12
+ s.date = %q{2011-09-23}
13
13
  s.description = %q{A Ruby DSL describing Web Services without implementation details.}
14
14
  s.email = %q{mattaimonetti@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  "lib/framework_ext/sinatra.rb",
26
26
  "lib/framework_ext/sinatra_controller.rb",
27
27
  "lib/inflection.rb",
28
+ "lib/json_response_verification.rb",
28
29
  "lib/params.rb",
29
30
  "lib/params_verification.rb",
30
31
  "lib/response.rb",
@@ -33,6 +34,7 @@ Gem::Specification.new do |s|
33
34
  "spec/hello_world_controller.rb",
34
35
  "spec/hello_world_service.rb",
35
36
  "spec/json_response_description_spec.rb",
37
+ "spec/json_response_verification_spec.rb",
36
38
  "spec/params_verification_spec.rb",
37
39
  "spec/preferences_service.rb",
38
40
  "spec/spec_helper.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wsdsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-12 00:00:00.000000000Z
12
+ date: 2011-09-23 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: A Ruby DSL describing Web Services without implementation details.
15
15
  email: mattaimonetti@gmail.com
@@ -27,6 +27,7 @@ files:
27
27
  - lib/framework_ext/sinatra.rb
28
28
  - lib/framework_ext/sinatra_controller.rb
29
29
  - lib/inflection.rb
30
+ - lib/json_response_verification.rb
30
31
  - lib/params.rb
31
32
  - lib/params_verification.rb
32
33
  - lib/response.rb
@@ -35,6 +36,7 @@ files:
35
36
  - spec/hello_world_controller.rb
36
37
  - spec/hello_world_service.rb
37
38
  - spec/json_response_description_spec.rb
39
+ - spec/json_response_verification_spec.rb
38
40
  - spec/params_verification_spec.rb
39
41
  - spec/preferences_service.rb
40
42
  - spec/spec_helper.rb