whisperer 0.0.1 → 0.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.
Files changed (40) hide show
  1. checksums.yaml +5 -13
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +2 -1
  4. data/README.md +80 -9
  5. data/TODO.md +30 -35
  6. data/lib/whisperer.rb +18 -48
  7. data/lib/whisperer/merger.rb +36 -0
  8. data/lib/whisperer/preprocessors/default_values.rb +22 -0
  9. data/lib/whisperer/preprocessors/response_body.rb +2 -2
  10. data/lib/whisperer/record.rb +2 -35
  11. data/lib/whisperer/record/body.rb +3 -3
  12. data/lib/whisperer/record/default_value.rb +13 -0
  13. data/lib/whisperer/record/headers.rb +6 -1
  14. data/lib/whisperer/record/request.rb +1 -1
  15. data/lib/whisperer/record/response.rb +1 -6
  16. data/lib/whisperer/record/response/status.rb +2 -2
  17. data/lib/whisperer/serializers.rb +21 -0
  18. data/lib/whisperer/serializers/json.rb +26 -1
  19. data/lib/whisperer/serializers/json_multiple.rb +1 -1
  20. data/lib/whisperer/storage.rb +41 -0
  21. data/lib/whisperer/tasks/whisperer.rake +3 -3
  22. data/lib/whisperer/version.rb +1 -1
  23. data/spec/cassettes/empty_robb_stark.yml +2 -2
  24. data/spec/cassettes/girls/arya_stark.yml +2 -2
  25. data/spec/cassettes/robb_stark.yml +2 -2
  26. data/spec/cassettes/robb_stark_without_content_length.yml +2 -2
  27. data/spec/cassettes/sansa_stark.yml +1 -1
  28. data/spec/cassettes/starks.yml +2 -2
  29. data/spec/cassettes/wolfs.yml +2 -2
  30. data/spec/unit/merger_spec.rb +98 -0
  31. data/spec/unit/preprocessors/content_length_spec.rb +9 -5
  32. data/spec/unit/preprocessors/default_values_spec.rb +26 -0
  33. data/spec/unit/preprocessors/response_body_spec.rb +4 -4
  34. data/spec/unit/record/headers_spec.rb +13 -1
  35. data/spec/unit/record_spec.rb +0 -73
  36. data/spec/unit/serializers/json_spec.rb +60 -12
  37. data/spec/unit/serializers_spec.rb +24 -0
  38. data/spec/unit/storage_spec.rb +82 -0
  39. data/spec/unit/whisperer_spec.rb +33 -103
  40. metadata +26 -12
@@ -6,15 +6,19 @@ describe Whisperer::Preprocessors::ContentLength do
6
6
 
7
7
  context 'when a content length for a response is defined' do
8
8
  let(:record) {
9
- r = Whisperer::Record.new
10
- r.response.headers.content_length = '10'
11
- r
9
+ Whisperer::Record.new(
10
+ response: {
11
+ headers: {
12
+ content_length: 10
13
+ }
14
+ }
15
+ )
12
16
  }
13
17
 
14
18
  it 'record has a unchanged content length' do
15
19
  subject.process
16
20
 
17
- expect(record.response.headers.content_length).to eq('10')
21
+ expect(record.response.headers.content_length).to eq(10)
18
22
  end
19
23
  end
20
24
 
@@ -32,7 +36,7 @@ describe Whisperer::Preprocessors::ContentLength do
32
36
  it 'measures size of body and writes it to the content length header of the response' do
33
37
  subject.process
34
38
 
35
- expect(record.response.headers.content_length).to eq('4')
39
+ expect(record.response.headers.content_length).to eq(4)
36
40
  end
37
41
  end
38
42
  end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Preprocessors::DefaultValues do
4
+ describe '#process' do
5
+ let(:record) {
6
+ r = Whisperer::Record.new
7
+ r.request.method = Whisperer::DefaultValue.new(:get)
8
+ r.response.status.code = Whisperer::DefaultValue.new(200)
9
+ r
10
+ }
11
+
12
+ subject { described_class.new(record) }
13
+
14
+ before do
15
+ subject.process
16
+ end
17
+
18
+ it 'has correct value for the request method' do
19
+ expect(record.request.method).to eq(:get)
20
+ end
21
+
22
+ it 'has correct value for the response status' do
23
+ expect(record.response.status.code).to eq(200)
24
+ end
25
+ end
26
+ end
@@ -8,7 +8,7 @@ describe Whisperer::Preprocessors::ResponseBody do
8
8
  let(:record) { Whisperer::Record.new }
9
9
 
10
10
  it 'does not serialize anything' do
11
- expect(Whisperer).to_not receive(:serializer)
11
+ expect(Whisperer::Serializers).to_not receive(:fetch)
12
12
 
13
13
  subject.process
14
14
  end
@@ -29,17 +29,17 @@ describe Whisperer::Preprocessors::ResponseBody do
29
29
  }
30
30
 
31
31
  before do
32
- allow(Whisperer).to receive(:serializer).and_return(serializer)
32
+ allow(Whisperer::Serializers).to receive(:fetch).and_return(serializer)
33
33
  allow(serializer).to receive(:serialize).and_return(serialized_data)
34
34
  end
35
35
 
36
36
  it 'gets the serializer' do
37
- expect(Whisperer).to receive(:serializer).with(:json)
37
+ expect(Whisperer::Serializers).to receive(:fetch).with(:json)
38
38
 
39
39
  subject.process
40
40
  end
41
41
 
42
- it 'serializes the respose body' do
42
+ it 'serializes the response body' do
43
43
  expect(serializer).to receive(:serialize).with(data_obj, {some: 'options'})
44
44
 
45
45
  subject.process
@@ -1,7 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Whisperer::Headers do
4
- describe '.to_hash' do
4
+ describe '.new' do
5
+ context 'when there is not such attribute' do
6
+ subject {
7
+ described_class.new(connection: 'keep-alive')
8
+ }
9
+
10
+ it 'adds them dynamically' do
11
+ expect(subject.connection).to eq('keep-alive')
12
+ end
13
+ end
14
+ end
15
+
16
+ describe '#to_hash' do
5
17
  subject {
6
18
  obj = described_class.new()
7
19
 
@@ -1,77 +1,4 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Whisperer::Record do
4
- describe '#merge!' do
5
- let(:record) {
6
- r = Whisperer::Record.new(
7
- request: {
8
- uri: 'http://google.com',
9
- },
10
- response: {
11
- body: {
12
- encoding: 'UTF-8',
13
- string: 'test'
14
- }
15
- },
16
- recorded_at: 'test data'
17
- )
18
-
19
- r.request.headers.attribute(:content_length, Integer)
20
- r.request.headers.attribute(:accept, String)
21
-
22
- r.request.headers.content_length = 100
23
- r.request.headers.accept = 'javascript'
24
- r
25
- }
26
-
27
- let(:another_record) {
28
- r = Whisperer::Record.new(
29
- request: {
30
- headers: {
31
- content_length: 50
32
- }
33
- },
34
- response: {
35
- body: {
36
- encoding: 'UTF-16'
37
- }
38
- }
39
- )
40
-
41
- r.request.headers.attribute(:content_length, Integer)
42
-
43
- r.request.headers.content_length = 50
44
- r
45
- }
46
-
47
- subject { another_record }
48
-
49
- before do
50
- subject.merge!(record)
51
- end
52
-
53
- it 'has a correct content length header for the request' do
54
- expect(subject.request.headers.content_length).to eq(50)
55
- end
56
-
57
- it 'has an accept header for the request' do
58
- expect(subject.request.headers.accept).to eq('javascript')
59
- end
60
-
61
- it 'has an url' do
62
- expect(subject.request.uri).to eq('http://google.com')
63
- end
64
-
65
- it 'has a correct encoding for the body of the response' do
66
- expect(subject.response.body.encoding).to eq('UTF-16')
67
- end
68
-
69
- it 'has a string for the body of the response' do
70
- expect(subject.response.body.string).to eq('test')
71
- end
72
-
73
- it 'has a correct recorded_at value' do
74
- expect(subject.recorded_at).to eq('test data')
75
- end
76
- end
77
4
  end
@@ -7,8 +7,48 @@ class TestChildJson < Whisperer::Serializers::Json
7
7
  end
8
8
  end
9
9
 
10
+ class TestObj
11
+ def initialize(attrs)
12
+ @first_name = attrs[:first_name]
13
+ @last_name = nil
14
+ end
15
+
16
+ # we need to make sure that our serializer uses accessors methods
17
+ # when it exists.
18
+ def last_name
19
+ 'Snow'
20
+ end
21
+ end
22
+
23
+ class TestObjWithAttrs
24
+ def attributes
25
+ {
26
+ first_name: 'John',
27
+ last_name: 'Snow'
28
+ }
29
+ end
30
+ end
31
+
10
32
  describe Whisperer::Serializers::Json do
11
33
  describe '#serialize' do
34
+ shared_examples 'serializing an object' do
35
+ it 'returns json string with serialized attributes' do
36
+ expect(subject.serialize).to eq('{"first_name":"John","last_name":"Snow"}')
37
+ end
38
+
39
+ context 'when the class is inherited' do
40
+ subject { TestChildJson.new(given_obj) }
41
+
42
+ context 'when the child class alters the data structure' do
43
+ it 'returns the altered structure' do
44
+ expect(subject.serialize).to eq(
45
+ '{"test":{"first_name":"John","last_name":"Snow"}}'
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
51
+
12
52
  let(:attrs) {
13
53
  {
14
54
  first_name: 'John',
@@ -16,22 +56,30 @@ describe Whisperer::Serializers::Json do
16
56
  }
17
57
  }
18
58
 
19
- subject { described_class.new(OpenStruct.new(attrs)) }
59
+ subject { described_class.new(given_obj) }
60
+
61
+ context 'when an open struct object is given' do
62
+ let(:given_obj) {
63
+ OpenStruct.new(attrs)
64
+ }
65
+
66
+ it_behaves_like 'serializing an object'
67
+ end
68
+
69
+ context 'When a pure ruby object is given' do
70
+ let(:given_obj) {
71
+ TestObj.new(attrs)
72
+ }
20
73
 
21
- it 'returns json string with serialized attributes' do
22
- expect(subject.serialize).to eq('{"first_name":"John","last_name":"Snow"}')
74
+ it_behaves_like 'serializing an object'
23
75
  end
24
76
 
25
- context 'when the class is inherited' do
26
- subject { TestChildJson.new(OpenStruct.new(attrs)) }
77
+ context 'when an object has the attributes method' do
78
+ let(:given_obj) {
79
+ TestObjWithAttrs.new
80
+ }
27
81
 
28
- context 'when the child class alters the data structure' do
29
- it 'returns the altered structure' do
30
- expect(subject.serialize).to eq(
31
- '{"test":{"first_name":"John","last_name":"Snow"}}'
32
- )
33
- end
34
- end
82
+ it_behaves_like 'serializing an object'
35
83
  end
36
84
  end
37
85
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Serializers do
4
+ describe '.fetch' do
5
+ before do
6
+ described_class.register(:test_json, 'My test class')
7
+ end
8
+
9
+ context 'when there is not such serializer' do
10
+ it 'raises an error' do
11
+ expect { described_class.fetch(:mytest) }.to raise_error(
12
+ ArgumentError,
13
+ 'There is not serializer registered with "mytest" name'
14
+ )
15
+ end
16
+ end
17
+
18
+ context 'when there is such serializer' do
19
+ it 'returns the registered class' do
20
+ expect(described_class.fetch(:test_json)).to eq('My test class')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Storage do
4
+ describe '.define' do
5
+ let(:cassette_record) { instance_double('Whisperer::Record') }
6
+ let(:dsl) { instance_double('Whisperer::Dsl', container: cassette_record) }
7
+
8
+ before do
9
+ allow(Whisperer::Dsl).to receive(:build).and_return(dsl)
10
+ end
11
+
12
+ after do
13
+ described_class.reset_storage
14
+ end
15
+
16
+ it 'builds the dsl object' do
17
+ expect(Whisperer::Dsl).to receive(:build)
18
+
19
+ described_class.define(:test) {}
20
+ end
21
+
22
+ it 'executes a given block over the dsl object' do
23
+ expect(dsl).to receive(:request)
24
+
25
+ described_class.define(:test) {
26
+ request
27
+ }
28
+ end
29
+
30
+ it 'stores the generated cassette record' do
31
+ described_class.define(:test) {}
32
+
33
+ expect(described_class.cassette_record(:test)).to eq(cassette_record)
34
+ expect(described_class.defined_any?).to be_truthy
35
+ end
36
+
37
+ context 'when a string as a name of the cassette record is given' do
38
+ it 'stores a cassette record with a symbol key' do
39
+ described_class.define('test') {}
40
+
41
+ expect(described_class.cassette_record(:test)).to eq(cassette_record)
42
+ end
43
+ end
44
+
45
+ context 'when a parent is defined for a cassette record' do
46
+ context 'when such parent exists' do
47
+ let(:orig_cassette_record) { double('original cassette record') }
48
+
49
+ before do
50
+ expect(described_class).to receive(:cassette_record).with(:some_parent).and_return(
51
+ orig_cassette_record
52
+ )
53
+ end
54
+
55
+ it 'merges the original record with the newly built' do
56
+ expect(Whisperer::Merger).to receive(:merge).with(
57
+ cassette_record,
58
+ orig_cassette_record
59
+ )
60
+
61
+ described_class.define('test', parent: :some_parent) {}
62
+ end
63
+ end
64
+
65
+ context 'when such parent does not exist' do
66
+ it 'raises an error' do
67
+ expect {
68
+ described_class.define('test', parent: :some_parent) {}
69
+ }.to raise_error(ArgumentError, 'Parent record "some_parent" is not declared.')
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '.defined_any?' do
76
+ context 'when there are not defined cassette_records' do
77
+ it 'returns false' do
78
+ expect(described_class.defined_any?).to be_falsey
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,94 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Whisperer do
4
- after do
5
- described_class.cassette_records.clear
6
- end
7
-
8
4
  describe '.define' do
9
- let(:cassette_record) { instance_double('Whisperer::Record', merge!: true) }
10
- let(:dsl) { instance_double('Whisperer::Dsl', container: cassette_record) }
11
-
12
- before do
13
- allow(Whisperer::Dsl).to receive(:build).and_return(dsl)
14
- end
15
-
16
- it 'builds the dsl object' do
17
- expect(Whisperer::Dsl).to receive(:build)
18
-
19
- described_class.define(:test) {}
20
- end
21
-
22
- it 'executes a given block over the dsl object' do
23
- expect(dsl).to receive(:request)
24
-
25
- described_class.define(:test) {
26
- request
27
- }
28
- end
29
-
30
- it 'stores the generated cassette record' do
31
- described_class.define(:test) {}
5
+ it 'proxies to the storage class' do
6
+ expect(Whisperer::Storage).to receive(:define).with(
7
+ 'test arg'
8
+ )
32
9
 
33
- expect(Whisperer.cassette_records[:test]).to eq(cassette_record)
34
- end
35
-
36
- context 'when a string as a name of the cassette record is given' do
37
- it 'stores a cassette record with a symbol key' do
38
- described_class.define('test') {}
39
-
40
- expect(Whisperer.cassette_records[:test]).to eq(cassette_record)
41
- end
42
- end
43
-
44
- context 'when a parent is defined for a cassette record' do
45
- context 'when such parent exists' do
46
- let(:orig_cassette_record) { double('original cassette record') }
47
-
48
- before do
49
- Whisperer.cassette_records[:some_parent] = orig_cassette_record
50
- end
51
-
52
- it 'merges the original record with the newly built' do
53
- expect(cassette_record).to receive(:merge!).with(orig_cassette_record)
54
-
55
- described_class.define('test', parent: :some_parent) {}
56
- end
57
- end
58
-
59
- context 'when such parent does not exist' do
60
- it 'raises an error' do
61
- expect {
62
- described_class.define('test', parent: :some_parent) {}
63
- }.to raise_error(ArgumentError, 'Parent record "some_parent" is not declared.')
64
- end
65
- end
10
+ described_class.define('test arg')
66
11
  end
67
12
  end
68
13
 
69
- describe '.defined_any?' do
70
- context 'when there are defined cassette records' do
14
+ describe '.generate' do
15
+ context 'when the cassette record with the given name does not exist' do
71
16
  before do
72
- described_class.cassette_records[:test] = true
17
+ expect(Whisperer::Storage).to receive(:cassette_record).and_return(nil)
73
18
  end
74
19
 
75
- it 'returns true' do
76
- expect(Whisperer.defined_any?).to be_truthy
77
- end
78
- end
79
-
80
- context 'when there are not defined cassette_records' do
81
- it 'returns false' do
82
- expect(Whisperer.defined_any?).to be_falsey
83
- end
84
- end
85
- end
86
-
87
- describe '.generate' do
88
- context 'when the cassette record with the given name does not exist' do
89
20
  it 'raises an error' do
90
21
  expect { described_class.generate(:mytest) }.to raise_error(
91
- Whisperer::NocassetteRecordError,
22
+ Whisperer::NoCassetteRecordError,
92
23
  'There is not cassette builder with "mytest" name.'
93
24
  )
94
25
  end
@@ -109,7 +40,7 @@ describe Whisperer do
109
40
  let(:cassette_record) { double }
110
41
 
111
42
  before do
112
- described_class.cassette_records[:test] = cassette_record
43
+ expect(Whisperer::Storage).to receive(:cassette_record).with(:test).and_return(cassette_record)
113
44
  end
114
45
 
115
46
  context 'when the given name is a symbol' do
@@ -124,25 +55,33 @@ describe Whisperer do
124
55
 
125
56
  describe '.generate_all' do
126
57
  context 'when there are defined cassettes' do
127
- let(:record1) { double('cassette record 1') }
128
- let(:record2) { double('cassette record 2') }
58
+ let(:record1) { double('Cassette record 1') }
59
+ let(:record2) { double('Cassette record 2') }
129
60
 
130
61
  before do
131
- Whisperer::cassette_records[:record1] = record1
132
- Whisperer::cassette_records[:record2] = record2
62
+ expect(Whisperer::Storage).to receive(:cassette_records).and_return(
63
+ record1: record1,
64
+ record2: record2
65
+ )
133
66
 
134
- allow(Whisperer).to receive(:defined_any?).and_return(true)
135
- allow(Whisperer).to receive(:generate)
67
+ allow(Whisperer::Storage).to receive(:defined_any?).and_return(true)
68
+ allow(Whisperer::Generator).to receive(:generate)
136
69
  end
137
70
 
138
71
  it 'generates the VCR cassette based on record1' do
139
- expect(Whisperer).to receive(:generate).with(:record1)
72
+ expect(Whisperer::Generator).to receive(:generate).with(
73
+ record1,
74
+ :record1
75
+ )
140
76
 
141
77
  described_class.generate_all
142
78
  end
143
79
 
144
80
  it 'generates the VCR cassette based on record2' do
145
- expect(Whisperer).to receive(:generate).with(:record2)
81
+ expect(Whisperer::Generator).to receive(:generate).with(
82
+ record2,
83
+ :record2
84
+ )
146
85
 
147
86
  described_class.generate_all
148
87
  end
@@ -155,32 +94,23 @@ describe Whisperer do
155
94
 
156
95
  it 'raises and error' do
157
96
  expect { described_class.generate_all }.to raise_error(
158
- Whisperer::NocassetteRecordError,
159
- 'cassette builders are not found.'
97
+ Whisperer::NoCassetteRecordError,
98
+ 'Cassette builders are not found.'
160
99
  )
161
100
  end
162
101
  end
163
102
  end
164
103
 
165
- describe '.serializer' do
166
- context 'when there is not such serializer' do
167
- it 'raises an error' do
168
- expect { described_class.serializer(:mytest) }.to raise_error(
169
- ArgumentError,
170
- 'There is not serializer registered with "mytest" name'
171
- )
172
- end
173
- end
104
+ describe '.register_serializer' do
105
+ it 'registers a serializer' do
106
+ expect(Whisperer::Serializers).to receive(:register).with('some name', 'some class')
174
107
 
175
- context 'when there is such serializer' do
176
- it 'returns the registered class' do
177
- expect(described_class.serializer(:json)).to eq(Whisperer::Serializers::Json)
178
- end
108
+ Whisperer.register_serializer('some name', 'some class')
179
109
  end
180
110
  end
181
111
 
182
112
  describe '.register_preprocessor' do
183
- it 'registers preprocessor' do
113
+ it 'registers a preprocessor' do
184
114
  expect(Whisperer::Preprocessors).to receive(:register).with('some name', 'some class')
185
115
 
186
116
  Whisperer.register_preprocessor('some name', 'some class')