odeon_uk 4.0.0 → 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 +33 -0
- data/README.md +90 -21
- data/Rakefile +14 -15
- data/lib/odeon_uk/cinema.rb +41 -23
- 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 -40
- 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 -123
- 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,149 +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(71) }
|
|
12
|
-
|
|
13
|
-
it 'returns an array of performances' do
|
|
14
|
-
OdeonUk::Internal::ApiResponse.stub :new, api_response do
|
|
15
|
-
subject.must_be_instance_of(Array)
|
|
16
|
-
subject.each do |element|
|
|
17
|
-
element.must_be_instance_of(described_class)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
3
|
+
class OdeonUk::PerformanceTest < Minitest::Test
|
|
4
|
+
DATE = Date.new(2026, 10, 24)
|
|
21
5
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
subject.count.must_be :>, 110
|
|
25
|
-
end
|
|
26
|
-
end
|
|
6
|
+
def setup
|
|
7
|
+
@api_response = FakeApiResponse.new
|
|
27
8
|
end
|
|
28
9
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
film_name: 'The Big Short',
|
|
36
|
-
cinema_id: 71,
|
|
37
|
-
cinema_name: 'Brighton',
|
|
38
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
39
|
-
}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'sets cinema name and film name' do
|
|
43
|
-
subject.film_name.must_equal 'The Big Short'
|
|
44
|
-
subject.cinema_name.must_equal 'Brighton'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it 'booking url, dimension & varient are set to defaults' do
|
|
48
|
-
subject.booking_url.must_equal nil
|
|
49
|
-
subject.dimension.must_equal '2d'
|
|
50
|
-
subject.variant.must_equal []
|
|
51
|
-
end
|
|
52
|
-
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
|
|
53
15
|
end
|
|
54
16
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
film_name: 'Ant Man',
|
|
59
|
-
dimension: '3d',
|
|
60
|
-
cinema_id: 71,
|
|
61
|
-
cinema_name: 'Brighton',
|
|
62
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
63
|
-
}
|
|
64
|
-
end
|
|
17
|
+
def test_at_accepts_string_id
|
|
18
|
+
assert_equal 6, performances_at('824').count
|
|
19
|
+
end
|
|
65
20
|
|
|
66
|
-
|
|
21
|
+
def test_at_sets_cinema_details
|
|
22
|
+
performances = performances_at(824)
|
|
67
23
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
subject.must_equal '3d'
|
|
71
|
-
end
|
|
24
|
+
assert_equal ['824'], performances.map(&:cinema_id).uniq
|
|
25
|
+
assert_equal ['Brighton'], performances.map(&:cinema_name).uniq
|
|
72
26
|
end
|
|
73
27
|
|
|
74
|
-
|
|
75
|
-
|
|
28
|
+
def test_at_parses_first_performance
|
|
29
|
+
performance = performances_at(824).first
|
|
76
30
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
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
|
|
86
38
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
subject.must_equal Time.utc(2013, 9, 12, 11, 0)
|
|
90
|
-
end
|
|
91
|
-
end
|
|
39
|
+
def test_at_parses_3d_imax
|
|
40
|
+
performance = performances_at(824)[1]
|
|
92
41
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{
|
|
96
|
-
film_name: 'Steve Jobs',
|
|
97
|
-
cinema_id: 71,
|
|
98
|
-
cinema_name: 'Brighton',
|
|
99
|
-
starting_at: Time.new(2013, 9, 12, 11, 0)
|
|
100
|
-
}
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it 'returns UTC time' do
|
|
104
|
-
subject.must_be_instance_of Time
|
|
105
|
-
subject.must_equal Time.utc(2013, 9, 12, 10, 0)
|
|
106
|
-
subject.utc?.must_equal(true)
|
|
107
|
-
end
|
|
108
|
-
end
|
|
42
|
+
assert_equal '3d', performance.dimension
|
|
43
|
+
assert_equal %w(imax), performance.variant
|
|
109
44
|
end
|
|
110
45
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
cinema_id: 71,
|
|
116
|
-
cinema_name: 'Brighton',
|
|
117
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0)
|
|
118
|
-
}
|
|
119
|
-
end
|
|
46
|
+
def test_at_returns_language_and_subtitles
|
|
47
|
+
performances = performances_at(824)
|
|
48
|
+
tamil = performances[3]
|
|
49
|
+
korean = performances[2]
|
|
120
50
|
|
|
121
|
-
|
|
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
|
|
122
57
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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?
|
|
127
64
|
end
|
|
128
65
|
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
131
69
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
cinema_name: 'Brighton',
|
|
137
|
-
starting_at: Time.utc(2013, 9, 12, 11, 0),
|
|
138
|
-
variant: %w(Subtitles Senior)
|
|
139
|
-
}
|
|
140
|
-
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) }
|
|
141
74
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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)
|
|
146
81
|
end
|
|
147
82
|
end
|
|
148
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
|
|
149
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'
|