ticket_sales 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ module TicketSales
2
+ module TicketSearch
3
+ def get_tickets(from, to)
4
+ filter Criteria.from(from) & Criteria.to(to)
5
+ end
6
+
7
+ def cheapest_ticket(from, to)
8
+ get_tickets(from, to).min_by(&:price)
9
+ end
10
+
11
+ def fastest_ticket(from, to)
12
+ get_tickets(from, to).min_by(&:travel_length)
13
+ end
14
+
15
+ def tickets_arriving_at(location, time)
16
+ filter Criteria.to(location) & Criteria.arrives_before(time)
17
+ end
18
+
19
+ def tickets_departing_from(location, time)
20
+ filter Criteria.from(location) & Criteria.departs_after(time)
21
+ end
22
+
23
+ def previous_tickets_combined_with(ticket)
24
+ tickets_arriving_at(ticket.from, ticket.departure_time).map do |current|
25
+ current.combine ticket
26
+ end
27
+ end
28
+
29
+ def next_tickets_combined_with(ticket)
30
+ tickets_departing_from(ticket.to, ticket.arrival_time).map do |current|
31
+ ticket.combine current
32
+ end
33
+ end
34
+
35
+ def tickets_connected_with(ticket)
36
+ tickets_arriving_at(ticket.from, ticket.departure_time).
37
+ product(tickets_departing_from(ticket.to, ticket.arrival_time)).map do |left, right|
38
+ left.combine(ticket).combine(right)
39
+ end
40
+ end
41
+ end
42
+
43
+ class TicketList
44
+ include Enumerable
45
+ include TicketSearch
46
+
47
+ attr_reader :tickets
48
+
49
+ def initialize
50
+ @tickets = []
51
+ end
52
+
53
+ def add(ticket)
54
+ @tickets |= tickets_combined_with(ticket)
55
+ @tickets << ticket
56
+ end
57
+
58
+ def each(&block)
59
+ @tickets.each(&block)
60
+ end
61
+
62
+ def filter(criteria)
63
+ @tickets.select { |ticket| criteria.met_by? ticket }
64
+ end
65
+
66
+ private
67
+
68
+ def tickets_combined_with(ticket)
69
+ previous_tickets_combined_with(ticket) |
70
+ next_tickets_combined_with(ticket) |
71
+ tickets_connected_with(ticket)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,31 @@
1
+ module TicketSales
2
+ class User
3
+ attr_reader :name, :email, :inventory, :balance
4
+
5
+ def initialize(name, email, balance)
6
+ @name = name
7
+ @email = email
8
+ @balance = balance
9
+ @inventory = []
10
+ end
11
+
12
+ def can_pay?(price)
13
+ @balance >= price
14
+ end
15
+
16
+ def buy(item, price)
17
+ add item
18
+ pay price
19
+ end
20
+
21
+ private
22
+
23
+ def pay(price)
24
+ @balance -= price
25
+ end
26
+
27
+ def add(item)
28
+ @inventory << item
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH << './lib'
2
+
3
+ require 'ticket_sales'
4
+ require 'minitest/autorun'
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ # class TestClassName < MiniTest::Unit::TestCase
4
+ # def setup
5
+
6
+ # end
7
+
8
+ # # Tests
9
+ # # ======================================
10
+
11
+ # end
@@ -0,0 +1,133 @@
1
+ require 'test_helper'
2
+
3
+ class TestCriteria < MiniTest::Unit::TestCase
4
+ include TicketSales
5
+
6
+ def setup
7
+ @haskovo_sofia = Ticket.build 'Haskovo', 'Sofia', 230, Time.new(2013, 3, 3, 15),
8
+ Time.new(2013, 3, 3, 18), '20'.to_d, 'fast, class A, cheap'
9
+ @sofia_moscow = Ticket.build 'Sofia', 'Moscow', 1800, Time.new(2013, 3, 3, 15),
10
+ Time.new(2013,3,3, 17), '130'.to_d, 'airplane ticket, fast'
11
+ end
12
+
13
+ # Tests
14
+
15
+ def test_criteria_from
16
+ assert Criteria.from('Haskovo').met_by? @haskovo_sofia
17
+ refute Criteria.from('qwe').met_by? @haskovo_sofia
18
+ refute Criteria.from('Sofia').met_by? @haskovo_sofia
19
+ assert Criteria.from('Sofia').met_by? @sofia_moscow
20
+ refute Criteria.from('Haskovo').met_by? @sofia_moscow
21
+ refute Criteria.from('12345').met_by? @sofia_moscow
22
+ end
23
+
24
+ def test_criteria_from
25
+ assert Criteria.to('Sofia').met_by? @haskovo_sofia
26
+ refute Criteria.to('Moscow').met_by? @haskovo_sofia
27
+ refute Criteria.to('qwe').met_by? @haskovo_sofia
28
+ assert Criteria.to('Moscow').met_by? @sofia_moscow
29
+ refute Criteria.to('Sofia').met_by? @sofia_moscow
30
+ refute Criteria.to('12345').met_by? @sofia_moscow
31
+ end
32
+
33
+ def test_criteria_price_from
34
+ assert Criteria.price_from('10'.to_d).met_by? @haskovo_sofia
35
+ refute Criteria.price_from('25'.to_d).met_by? @haskovo_sofia
36
+ assert Criteria.price_from('-5'.to_d).met_by? @haskovo_sofia
37
+ assert Criteria.price_from('100'.to_d).met_by? @sofia_moscow
38
+ refute Criteria.price_from('140'.to_d).met_by? @sofia_moscow
39
+ assert Criteria.price_from('0'.to_d).met_by? @sofia_moscow
40
+ end
41
+
42
+ def test_criteria_price_to
43
+ assert Criteria.price_to('30'.to_d).met_by? @haskovo_sofia
44
+ refute Criteria.price_to('15'.to_d).met_by? @haskovo_sofia
45
+ assert Criteria.price_to('100'.to_d).met_by? @haskovo_sofia
46
+ assert Criteria.price_to('300'.to_d).met_by? @sofia_moscow
47
+ refute Criteria.price_to('100'.to_d).met_by? @sofia_moscow
48
+ assert Criteria.price_to('140'.to_d).met_by? @sofia_moscow
49
+ end
50
+
51
+ def test_criteria_feature
52
+ assert Criteria.feature('fast').met_by? @sofia_moscow
53
+ assert Criteria.feature('fast').met_by? @haskovo_sofia
54
+ refute Criteria.feature('slow').met_by? @sofia_moscow
55
+ refute Criteria.feature('slow').met_by? @haskovo_sofia
56
+ assert Criteria.feature('airplane').met_by? @sofia_moscow
57
+ refute Criteria.feature('airplane').met_by? @haskovo_sofia
58
+ end
59
+
60
+ def test_criteria_departs_after
61
+ assert Criteria.departs_after(Time.new 2013, 3, 3, 10).met_by? @sofia_moscow
62
+ assert Criteria.departs_after(Time.new 2013, 3, 3, 11).met_by? @haskovo_sofia
63
+ refute Criteria.departs_after(Time.new 2013, 3, 3, 15).met_by? @sofia_moscow
64
+ refute Criteria.departs_after(Time.new 2013, 3, 3, 15).met_by? @haskovo_sofia
65
+ assert Criteria.departs_after(Time.new 2013, 3, 3, 14, 59).met_by? @sofia_moscow
66
+ refute Criteria.departs_after(Time.new 2013, 3, 3, 18).met_by? @haskovo_sofia
67
+ end
68
+
69
+ def test_criteria_departs_before
70
+ refute Criteria.departs_before(Time.new 2013, 3, 3, 10).met_by? @sofia_moscow
71
+ refute Criteria.departs_before(Time.new 2013, 3, 3, 11).met_by? @haskovo_sofia
72
+ refute Criteria.departs_before(Time.new 2013, 3, 3, 15).met_by? @sofia_moscow
73
+ refute Criteria.departs_before(Time.new 2013, 3, 3, 15).met_by? @haskovo_sofia
74
+ assert Criteria.departs_before(Time.new 2013, 3, 3, 15, 1).met_by? @sofia_moscow
75
+ refute Criteria.departs_before(Time.new 2013, 3, 3, 14, 59).met_by? @haskovo_sofia
76
+ end
77
+
78
+ def test_criteria_arrives_before
79
+ refute Criteria.arrives_before(Time.new 2013, 3, 3, 10).met_by? @sofia_moscow
80
+ assert Criteria.arrives_before(Time.new 2013, 3, 3, 18, 30).met_by? @haskovo_sofia
81
+ refute Criteria.arrives_before(Time.new 2013, 3, 3, 15, 10).met_by? @sofia_moscow
82
+ refute Criteria.arrives_before(Time.new 2013, 3, 3, 16).met_by? @haskovo_sofia
83
+ assert Criteria.arrives_before(Time.new 2013, 3, 3, 17, 1).met_by? @sofia_moscow
84
+ refute Criteria.arrives_before(Time.new 2013, 3, 3, 18).met_by? @haskovo_sofia
85
+ end
86
+
87
+ def test_criteria_arrives_after
88
+ assert Criteria.arrives_after(Time.new 2013, 3, 3, 15).met_by? @sofia_moscow
89
+ refute Criteria.arrives_after(Time.new 2013, 3, 3, 18, 30).met_by? @haskovo_sofia
90
+ assert Criteria.arrives_after(Time.new 2013, 3, 3, 14, 35).met_by? @sofia_moscow
91
+ assert Criteria.arrives_after(Time.new 2013, 3, 3, 16).met_by? @haskovo_sofia
92
+ refute Criteria.arrives_after(Time.new 2013, 3, 3, 17, 1).met_by? @sofia_moscow
93
+ assert Criteria.arrives_after(Time.new 2013, 3, 3, 17, 59).met_by? @haskovo_sofia
94
+ end
95
+
96
+ def test_criteria_conjunction
97
+ criteria = Criteria.to('Sofia') & Criteria.from('Haskovo')
98
+ assert criteria.met_by?(@haskovo_sofia)
99
+ refute criteria.met_by?(@sofia_moscow)
100
+
101
+ criteria = Criteria.to('Sofia') & Criteria.to('Haskovo')
102
+ refute criteria.met_by?(@haskovo_sofia)
103
+ refute criteria.met_by?(@sofia_moscow)
104
+ end
105
+
106
+ def test_criteria_conjunction
107
+ criteria = Criteria.to('Sofia') | Criteria.from('Haskovo')
108
+ assert criteria.met_by?(@haskovo_sofia)
109
+ refute criteria.met_by?(@sofia_moscow)
110
+
111
+ criteria = Criteria.to('Sofia') | Criteria.to('Moscow')
112
+ assert criteria.met_by?(@haskovo_sofia)
113
+ assert criteria.met_by?(@sofia_moscow)
114
+
115
+ criteria = Criteria.departs_after(Time.new 2015) | Criteria.departs_after(Time.new 2014)
116
+ refute criteria.met_by?(@haskovo_sofia)
117
+ refute criteria.met_by?(@sofia_moscow)
118
+ end
119
+
120
+ def test_negation
121
+ criteria = !Criteria.from('Haskovo')
122
+ refute criteria.met_by? @haskovo_sofia
123
+ assert criteria.met_by? @sofia_moscow
124
+
125
+ criteria = !Criteria.feature('lol')
126
+ assert criteria.met_by? @haskovo_sofia
127
+ assert criteria.met_by? @sofia_moscow
128
+
129
+ criteria = !Criteria.feature('airplane')
130
+ assert criteria.met_by? @haskovo_sofia
131
+ refute criteria.met_by? @sofia_moscow
132
+ end
133
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+
4
+ class TestDataModels < MiniTest::Unit::TestCase
5
+ include DataModels
6
+
7
+ def setup
8
+ DataMapper.finalize.auto_migrate!
9
+ end
10
+
11
+ def test_creating_data_objects
12
+ property = Property.create(count: 10, promotion_name: :percent, promotion_value: '10'.to_d)
13
+
14
+ ticket = Ticket.create(from: 'Haskovo', to: 'Ruse', distance: 230, departure_time: Time.new(2013, 3, 3, 14),
15
+ arrival_time: Time.new(2013, 3, 3, 19), price: '123'.to_d, features: 'lol', property: property)
16
+
17
+ assert_equal property, ticket.property
18
+
19
+ center = TicketCenter.create(tickets: [ticket])
20
+ assert_includes center.tickets, ticket
21
+ assert_equal center, TicketCenter.first
22
+ assert_equal property, TicketCenter.first.tickets.first.property
23
+ end
24
+ end
@@ -0,0 +1,94 @@
1
+ require 'test_helper'
2
+
3
+ class TestRepository < MiniTest::Unit::TestCase
4
+ def setup
5
+ DataMapper.finalize.auto_migrate!
6
+
7
+ @center = TicketSales::TicketCenter.new
8
+ @haskovo_sofia = TicketSales::Ticket.build 'Haskovo', 'Sofia', 230, Time.new(2013, 3, 3, 15),
9
+ Time.new(2013, 3, 3, 18), '15'.to_d, 'fast, class A, cheap'
10
+ @sofia_ruse = TicketSales::Ticket.build 'Sofia', 'Ruse', 400, Time.new(2013, 3, 3, 19),
11
+ Time.new(2013, 3, 4), '15'.to_d, 'long'
12
+ @ruse_burgas = TicketSales::Ticket.build 'Ruse', 'Burgas', 500, Time.new(2013, 3, 4, 5),
13
+ Time.new(2013, 3, 4, 13), '35'.to_d, ''
14
+ @not_added = TicketSales::Ticket.build 'Burgas', 'Moscow', 1900, Time.new(2013, 3, 4, 6),
15
+ Time.new(2013, 3, 4, 17), '100'.to_d, ''
16
+
17
+ @center.add @haskovo_sofia, 10, TicketSales::Promotion.build(percent: 10)
18
+ @center.add @sofia_ruse, 15, TicketSales::Promotion.build(amount: 3)
19
+ @center.add @ruse_burgas, 10, TicketSales::Promotion.build(hour: 1)
20
+ end
21
+
22
+ def data_ticket_equals_normal_ticket?(ticket, property, data_ticket)
23
+ ticket.from == data_ticket.from and
24
+ ticket.to == data_ticket.to and
25
+ ticket.distance == data_ticket.distance and
26
+ ticket.departure_time == data_ticket.departure_time.to_time and
27
+ ticket.arrival_time == data_ticket.arrival_time.to_time and
28
+ ticket.price == data_ticket.price and
29
+ ticket.features == data_ticket.features and
30
+ property.count == data_ticket.property.count
31
+ end
32
+
33
+ # Tests
34
+
35
+ def test_persisting_a_ticket_center
36
+ DataModels::Repository.persist @center
37
+
38
+ center = DataModels::TicketCenter.get(1)
39
+ assert_respond_to center, :save
40
+ assert_respond_to center, :id
41
+ assert_respond_to center, :tickets
42
+ assert center.id
43
+
44
+ can_be_found = center.tickets.any? do |data_ticket|
45
+ data_ticket_equals_normal_ticket? @haskovo_sofia, @center.properties[@haskovo_sofia], data_ticket
46
+ end
47
+ assert can_be_found
48
+
49
+ can_be_found = center.tickets.any? do |data_ticket|
50
+ data_ticket_equals_normal_ticket? @sofia_ruse, @center.properties[@sofia_ruse], data_ticket
51
+ end
52
+ assert can_be_found
53
+
54
+ can_be_found = center.tickets.any? do |data_ticket|
55
+ data_ticket_equals_normal_ticket? @ruse_burgas, @center.properties[@ruse_burgas], data_ticket
56
+ end
57
+ assert can_be_found
58
+
59
+ can_be_found = center.tickets.any? do |data_ticket|
60
+ data_ticket_equals_normal_ticket? @not_added, @center.properties[@not_added], data_ticket
61
+ end
62
+ refute can_be_found
63
+ end
64
+
65
+ def test_finding_and_mapping_data_center_to_ticket_center
66
+ DataModels::Repository.persist @center
67
+ center_data = DataModels::Repository.find(1)
68
+
69
+ center = DataModels::Repository.ticket_center_from(center_data)
70
+ assert_respond_to center, :available?
71
+ assert_respond_to center, :add
72
+ assert_respond_to center, :sell
73
+
74
+ assert center.available? @haskovo_sofia, 10
75
+ assert center.available? @sofia_ruse, 15
76
+ assert center.available? @ruse_burgas, 10
77
+ refute center.available? @haskovo_sofia, 11
78
+ refute center.available? @sofia_ruse, 16
79
+ refute center.available? @ruse_burgas, 11
80
+ refute center.available? @not_added
81
+
82
+ assert_equal 10, center.properties[@haskovo_sofia].count
83
+ assert_kind_of TicketSales::Promotion::PercentOff, center.properties[@haskovo_sofia].promotion
84
+ assert_equal 10, center.properties[@haskovo_sofia].promotion.percent
85
+
86
+ assert_equal 15, center.properties[@sofia_ruse].count
87
+ assert_kind_of TicketSales::Promotion::AmountOff, center.properties[@sofia_ruse].promotion
88
+ assert_equal 3, center.properties[@sofia_ruse].promotion.amount
89
+
90
+ assert_equal 10, center.properties[@ruse_burgas].count
91
+ assert_kind_of TicketSales::Promotion::EveryHour, center.properties[@ruse_burgas].promotion
92
+ assert_equal 1, center.properties[@ruse_burgas].promotion.amount
93
+ end
94
+ end
@@ -0,0 +1,115 @@
1
+ require 'test_helper'
2
+
3
+ class TestPromotions < MiniTest::Unit::TestCase
4
+ def setup
5
+ @haskovo_sofia = TicketSales::Ticket.build 'Haskovo', 'Sofia', 230, Time.new(2013, 3, 3, 15),
6
+ Time.new(2013, 3, 3, 18), '15'.to_d, 'fast, class A, cheap'
7
+ @sofia_ruse = TicketSales::Ticket.build 'Sofia', 'Ruse', 400, Time.new(2013, 3, 3, 19),
8
+ Time.new(2013,3,4), '12'.to_d, 'long'
9
+ @ruse_burgas = TicketSales::Ticket.build 'Ruse', 'Burgas', 500, Time.new(2013, 3, 4, 5),
10
+ Time.new(2013, 3, 4, 13), '35'.to_d, ''
11
+ @burgas_moscow = TicketSales::Ticket.build 'Burgas', 'Moscow', 1900, Time.new(2013, 3, 4, 20),
12
+ Time.new(2013, 3, 4, 22), '120'.to_d, 'airplane'
13
+ end
14
+
15
+ # Tests
16
+
17
+ def test_bulding_promotion
18
+ percent_off = TicketSales::Promotion.build percent: 10
19
+ assert_kind_of TicketSales::Promotion::PercentOff, percent_off
20
+ assert_equal 10, percent_off.percent
21
+
22
+ amount_off = TicketSales::Promotion.build amount: 10
23
+ assert_kind_of TicketSales::Promotion::AmountOff, amount_off
24
+ assert_equal 10, amount_off.amount
25
+
26
+ amount_off_for_kilometers = TicketSales::Promotion.build hundred_kilometers: 15
27
+ assert_kind_of TicketSales::Promotion::EveryHundredthKilometer, amount_off_for_kilometers
28
+ assert_equal 15, amount_off_for_kilometers.amount
29
+
30
+ amount_off_for_stop = TicketSales::Promotion.build stop: 5
31
+ assert_kind_of TicketSales::Promotion::EveryStop, amount_off_for_stop
32
+ assert_equal 5, amount_off_for_stop.amount
33
+
34
+ amount_off_for_hour = TicketSales::Promotion.build hour: 2
35
+ assert_kind_of TicketSales::Promotion::EveryHour, amount_off_for_hour
36
+ assert_equal 2, amount_off_for_hour.amount
37
+ end
38
+
39
+ def test_promotion_percent_off
40
+ ten_percent_off = TicketSales::Promotion.build percent: 10
41
+ assert_equal '1.5'.to_d, ten_percent_off.discount(@haskovo_sofia)
42
+ assert_equal '1.2'.to_d, ten_percent_off.discount(@sofia_ruse)
43
+ assert_equal '3.5'.to_d, ten_percent_off.discount(@ruse_burgas)
44
+ assert_equal '12'.to_d, ten_percent_off.discount(@burgas_moscow)
45
+
46
+ twenty_five_percent_off = TicketSales::Promotion.build percent: 25
47
+ assert_equal '3.75'.to_d, twenty_five_percent_off.discount(@haskovo_sofia)
48
+ assert_equal '3'.to_d, twenty_five_percent_off.discount(@sofia_ruse)
49
+ assert_equal '8.75'.to_d, twenty_five_percent_off.discount(@ruse_burgas)
50
+ assert_equal '30'.to_d, twenty_five_percent_off.discount(@burgas_moscow)
51
+ end
52
+
53
+ def test_promotion_amount_off
54
+ thirteen_off = TicketSales::Promotion.build amount: 13
55
+ assert_equal '13'.to_d, thirteen_off.discount(@haskovo_sofia)
56
+ assert_equal '12'.to_d, thirteen_off.discount(@sofia_ruse)
57
+ assert_equal '13'.to_d, thirteen_off.discount(@ruse_burgas)
58
+ assert_equal '13'.to_d, thirteen_off.discount(@burgas_moscow)
59
+
60
+ twenty_off = TicketSales::Promotion.build amount: 20
61
+ assert_equal '15'.to_d, twenty_off.discount(@haskovo_sofia)
62
+ assert_equal '12'.to_d, twenty_off.discount(@sofia_ruse)
63
+ assert_equal '20'.to_d, twenty_off.discount(@ruse_burgas)
64
+ assert_equal '20'.to_d, twenty_off.discount(@burgas_moscow)
65
+ end
66
+
67
+ def test_promotion_amount_off_for_every_hundredth_kilometer
68
+ promotion = TicketSales::Promotion.build hundred_kilometers: 1
69
+ assert_equal '2'.to_d, promotion.discount(@haskovo_sofia)
70
+ assert_equal '4'.to_d, promotion.discount(@sofia_ruse)
71
+ assert_equal '5'.to_d, promotion.discount(@ruse_burgas)
72
+ assert_equal '19'.to_d, promotion.discount(@burgas_moscow)
73
+
74
+ promotion = TicketSales::Promotion.build hundred_kilometers: 5
75
+ assert_equal '10'.to_d, promotion.discount(@haskovo_sofia)
76
+ assert_equal '12'.to_d, promotion.discount(@sofia_ruse)
77
+ assert_equal '25'.to_d, promotion.discount(@ruse_burgas)
78
+ assert_equal '95'.to_d, promotion.discount(@burgas_moscow)
79
+ end
80
+
81
+ def test_promotion_amount_off_for_every_stop
82
+ promotion = TicketSales::Promotion.build stop: 2
83
+ assert_equal '0'.to_d, promotion.discount(@haskovo_sofia)
84
+ assert_equal '0'.to_d, promotion.discount(@sofia_ruse)
85
+ assert_equal '0'.to_d, promotion.discount(@ruse_burgas)
86
+ assert_equal '0'.to_d, promotion.discount(@burgas_moscow)
87
+ assert_equal '2'.to_d, promotion.discount(@haskovo_sofia.combine(@sofia_ruse))
88
+ assert_equal '4'.to_d, promotion.discount(@haskovo_sofia.combine(@sofia_ruse).combine(@ruse_burgas))
89
+
90
+ promotion = TicketSales::Promotion.build stop: 30
91
+ assert_equal '27'.to_d, promotion.discount(@haskovo_sofia.combine(@sofia_ruse))
92
+ end
93
+
94
+ def test_promotion_amount_off_for_every_hour
95
+ promotion = TicketSales::Promotion.build hour: 1
96
+ assert_equal '3'.to_d, promotion.discount(@haskovo_sofia)
97
+ assert_equal '5'.to_d, promotion.discount(@sofia_ruse)
98
+ assert_equal '8'.to_d, promotion.discount(@ruse_burgas)
99
+ assert_equal '2'.to_d, promotion.discount(@burgas_moscow)
100
+
101
+ promotion = TicketSales::Promotion.build hour: 4
102
+ assert_equal '12'.to_d, promotion.discount(@haskovo_sofia)
103
+ assert_equal '12'.to_d, promotion.discount(@sofia_ruse)
104
+ assert_equal '32'.to_d, promotion.discount(@ruse_burgas)
105
+ assert_equal '8'.to_d, promotion.discount(@burgas_moscow)
106
+ end
107
+
108
+ def test_no_promotion
109
+ no_promotion = TicketSales::Promotion.build
110
+ assert_equal '0'.to_d, no_promotion.discount(@haskovo_sofia)
111
+ assert_equal '0'.to_d, no_promotion.discount(@sofia_ruse)
112
+ assert_equal '0'.to_d, no_promotion.discount(@ruse_burgas)
113
+ assert_equal '0'.to_d, no_promotion.discount(@burgas_moscow)
114
+ end
115
+ end