odeon_uk 4.0.1 → 5.0.0
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 +5 -5
- data/.github/workflows/test.yml +43 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +28 -0
- data/README.md +90 -21
- data/Rakefile +14 -15
- data/lib/odeon_uk/cinema.rb +40 -22
- data/lib/odeon_uk/internal/api_response.rb +19 -39
- data/lib/odeon_uk/internal/guest_token.rb +23 -0
- data/lib/odeon_uk/internal/parser/api/showtime.rb +80 -0
- data/lib/odeon_uk/internal/title_sanitizer.rb +3 -8
- data/lib/odeon_uk/performance.rb +34 -41
- data/lib/odeon_uk/version.rb +3 -3
- data/lib/odeon_uk.rb +16 -2
- data/odeon_uk.gemspec +10 -6
- data/test/fixtures/api/showtimes-824.json +66 -0
- data/test/fixtures/api/sites.json +32 -0
- data/test/lib/odeon_uk/cinema_test.rb +66 -215
- data/test/lib/odeon_uk/internal/api_response_test.rb +48 -29
- data/test/lib/odeon_uk/internal/fixture_shape_test.rb +14 -0
- data/test/lib/odeon_uk/internal/guest_token_test.rb +84 -0
- data/test/lib/odeon_uk/internal/parser/api/showtime_test.rb +68 -0
- data/test/lib/odeon_uk/internal/title_sanitizer_test.rb +109 -89
- data/test/lib/odeon_uk/performance_test.rb +124 -146
- data/test/lib/odeon_uk/version_test.rb +3 -3
- data/test/live/api_shape_test.rb +19 -0
- data/test/live/integration_test.rb +21 -0
- data/test/live/live_helper.rb +11 -0
- data/test/package_test.rb +56 -0
- data/test/support/api_fixtures_helper.rb +5 -30
- data/test/support/api_shapes.rb +46 -0
- data/test/support/fake_api_response.rb +9 -6
- data/test/test_helper.rb +6 -3
- metadata +66 -89
- data/.travis.yml +0 -7
- data/lib/odeon_uk/internal/parser/api/film_lookup.rb +0 -34
- data/lib/odeon_uk/internal/parser/api/performance_day.rb +0 -92
- data/rake/fixture_creator.rb +0 -46
- data/test/fixtures/api/all_cinemas.plist +0 -0
- data/test/fixtures/api/app_init.plist +0 -0
- data/test/fixtures/api/film_times/71-14876.plist +0 -0
- data/test/fixtures/api/film_times/71-15408.plist +0 -0
- data/test/fixtures/api/film_times/71-15684.plist +0 -0
- data/test/fixtures/api/film_times/71-15866.plist +0 -0
- data/test/fixtures/api/film_times/71-15868.plist +0 -0
- data/test/fixtures/api/film_times/71-15961.plist +0 -0
- data/test/fixtures/api/film_times/71-15963.plist +0 -0
- data/test/fixtures/api/film_times/71-15965.plist +0 -0
- data/test/fixtures/api/film_times/71-15967.plist +0 -0
- data/test/fixtures/api/film_times/71-15969.plist +0 -0
- data/test/fixtures/api/film_times/71-15977.plist +0 -0
- data/test/fixtures/api/film_times/71-15980.plist +0 -0
- data/test/fixtures/api/film_times/71-16037.plist +0 -0
- data/test/fixtures/api/film_times/71-16136.plist +0 -0
- data/test/fixtures/api/film_times/71-16142.plist +0 -0
- data/test/fixtures/api/film_times/71-16143.plist +0 -0
- data/test/fixtures/api/film_times/71-16187.plist +0 -0
- data/test/fixtures/api/film_times/71-16369.plist +0 -0
- data/test/fixtures/api/film_times/71-16370.plist +0 -0
- data/test/fixtures/api/film_times/71-16374.plist +0 -0
- data/test/fixtures/api/film_times/71-16386.plist +0 -0
- data/test/fixtures/api/film_times/71-16387.plist +0 -0
- data/test/fixtures/api/film_times/71-16388.plist +0 -0
- data/test/fixtures/api/film_times/71-16438.plist +0 -0
- data/test/fixtures/api/film_times/71-16454.plist +0 -0
- data/test/fixtures/api/film_times/71-16457.plist +0 -0
- data/test/fixtures/api/film_times/71-16477.plist +0 -0
- data/test/fixtures/api/film_times/71-16478.plist +0 -0
- data/test/fixtures/api/film_times/71-16480.plist +0 -0
- data/test/fixtures/api/film_times/71-16482.plist +0 -0
- data/test/fixtures/api/film_times/71-16489.plist +0 -0
|
@@ -1,172 +1,150 @@
|
|
|
1
1
|
require_relative '../../test_helper'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
let(:api_response) { FakeApiResponse.new }
|
|
6
|
-
|
|
7
|
-
before { WebMock.disable_net_connect! }
|
|
8
|
-
after { WebMock.allow_net_connect! }
|
|
9
|
-
|
|
10
|
-
describe '.at(cinema_id)' do
|
|
11
|
-
subject { described_class.at(cinema_id) }
|
|
12
|
-
|
|
13
|
-
describe 'passed Fixnum' do
|
|
14
|
-
let(:cinema_id) { 71 }
|
|
15
|
-
|
|
16
|
-
it 'returns an array of performances' do
|
|
17
|
-
OdeonUk::Internal::ApiResponse.stub :new, api_response do
|
|
18
|
-
subject.must_be_instance_of(Array)
|
|
19
|
-
subject.each do |element|
|
|
20
|
-
element.must_be_instance_of(described_class)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'returns at least a sensible number' do
|
|
26
|
-
OdeonUk::Internal::ApiResponse.stub :new, api_response do
|
|
27
|
-
subject.count.must_be :>, 110
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
3
|
+
class OdeonUk::PerformanceTest < Minitest::Test
|
|
4
|
+
DATE = Date.new(2026, 10, 24)
|
|
31
5
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
it 'returns an array of performances' do
|
|
36
|
-
OdeonUk::Internal::ApiResponse.stub :new, api_response do
|
|
37
|
-
subject.must_be_instance_of(Array)
|
|
38
|
-
subject.each do |element|
|
|
39
|
-
element.must_be_instance_of(described_class)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it 'returns at least a sensible number' do
|
|
45
|
-
OdeonUk::Internal::ApiResponse.stub :new, api_response do
|
|
46
|
-
subject.count.must_be :>, 110
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
6
|
+
def setup
|
|
7
|
+
@api_response = FakeApiResponse.new
|
|
50
8
|
end
|
|
51
9
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
film_name: 'The Big Short',
|
|
59
|
-
cinema_id: 71,
|
|
60
|
-
cinema_name: 'Brighton',
|
|
61
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
62
|
-
}
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it 'sets cinema name and film name' do
|
|
66
|
-
subject.film_name.must_equal 'The Big Short'
|
|
67
|
-
subject.cinema_name.must_equal 'Brighton'
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'booking url, dimension & varient are set to defaults' do
|
|
71
|
-
subject.booking_url.must_equal nil
|
|
72
|
-
subject.dimension.must_equal '2d'
|
|
73
|
-
subject.variant.must_equal []
|
|
74
|
-
end
|
|
75
|
-
end
|
|
10
|
+
def test_at_returns_performances
|
|
11
|
+
performances = performances_at(824)
|
|
12
|
+
|
|
13
|
+
assert(performances.all? { |p| p.instance_of?(OdeonUk::Performance) })
|
|
14
|
+
assert_equal 6, performances.count
|
|
76
15
|
end
|
|
77
16
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
film_name: 'Ant Man',
|
|
82
|
-
dimension: '3d',
|
|
83
|
-
cinema_id: 71,
|
|
84
|
-
cinema_name: 'Brighton',
|
|
85
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
86
|
-
}
|
|
87
|
-
end
|
|
17
|
+
def test_at_accepts_string_id
|
|
18
|
+
assert_equal 6, performances_at('824').count
|
|
19
|
+
end
|
|
88
20
|
|
|
89
|
-
|
|
21
|
+
def test_at_sets_cinema_details
|
|
22
|
+
performances = performances_at(824)
|
|
90
23
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
subject.must_equal '3d'
|
|
94
|
-
end
|
|
24
|
+
assert_equal ['824'], performances.map(&:cinema_id).uniq
|
|
25
|
+
assert_equal ['Brighton'], performances.map(&:cinema_name).uniq
|
|
95
26
|
end
|
|
96
27
|
|
|
97
|
-
|
|
98
|
-
|
|
28
|
+
def test_at_parses_first_performance
|
|
29
|
+
performance = performances_at(824).first
|
|
99
30
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
end
|
|
31
|
+
assert_equal 'The Example Film', performance.film_name
|
|
32
|
+
assert_equal Time.utc(2026, 10, 24, 8, 0), performance.starting_at
|
|
33
|
+
assert_equal '2d', performance.dimension
|
|
34
|
+
assert_equal %w(audio_described), performance.variant
|
|
35
|
+
assert_equal 'https://www.odeon.co.uk/ticketing/seat-picker/?showtimeId=824-1001',
|
|
36
|
+
performance.booking_url
|
|
37
|
+
end
|
|
109
38
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
subject.must_equal Time.utc(2013, 9, 12, 11, 0)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
39
|
+
def test_at_parses_3d_imax
|
|
40
|
+
performance = performances_at(824)[1]
|
|
115
41
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
film_name: 'Steve Jobs',
|
|
120
|
-
cinema_id: 71,
|
|
121
|
-
cinema_name: 'Brighton',
|
|
122
|
-
starting_at: Time.new(2013, 9, 12, 11, 0)
|
|
123
|
-
}
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'returns UTC time' do
|
|
127
|
-
subject.must_be_instance_of Time
|
|
128
|
-
subject.must_equal Time.utc(2013, 9, 12, 10, 0)
|
|
129
|
-
subject.utc?.must_equal(true)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
42
|
+
assert_equal '3d', performance.dimension
|
|
43
|
+
assert_equal %w(imax), performance.variant
|
|
132
44
|
end
|
|
133
45
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
cinema_id: 71,
|
|
139
|
-
cinema_name: 'Brighton',
|
|
140
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
141
|
-
}
|
|
142
|
-
end
|
|
46
|
+
def test_at_returns_language_and_subtitles
|
|
47
|
+
performances = performances_at(824)
|
|
48
|
+
tamil = performances[3]
|
|
49
|
+
korean = performances[2]
|
|
143
50
|
|
|
144
|
-
|
|
51
|
+
assert_equal 'Imaginary Picture', tamil.film_name
|
|
52
|
+
assert_equal 'Tamil', tamil.language
|
|
53
|
+
assert tamil.subtitled?
|
|
54
|
+
assert_equal 'Korean', korean.language
|
|
55
|
+
assert_equal %w(arts subtitled), korean.variant
|
|
56
|
+
end
|
|
145
57
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
58
|
+
def test_at_treats_open_captions_as_subtitled
|
|
59
|
+
kids = performances_at(824)[4]
|
|
60
|
+
|
|
61
|
+
assert_nil kids.language
|
|
62
|
+
assert_equal %w(kids subtitled), kids.variant
|
|
63
|
+
assert kids.subtitled?
|
|
150
64
|
end
|
|
151
65
|
|
|
152
|
-
|
|
153
|
-
|
|
66
|
+
def test_at_keeps_after_midnight_on_next_utc_day
|
|
67
|
+
assert_equal Time.utc(2026, 10, 24, 23, 15), performances_at(824).last.starting_at
|
|
68
|
+
end
|
|
154
69
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
cinema_name: 'Brighton',
|
|
160
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0),
|
|
161
|
-
variant: %w(Subtitles Senior)
|
|
162
|
-
}
|
|
163
|
-
end
|
|
70
|
+
def test_at_requests_each_date_in_range
|
|
71
|
+
to = DATE + 2
|
|
72
|
+
|
|
73
|
+
with_fake_api { OdeonUk::Performance.at(824, from: DATE, to: to) }
|
|
164
74
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
75
|
+
assert_equal (DATE..to).to_a, @api_response.requested_dates
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_at_rejects_range_ending_before_start
|
|
79
|
+
assert_raises(ArgumentError) do
|
|
80
|
+
OdeonUk::Performance.at(824, from: DATE, to: DATE - 1)
|
|
169
81
|
end
|
|
170
82
|
end
|
|
171
83
|
|
|
84
|
+
def test_new_sets_names
|
|
85
|
+
performance = OdeonUk::Performance.new(options)
|
|
86
|
+
|
|
87
|
+
assert_equal 'The Big Short', performance.film_name
|
|
88
|
+
assert_equal 'Brighton', performance.cinema_name
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def test_new_sets_defaults
|
|
92
|
+
performance = OdeonUk::Performance.new(options)
|
|
93
|
+
|
|
94
|
+
assert_nil performance.booking_url
|
|
95
|
+
assert_nil performance.festival
|
|
96
|
+
assert_equal '2d', performance.dimension
|
|
97
|
+
assert_nil performance.language
|
|
98
|
+
refute performance.subtitled?
|
|
99
|
+
assert_equal [], performance.variant
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_language
|
|
103
|
+
assert_equal 'Tamil', OdeonUk::Performance.new(options(language: 'Tamil')).language
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_festival
|
|
107
|
+
festival = Cinebase::Festival.new(name: 'Cine-Excess', year: 2026)
|
|
108
|
+
performance = OdeonUk::Performance.new(options(festival: festival))
|
|
109
|
+
|
|
110
|
+
assert_equal festival, performance.festival
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def test_subtitled
|
|
114
|
+
assert OdeonUk::Performance.new(options(variant: %w(subtitled))).subtitled?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_starting_at_converts_local_time_to_utc
|
|
118
|
+
starting_at = OdeonUk::Performance.new(
|
|
119
|
+
options(starting_at: Time.new(2013, 9, 12, 11, 0))
|
|
120
|
+
).starting_at
|
|
121
|
+
|
|
122
|
+
assert_equal Time.utc(2013, 9, 12, 10, 0), starting_at
|
|
123
|
+
assert starting_at.utc?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_variant_is_sorted_and_lower_case
|
|
127
|
+
performance = OdeonUk::Performance.new(options(variant: %w(Subtitled Senior)))
|
|
128
|
+
|
|
129
|
+
assert_equal %w(senior subtitled), performance.variant
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
def options(overrides = {})
|
|
135
|
+
{
|
|
136
|
+
film_name: 'The Big Short',
|
|
137
|
+
cinema_id: '824',
|
|
138
|
+
cinema_name: 'Brighton',
|
|
139
|
+
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
140
|
+
}.merge(overrides)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def performances_at(cinema_id)
|
|
144
|
+
with_fake_api { OdeonUk::Performance.at(cinema_id, from: DATE, to: DATE) }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def with_fake_api(&block)
|
|
148
|
+
OdeonUk::Internal::ApiResponse.stub(:new, @api_response, &block)
|
|
149
|
+
end
|
|
172
150
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative 'live_helper'
|
|
2
|
+
|
|
3
|
+
class LiveApiShapeTest < Minitest::Test
|
|
4
|
+
include ApiShapes
|
|
5
|
+
|
|
6
|
+
def test_sites_are_readable
|
|
7
|
+
assert_sites_shape('sites' => api.sites)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_showtimes_are_readable
|
|
11
|
+
assert_showtimes_shape(api.showtimes('824', Date.today + 1))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def api
|
|
17
|
+
OdeonUk::Internal::ApiResponse.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative 'live_helper'
|
|
2
|
+
|
|
3
|
+
class LiveCinemaTest < Minitest::Test
|
|
4
|
+
def test_all_returns_cinemas
|
|
5
|
+
cinemas = OdeonUk::Cinema.all
|
|
6
|
+
|
|
7
|
+
assert(cinemas.all? { |cinema| cinema.instance_of?(OdeonUk::Cinema) })
|
|
8
|
+
assert_operator cinemas.size, :>, 90
|
|
9
|
+
assert_equal 'Brighton', cinemas.detect { |cinema| cinema.id == '824' }.name
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class LivePerformanceTest < Minitest::Test
|
|
14
|
+
def test_at_returns_performances
|
|
15
|
+
tomorrow = Date.today + 1
|
|
16
|
+
performances = OdeonUk::Performance.at(824, from: tomorrow, to: tomorrow)
|
|
17
|
+
|
|
18
|
+
assert(performances.all? { |p| p.instance_of?(OdeonUk::Performance) })
|
|
19
|
+
assert_operator performances.count, :>, 10
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
require 'minitest/reporters'
|
|
3
|
+
|
|
4
|
+
Minitest::Reporters.use! [
|
|
5
|
+
Minitest::Reporters::DefaultReporter.new(color: true)
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
require File.expand_path('../../../lib/odeon_uk.rb', __FILE__)
|
|
9
|
+
require_relative '../support/api_shapes'
|
|
10
|
+
|
|
11
|
+
OdeonUk.token = ENV.fetch('ODEON_TOKEN') { OdeonUk.acquire_token! }
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Run separately after building: ODEON_PACKAGE=pkg/...gem bundle exec ruby test/package_test.rb
|
|
2
|
+
require "minitest/autorun"
|
|
3
|
+
require "rubygems/installer"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
require "open3"
|
|
7
|
+
require "base64"
|
|
8
|
+
require "json"
|
|
9
|
+
|
|
10
|
+
class PlatformPackageTest < Minitest::Test
|
|
11
|
+
def setup
|
|
12
|
+
@directory = Dir.mktmpdir("odeon-package-test")
|
|
13
|
+
@spec = Gem::Installer.at(
|
|
14
|
+
ENV.fetch("ODEON_PACKAGE"), install_dir: @directory, ignore_dependencies: true
|
|
15
|
+
).install
|
|
16
|
+
@vendor = File.join(@spec.full_gem_path, "vendor", "curl-impersonate")
|
|
17
|
+
@binary = File.join(@vendor, "bin", "curl-impersonate")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def teardown
|
|
21
|
+
FileUtils.remove_entry(@directory)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_installs_runnable_executable_with_notices_and_provenance
|
|
25
|
+
assert File.executable?(@binary)
|
|
26
|
+
output, status = Open3.capture2(@binary, "--version")
|
|
27
|
+
assert status.success?
|
|
28
|
+
assert_includes output, "curl"
|
|
29
|
+
assert File.file?(File.join(@vendor, "licenses", "LICENSE_CURL"))
|
|
30
|
+
assert_includes File.read(File.join(@vendor, "SOURCE")), "2.2.3"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_acquires_token_with_gem_local_executable_and_no_curl_on_path
|
|
34
|
+
payload = Base64.urlsafe_encode64(JSON.generate("exp" => Time.now.to_i + 3600), padding: false)
|
|
35
|
+
token = "header.#{payload}.signature"
|
|
36
|
+
data = { "api" => { "authToken" => token } }
|
|
37
|
+
page = "<script>\nwindow.initialData = #{JSON.generate(data)};\n</script>\n200"
|
|
38
|
+
# Substitute only the network response, not the installed package's path resolution.
|
|
39
|
+
File.write(@binary, "#!#{RbConfig.ruby}\nSTDOUT.write(#{page.dump})\n")
|
|
40
|
+
output, error, status = Open3.capture3(
|
|
41
|
+
{ "PATH" => @directory, "RUBYOPT" => nil, "BUNDLER_SETUP" => nil,
|
|
42
|
+
"GEM_PATH" => Gem.path.join(File::PATH_SEPARATOR) }, RbConfig.ruby,
|
|
43
|
+
"-I#{File.join(@spec.full_gem_path, 'lib')}", *cinebase_load_path, "-rodeon_uk",
|
|
44
|
+
"-e", "print OdeonUk.acquire_token!"
|
|
45
|
+
)
|
|
46
|
+
assert status.success?, error
|
|
47
|
+
assert_equal token, output
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# The package is installed without dependencies, so load the bundle's cinebase.
|
|
53
|
+
def cinebase_load_path
|
|
54
|
+
Gem.loaded_specs.fetch("cinebase").full_require_paths.map { |path| "-I#{path}" }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -2,40 +2,15 @@
|
|
|
2
2
|
module ApiFixturesHelper
|
|
3
3
|
private
|
|
4
4
|
|
|
5
|
-
def
|
|
6
|
-
read_fixture('api/
|
|
5
|
+
def sites_json
|
|
6
|
+
read_fixture('api/sites')
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
read_fixture(
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def film_times_plist(cinema_id, film_id)
|
|
14
|
-
read_fixture("api/film_times/#{cinema_id}-#{film_id}")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def film_times_plist_random
|
|
18
|
-
read_fixture("api/film_times/#{film_times_plist_names(71).sample}")
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def film_times_plist_names(cinema_id)
|
|
22
|
-
Dir.entries(File.expand_path('../../fixtures/api/film_times', __FILE__))
|
|
23
|
-
.reject { |filename| !filename.match(/\A#{cinema_id}-/) }
|
|
24
|
-
.map { |filename| filename.gsub('.plist', '') }
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def parse(content)
|
|
28
|
-
plist = CFPropertyList::List.new(data: content).value
|
|
29
|
-
CFPropertyList.native_types(plist).fetch('data', {})
|
|
9
|
+
def showtimes_json(cinema_id)
|
|
10
|
+
read_fixture("api/showtimes-#{cinema_id}")
|
|
30
11
|
end
|
|
31
12
|
|
|
32
13
|
def read_fixture(filepath)
|
|
33
|
-
File.read(File.expand_path("../../fixtures/#{filepath}.
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def stub_post(site_path, request_body, response_body)
|
|
37
|
-
url = "https://api.odeon.co.uk/2.1/api/#{site_path}"
|
|
38
|
-
response = { status: 200, body: response_body, headers: {} }
|
|
39
|
-
stub_request(:post, url).with(body: request_body).to_return(response)
|
|
14
|
+
File.read(File.expand_path("../../fixtures/#{filepath}.json", __FILE__))
|
|
40
15
|
end
|
|
41
16
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
|
|
3
|
+
# The parts of Vista responses the gem reads. Checked against the hand-written
|
|
4
|
+
# fixtures and, in the live suite, against real responses held only in memory.
|
|
5
|
+
module ApiShapes
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def assert_sites_shape(data)
|
|
9
|
+
sites = data.fetch('sites')
|
|
10
|
+
refute_empty sites
|
|
11
|
+
sites.each do |site|
|
|
12
|
+
assert_match(/\A\d{3}\z/, site.fetch('id'))
|
|
13
|
+
assert_kind_of String, site.dig('name', 'text')
|
|
14
|
+
address = site.fetch('contactDetails').fetch('address')
|
|
15
|
+
%w(line1 line2 city).each do |key|
|
|
16
|
+
assert_kind_of String, address.fetch(key), "site #{site['id']} #{key}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def assert_showtimes_shape(data)
|
|
22
|
+
related = data.fetch('relatedData')
|
|
23
|
+
films = related.fetch('films').to_h { |film| [film.fetch('id'), film] }
|
|
24
|
+
attributes = related.fetch('attributes').to_h do |attribute|
|
|
25
|
+
[attribute.fetch('id'), attribute]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
films.each_value { |film| assert_kind_of String, film.dig('title', 'text') }
|
|
29
|
+
attributes.each_value do |attribute|
|
|
30
|
+
assert_kind_of String, attribute.dig('shortName', 'text')
|
|
31
|
+
assert_kind_of String, attribute.dig('name', 'text')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
showtimes = data.fetch('showtimes')
|
|
35
|
+
refute_empty showtimes
|
|
36
|
+
showtimes.each do |showtime|
|
|
37
|
+
assert_kind_of String, showtime.fetch('id')
|
|
38
|
+
assert_includes films.keys, showtime.fetch('filmId')
|
|
39
|
+
assert_kind_of Time, Time.iso8601(showtime.fetch('schedule').fetch('startsAt'))
|
|
40
|
+
assert_includes [true, false], showtime.fetch('requires3dGlasses')
|
|
41
|
+
showtime.fetch('attributeIds').each do |id|
|
|
42
|
+
assert_includes attributes.keys, id
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -3,15 +3,18 @@ require_relative 'api_fixtures_helper'
|
|
|
3
3
|
class FakeApiResponse
|
|
4
4
|
include ApiFixturesHelper
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
attr_reader :requested_dates
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@requested_dates = []
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
def
|
|
11
|
-
parse(
|
|
12
|
+
def sites
|
|
13
|
+
JSON.parse(sites_json).fetch('sites')
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
+
def showtimes(cinema_id, date)
|
|
17
|
+
@requested_dates << date
|
|
18
|
+
JSON.parse(showtimes_json(cinema_id))
|
|
16
19
|
end
|
|
17
20
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
1
|
+
require 'simplecov'
|
|
2
|
+
SimpleCov.start do
|
|
3
|
+
add_filter '/test/'
|
|
4
|
+
end
|
|
3
5
|
|
|
4
6
|
require 'minitest/autorun'
|
|
7
|
+
require 'minitest/mock'
|
|
5
8
|
require 'minitest/reporters'
|
|
6
9
|
|
|
7
10
|
Minitest::Reporters.use! [
|
|
@@ -9,9 +12,9 @@ Minitest::Reporters.use! [
|
|
|
9
12
|
]
|
|
10
13
|
|
|
11
14
|
require 'webmock/minitest'
|
|
12
|
-
WebMock.allow_net_connect!
|
|
13
15
|
|
|
14
16
|
require File.expand_path('../../lib/odeon_uk.rb', __FILE__)
|
|
15
17
|
|
|
16
18
|
require_relative 'support/api_fixtures_helper'
|
|
19
|
+
require_relative 'support/api_shapes'
|
|
17
20
|
require_relative 'support/fake_api_response'
|