rod-rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/collection_proxy'
4
+
5
+ module Rod
6
+ module Rest
7
+ describe CollectionProxy do
8
+ let(:collection) { CollectionProxy.new(mercedes_proxy,association_name,size,client) }
9
+ let(:mercedes_proxy) { Object.new }
10
+ let(:association_name) { "drivers" }
11
+ let(:size) { 0 }
12
+ let(:client) { Object.new }
13
+
14
+ describe "#empty?" do
15
+ describe "with 0 elements" do
16
+ it "is empty" do
17
+ collection.empty?.should == true
18
+ end
19
+ end
20
+
21
+ describe "with 1 element" do
22
+ let(:size) { 1 }
23
+
24
+ it "is not empty" do
25
+ collection.empty?.should == false
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "#size" do
31
+ describe "with 5 elements" do
32
+ let(:size) { 5 }
33
+
34
+ it "has size of 5" do
35
+ collection.size.should == size
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "with car proxy" do
41
+ let(:car_type) { "Car" }
42
+ let(:mercedes_300_id) { 1 }
43
+
44
+ describe "with 3 drivers" do
45
+ let(:size) { 3 }
46
+ let(:schumaher) { Object.new }
47
+ let(:kubica) { Object.new }
48
+ let(:alonzo) { Object.new }
49
+
50
+ describe "#[index]" do
51
+ before do
52
+ stub(client).fetch_related_object(mercedes_proxy,association_name,1) { kubica }
53
+ stub(client).fetch_related_object(mercedes_proxy,association_name,5) { raise MissingResource.new("/cars/#{mercedes_300_id}/drivers/5") }
54
+ end
55
+
56
+ it "returns drivers by index" do
57
+ collection[1].should == kubica
58
+ end
59
+
60
+ it "returns nil in case of out of bounds driver" do
61
+ collection[5].should == nil
62
+ end
63
+ end
64
+
65
+ describe "#first" do
66
+ before do
67
+ stub(client).fetch_related_object(mercedes_proxy,association_name,0) { schumaher }
68
+ end
69
+
70
+ it "returns the first driver" do
71
+ collection.first.should == schumaher
72
+ end
73
+ end
74
+
75
+ describe "#last" do
76
+ before do
77
+ stub(client).fetch_related_object(mercedes_proxy,association_name,2) { alonzo }
78
+ end
79
+
80
+ it "returns the last driver" do
81
+ collection.last.should == alonzo
82
+ end
83
+ end
84
+
85
+ describe "#each" do
86
+ before do
87
+ stub(client).fetch_related_object(mercedes_proxy,association_name,0) { schumaher }
88
+ stub(client).fetch_related_object(mercedes_proxy,association_name,1) { kubica }
89
+ stub(client).fetch_related_object(mercedes_proxy,association_name,2) { alonzo }
90
+ end
91
+
92
+ it "iterates over the drivers" do
93
+ drivers = [schumaher,kubica,alonzo]
94
+ collection.each do |driver|
95
+ driver.should == drivers.shift
96
+ end
97
+ drivers.size.should == 0
98
+ end
99
+
100
+ it "allows to chain the calls" do
101
+ drivers = [schumaher,kubica,alonzo]
102
+ collection.each.map{|e| e }.should == drivers
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,108 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/json_serializer'
4
+
5
+ stub_class 'Rod::Model'
6
+
7
+ module Rod
8
+ module Rest
9
+ describe JsonSerializer do
10
+ let(:serializer) { JsonSerializer.new }
11
+ let(:object) { object = stub!.class { resource }.subject
12
+ stub(object).rod_id { rod_id }
13
+ stub(object).is_a?(Rod::Model) { true }
14
+ object
15
+ }
16
+ let(:rod_id) { 1 }
17
+ let(:type) { "Car" }
18
+ let(:resource) { resource = stub!.fields { fields }.subject
19
+ stub(resource).singular_associations { singular_associations }
20
+ stub(resource).plural_associations { plural_associations }
21
+ stub(resource).to_s { type }
22
+ resource
23
+ }
24
+ let(:fields) { [] }
25
+ let(:singular_associations) { [] }
26
+ let(:plural_associations) { [] }
27
+ let(:result) { JSON.parse(serializer.serialize(object),symbolize_names: true) }
28
+
29
+
30
+ describe "resource without properties" do
31
+ it "serializes its rod_id" do
32
+ result[:rod_id].should == rod_id
33
+ end
34
+
35
+ it "serializes its type" do
36
+ result[:type].should == type
37
+ end
38
+ end
39
+
40
+ describe "resource with name field" do
41
+ let(:fields) { [name_field] }
42
+ let(:name_field) { stub!.name { field_name }.subject }
43
+ let(:field_name) { "brand" }
44
+ let(:brand) { "Mercedes" }
45
+
46
+ before do
47
+ stub(object).brand { brand }
48
+ end
49
+
50
+ it "serializes its name field" do
51
+ result[:brand].should == brand
52
+ end
53
+ end
54
+
55
+ describe "resource with 'owner' singular association" do
56
+ let(:singular_associations) { [owner_association] }
57
+ let(:owner_association) { stub!.name { owner_association_name }.subject }
58
+ let(:owner_association_name){ "owner" }
59
+ let(:owner) { owner = stub!.rod_id { owner_rod_id }.subject
60
+ stub(owner).class { owner_type }.subject
61
+ owner
62
+ }
63
+ let(:owner_rod_id) { 10 }
64
+ let(:owner_type) { "Person" }
65
+
66
+ describe "with existing owner" do
67
+ before do
68
+ stub(object).owner { owner }
69
+ end
70
+
71
+ it "serializes rod_id of the owner" do
72
+ result[:owner][:rod_id] == owner_rod_id
73
+ end
74
+
75
+ it "serializes type of the owner" do
76
+ result[:owner][:type] == owner_type
77
+ end
78
+ end
79
+
80
+ describe "without owner" do
81
+ before do
82
+ stub(object).owner { nil }
83
+ end
84
+
85
+ it "serializes the owner as nil" do
86
+ result[:owner].should == nil
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "resource with 'drivers' plural association" do
92
+ let(:plural_associations) { [drivers_association] }
93
+ let(:drivers_association) { stub!.name { driver_association_name }.subject }
94
+ let(:driver_association_name) { "drivers" }
95
+ let(:drivers) { stub!.size { drivers_count }.subject }
96
+ let(:drivers_count) { 1 }
97
+
98
+ before do
99
+ stub(object).drivers { drivers }
100
+ end
101
+
102
+ it "serializes the number of associated objects" do
103
+ result[:drivers][:count].should == drivers_count
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,37 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/metadata'
4
+
5
+ module Rod
6
+ module Rest
7
+ describe Metadata do
8
+ let(:metadata) { Metadata.new(description: description, parser: parser, resource_metadata_factory: resource_metadata_factory) }
9
+ let(:parser) { stub!.parse(description,is_a(Hash)) { hash_description }.subject }
10
+ let(:description) { Object.new }
11
+ let(:hash_description) { { resource_name => resource_description, "Rod" => rod_description } }
12
+ let(:resource_description) { Object.new }
13
+ let(:rod_description) { Object.new }
14
+ let(:resource_metadata_factory) { stub!.new(resource_name,resource_description) { resource_metadata }.subject }
15
+ let(:resource_metadata) { Object.new }
16
+ let(:resource_name) { "Resource" }
17
+
18
+ it "creates the metadata from the description" do
19
+ metadata.resources
20
+ expect(parser).to have_received.parse(description,is_a(Hash))
21
+ end
22
+
23
+ it "returns collection of resource descriptions" do
24
+ metadata.resources.should respond_to(:each)
25
+ end
26
+
27
+ it "skips Rod pseudo-resource description" do
28
+ metadata.resources.size.should == hash_description.size - 1
29
+ end
30
+
31
+ it "creates the metadata description using the metadata factory" do
32
+ metadata.resources.first
33
+ expect(resource_metadata_factory).to have_received.new(resource_name,resource_description)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/property_metadata'
4
+
5
+ module Rod
6
+ module Rest
7
+ describe PropertyMetadata do
8
+ let(:property_metadata) { PropertyMetadata.new(name,options) }
9
+
10
+ describe "constructor" do
11
+ it "forbids to create property without name" do
12
+ lambda { PropertyMetadata.new(nil,{}) }.should raise_error(ArgumentError)
13
+ end
14
+ end
15
+
16
+ describe "#name" do
17
+ let(:options) { { type: :integer } }
18
+ let(:name) { :age }
19
+
20
+ it "converts its name to string" do
21
+ property_metadata.name.should be_a(String)
22
+ end
23
+
24
+ it "returns the name of the poperty" do
25
+ property_metadata.name.should == name.to_s
26
+ end
27
+ end
28
+
29
+ describe "#symbolic_name" do
30
+ let(:options) { { type: :string } }
31
+ let(:name) { :name }
32
+
33
+ it "converts its symbolic name to string" do
34
+ property_metadata.symbolic_name.should be_a(Symbol)
35
+ end
36
+
37
+ it "returns the symbolic name of the poperty" do
38
+ property_metadata.symbolic_name.should == name.to_sym
39
+ end
40
+ end
41
+
42
+ describe "#indexed?" do
43
+ let(:options) { { type: :string, index: index } }
44
+ let(:name) { :brand }
45
+
46
+ describe "with index" do
47
+ let(:index) { :hash }
48
+
49
+ it "returns true" do
50
+ property_metadata.should be_indexed
51
+ end
52
+ end
53
+
54
+ describe "without index" do
55
+ let(:index) { nil }
56
+ it "returns false" do
57
+ property_metadata.should_not be_indexed
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,87 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/proxy'
4
+
5
+ module Rod
6
+ module Rest
7
+ describe Proxy do
8
+ let(:proxy) { Proxy.new(metadata,client,collection_proxy_factory: collection_proxy_factory) }
9
+ let(:metadata) { metadata = stub!.fields { [id_field,name_field] }.subject
10
+ stub(metadata).singular_associations { [owner_association] }
11
+ stub(metadata).plural_associations { [drivers_association] }
12
+ stub(metadata).name { car_type }
13
+ metadata
14
+ }
15
+ let(:client) { client = stub!.fetch_object(schumaher_hash) { schumaher_object }.subject }
16
+ let(:collection_proxy_factory) { stub!.new(anything,drivers_association_name,drivers_count,client) { collection_proxy }.subject }
17
+ let(:collection_proxy) { Object.new }
18
+ let(:id_field) { property = stub!.symbolic_name { :rod_id }.subject
19
+ stub(property).name { "rod_id" }
20
+ property
21
+ }
22
+ let(:name_field) { property = stub!.symbolic_name { :name }.subject
23
+ stub(property).name { "name" }
24
+ property
25
+ }
26
+ let(:owner_association) { property = stub!.symbolic_name { :owner }.subject
27
+ stub(property).name { "owner" }
28
+ property
29
+ }
30
+ let(:drivers_association) { property = stub!.symbolic_name { drivers_association_name.to_sym }.subject
31
+ stub(property).name { drivers_association_name }
32
+ property
33
+ }
34
+ let(:drivers_association_name) { "drivers"}
35
+
36
+ let(:car_type) { "Test::Car" }
37
+ let(:mercedes_300_hash) { { rod_id: mercedes_300_id, name: mercedes_300_name, type: car_type,
38
+ owner: { rod_id: schumaher_id, type: person_type}, drivers: { count: drivers_count } } }
39
+ let(:mercedes_300_id) { 1 }
40
+ let(:mercedes_300_name) { "Mercedes 300" }
41
+
42
+ let(:person_type) { "Test::Person" }
43
+ let(:drivers_count) { 1 }
44
+ let(:schumaher_hash) { { rod_id: schumaher_id, type: person_type } }
45
+ let(:schumaher_id) { 2 }
46
+ let(:schumaher_object) { Object.new }
47
+ let(:owner_object) { schumaher_object }
48
+ let(:first_driver_object) { schumaher_object }
49
+
50
+ it "creates new instances" do
51
+ proxy.new(mercedes_300_hash).should_not == nil
52
+ end
53
+
54
+ it "refuses to create instances with missing rod_id" do
55
+ lambda { proxy.new({}) }.should raise_error(InvalidData)
56
+ end
57
+
58
+ it "refuses to create instances with missing type" do
59
+ lambda { proxy.new({rod_id: mercedes_300_id}) }.should raise_error(InvalidData)
60
+ end
61
+
62
+ describe "created instance" do
63
+ let(:mercedes_300) { proxy.new(mercedes_300_hash) }
64
+
65
+ it "has a type" do
66
+ mercedes_300.type.should == car_type
67
+ end
68
+
69
+ it "has an id" do
70
+ mercedes_300.rod_id.should == mercedes_300_id
71
+ end
72
+
73
+ it "has a valid 'name' field" do
74
+ mercedes_300.name.should == mercedes_300_name
75
+ end
76
+
77
+ it "has an valid 'owner' singular association" do
78
+ mercedes_300.owner.should == owner_object
79
+ end
80
+
81
+ it "has a valid 'drivers' plural association" do
82
+ mercedes_300.drivers.should == collection_proxy
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,44 @@
1
+ require 'bundler/setup'
2
+ require_relative 'test_helper'
3
+ require 'rod/rest/proxy_factory'
4
+
5
+ module Rod
6
+ module Rest
7
+ describe ProxyFactory do
8
+ let(:factory) { ProxyFactory.new(metadata,client,proxy_class: proxy_class) }
9
+ let(:metadata) { [car_metadata,person_metadata] }
10
+ let(:car_metadata) { stub!.name { car_type }.subject }
11
+ let(:person_metadata) { stub!.name { person_type }.subject }
12
+ let(:client) { Object.new }
13
+ let(:car_type) { "Car" }
14
+ let(:person_type) { "Person" }
15
+ let(:unknown_type) { "Unknown" }
16
+ let(:proxy_class) { klass = stub!.new(car_metadata,client) { car_proxy_factory }.subject
17
+ stub(klass).new(person_metadata,client) { person_proxy_factory }
18
+ klass
19
+ }
20
+ let(:car_proxy_factory) { stub!.new(mercedes_300_hash) { mercedes_300 }.subject }
21
+ let(:person_proxy_factory) { stub!.new(schumaher_hash) { schumaher }.subject }
22
+ let(:mercedes_300_hash) { { rod_id: mercedes_300_id, type: car_type } }
23
+ let(:schumaher_hash) { { rod_id: schumaher_id, type: person_type } }
24
+ let(:unknown_hash) { { rod_id: unknown_id, type: unknown_type } }
25
+ let(:mercedes_300_id) { 1 }
26
+ let(:schumaher_id) { 2 }
27
+ let(:unknown_id) { 3 }
28
+ let(:mercedes_300) { Object.new }
29
+ let(:schumaher) { Object.new }
30
+
31
+ it "builds new car from hash" do
32
+ factory.build(mercedes_300_hash).should == mercedes_300
33
+ end
34
+
35
+ it "builds new person proxy from hash" do
36
+ factory.build(schumaher_hash).should == schumaher
37
+ end
38
+
39
+ it "raises UnknownResource for unknown resource type" do
40
+ lambda { factory.build(unknown_hash) }.should raise_error(UnknownResource)
41
+ end
42
+ end
43
+ end
44
+ end