zxcvbn-ruby 1.1.0 → 1.2.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -3
  3. data/README.md +5 -5
  4. data/lib/zxcvbn/clock.rb +10 -0
  5. data/lib/zxcvbn/password_strength.rb +3 -3
  6. data/lib/zxcvbn/version.rb +3 -1
  7. metadata +9 -77
  8. data/.gitignore +0 -18
  9. data/.rspec +0 -1
  10. data/.travis.yml +0 -12
  11. data/CODE_OF_CONDUCT.md +0 -130
  12. data/Gemfile +0 -10
  13. data/Guardfile +0 -26
  14. data/Rakefile +0 -22
  15. data/spec/dictionary_ranker_spec.rb +0 -12
  16. data/spec/feedback_giver_spec.rb +0 -212
  17. data/spec/matchers/date_spec.rb +0 -109
  18. data/spec/matchers/dictionary_spec.rb +0 -30
  19. data/spec/matchers/digits_spec.rb +0 -15
  20. data/spec/matchers/l33t_spec.rb +0 -87
  21. data/spec/matchers/repeat_spec.rb +0 -18
  22. data/spec/matchers/sequences_spec.rb +0 -21
  23. data/spec/matchers/spatial_spec.rb +0 -20
  24. data/spec/matchers/year_spec.rb +0 -15
  25. data/spec/omnimatch_spec.rb +0 -24
  26. data/spec/scorer_spec.rb +0 -5
  27. data/spec/scoring/crack_time_spec.rb +0 -106
  28. data/spec/scoring/entropy_spec.rb +0 -216
  29. data/spec/scoring/math_spec.rb +0 -135
  30. data/spec/spec_helper.rb +0 -54
  31. data/spec/support/js_helpers.rb +0 -35
  32. data/spec/support/js_source/adjacency_graphs.js +0 -8
  33. data/spec/support/js_source/compiled.js +0 -1188
  34. data/spec/support/js_source/frequency_lists.js +0 -10
  35. data/spec/support/js_source/init.coffee +0 -63
  36. data/spec/support/js_source/init.js +0 -95
  37. data/spec/support/js_source/matching.coffee +0 -444
  38. data/spec/support/js_source/matching.js +0 -685
  39. data/spec/support/js_source/scoring.coffee +0 -270
  40. data/spec/support/js_source/scoring.js +0 -390
  41. data/spec/support/matcher.rb +0 -35
  42. data/spec/tester_spec.rb +0 -99
  43. data/spec/zxcvbn_spec.rb +0 -24
  44. data/zxcvbn-ruby.gemspec +0 -31
@@ -1,212 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::FeedbackGiver do
4
- # NOTE: We go in via the tester because the `FeedbackGiver` relies on both
5
- # Omnimatch and the Scorer, which are troublesome to wire up for tests
6
- let(:tester) { Zxcvbn::Tester.new }
7
-
8
- describe '.get_feedback' do
9
- it "gives empty feedback when a password's score is good" do
10
- feedback = tester.test('5815A30BE798').feedback
11
-
12
- expect(feedback).to be_a Zxcvbn::Feedback
13
- expect(feedback.warning).to be_nil
14
- expect(feedback.suggestions).to be_empty
15
- end
16
-
17
- it 'gives general feedback when a password is empty' do
18
- feedback = tester.test('').feedback
19
-
20
- expect(feedback).to be_a Zxcvbn::Feedback
21
- expect(feedback.warning).to be_nil
22
- expect(feedback.suggestions).to contain_exactly(
23
- 'Use a few words, avoid common phrases',
24
- 'No need for symbols, digits, or uppercase letters'
25
- )
26
- end
27
-
28
- it "gives general feedback when a password is poor but doesn't match any heuristics" do
29
- feedback = tester.test(':005:0').feedback
30
-
31
- expect(feedback).to be_a Zxcvbn::Feedback
32
- expect(feedback.warning).to be_nil
33
- expect(feedback.suggestions).to contain_exactly(
34
- 'Add another word or two. Uncommon words are better.'
35
- )
36
- end
37
-
38
- describe 'gives specific feedback' do
39
- describe 'for dictionary passwords' do
40
- it 'that are extremely common' do
41
- feedback = tester.test('password').feedback
42
-
43
- expect(feedback).to be_a Zxcvbn::Feedback
44
- expect(feedback.warning).to eql('This is a top-10 common password')
45
- expect(feedback.suggestions).to contain_exactly(
46
- 'Add another word or two. Uncommon words are better.'
47
- )
48
- end
49
-
50
- it 'that are very, very common' do
51
- feedback = tester.test('letmein').feedback
52
-
53
- expect(feedback).to be_a Zxcvbn::Feedback
54
- expect(feedback.warning).to eql('This is a top-100 common password')
55
- expect(feedback.suggestions).to contain_exactly(
56
- 'Add another word or two. Uncommon words are better.'
57
- )
58
- end
59
-
60
- it 'that are very common' do
61
- feedback = tester.test('playstation').feedback
62
-
63
- expect(feedback).to be_a Zxcvbn::Feedback
64
- expect(feedback.warning).to eql('This is a very common password')
65
- expect(feedback.suggestions).to contain_exactly(
66
- 'Add another word or two. Uncommon words are better.'
67
- )
68
- end
69
-
70
- it 'that are common and you tried to use l33tsp33k' do
71
- feedback = tester.test('pl4yst4ti0n').feedback
72
-
73
- expect(feedback).to be_a Zxcvbn::Feedback
74
- expect(feedback.warning).to eql(
75
- 'This is similar to a commonly used password'
76
- )
77
- expect(feedback.suggestions).to contain_exactly(
78
- 'Add another word or two. Uncommon words are better.',
79
- "Predictable substitutions like '@' instead of 'a' don't help very much"
80
- )
81
- end
82
-
83
- it 'that are common and you capitalised the start' do
84
- feedback = tester.test('Password').feedback
85
-
86
- expect(feedback).to be_a Zxcvbn::Feedback
87
- expect(feedback.warning).to eql(
88
- 'This is a top-10 common password'
89
- )
90
- expect(feedback.suggestions).to contain_exactly(
91
- 'Add another word or two. Uncommon words are better.',
92
- "Capitalization doesn't help very much"
93
- )
94
- end
95
-
96
- it 'that are common and you capitalised the whole thing' do
97
- feedback = tester.test('PASSWORD').feedback
98
-
99
- expect(feedback).to be_a Zxcvbn::Feedback
100
- expect(feedback.warning).to eql(
101
- 'This is a top-10 common password'
102
- )
103
- expect(feedback.suggestions).to contain_exactly(
104
- 'Add another word or two. Uncommon words are better.',
105
- 'All-uppercase is almost as easy to guess as all-lowercase'
106
- )
107
- end
108
-
109
- it 'that contain a common first name or last name' do
110
- feedback = tester.test('jessica').feedback
111
-
112
- expect(feedback).to be_a Zxcvbn::Feedback
113
- expect(feedback.warning).to eql(
114
- 'Names and surnames by themselves are easy to guess'
115
- )
116
- expect(feedback.suggestions).to contain_exactly(
117
- 'Add another word or two. Uncommon words are better.'
118
- )
119
-
120
- feedback = tester.test('smith').feedback
121
-
122
- expect(feedback).to be_a Zxcvbn::Feedback
123
- expect(feedback.warning).to eql(
124
- 'Names and surnames by themselves are easy to guess'
125
- )
126
- expect(feedback.suggestions).to contain_exactly(
127
- 'Add another word or two. Uncommon words are better.'
128
- )
129
- end
130
-
131
- it 'that contain a common name and surname' do
132
- feedback = tester.test('jessica smith').feedback
133
-
134
- expect(feedback).to be_a Zxcvbn::Feedback
135
- expect(feedback.warning).to eql(
136
- 'Common names and surnames are easy to guess'
137
- )
138
- expect(feedback.suggestions).to contain_exactly(
139
- 'Add another word or two. Uncommon words are better.'
140
- )
141
- end
142
- end
143
-
144
- describe 'for spatial passwords' do
145
- it 'that contain a straight keyboard row' do
146
- feedback = tester.test('1qaz').feedback
147
-
148
- expect(feedback).to be_a Zxcvbn::Feedback
149
- expect(feedback.warning).to eql(
150
- 'Straight rows of keys are easy to guess'
151
- )
152
- expect(feedback.suggestions).to contain_exactly(
153
- 'Add another word or two. Uncommon words are better.',
154
- 'Use a longer keyboard pattern with more turns'
155
- )
156
- end
157
-
158
- it 'that contain a keyboard pattern with one turn' do
159
- feedback = tester.test('zaqwer').feedback
160
-
161
- expect(feedback).to be_a Zxcvbn::Feedback
162
- expect(feedback.warning).to eql(
163
- 'Short keyboard patterns are easy to guess'
164
- )
165
- expect(feedback.suggestions).to contain_exactly(
166
- 'Add another word or two. Uncommon words are better.',
167
- 'Use a longer keyboard pattern with more turns'
168
- )
169
- end
170
- end
171
-
172
- it 'for passwords with repeated characters' do
173
- feedback = tester.test('zzz').feedback
174
-
175
- expect(feedback).to be_a Zxcvbn::Feedback
176
- expect(feedback.warning).to eql(
177
- 'Repeats like "aaa" are easy to guess'
178
- )
179
- expect(feedback.suggestions).to contain_exactly(
180
- 'Add another word or two. Uncommon words are better.',
181
- 'Avoid repeated words and characters'
182
- )
183
- end
184
-
185
- it 'for passwords with sequential characters' do
186
- feedback = tester.test('pqrpqrpqr').feedback
187
-
188
- expect(feedback).to be_a Zxcvbn::Feedback
189
- expect(feedback.warning).to eql(
190
- 'Sequences like abc or 6543 are easy to guess'
191
- )
192
- expect(feedback.suggestions).to contain_exactly(
193
- 'Add another word or two. Uncommon words are better.',
194
- 'Avoid sequences'
195
- )
196
- end
197
-
198
- it 'for passwords containing dates' do
199
- feedback = tester.test('testing02\12\1997').feedback
200
-
201
- expect(feedback).to be_a Zxcvbn::Feedback
202
- expect(feedback.warning).to eql(
203
- 'Dates are often easy to guess'
204
- )
205
- expect(feedback.suggestions).to contain_exactly(
206
- 'Add another word or two. Uncommon words are better.',
207
- 'Avoid dates and years that are associated with you'
208
- )
209
- end
210
- end
211
- end
212
- end
@@ -1,109 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Date do
4
- let(:matcher) { subject }
5
-
6
- {
7
- ' ' => 'testing02 12 1997',
8
- '-' => 'testing02-12-1997',
9
- '/' => 'testing02/12/1997',
10
- '\\' => 'testing02\12\1997',
11
- '_' => 'testing02_12_1997',
12
- '.' => 'testing02.12.1997'
13
- }.each do |separator, password|
14
- context "with #{separator} seperator" do
15
- let(:matches) { matcher.matches(password) }
16
-
17
- it 'finds matches' do
18
- expect(matches).not_to be_empty
19
- end
20
-
21
- it 'finds the correct matches' do
22
- expect(matches.count).to eq 1
23
- expect(matches[0].token).to eq %w[ 02 12 1997 ].join(separator)
24
- expect(matches[0].separator).to eq separator
25
- expect(matches[0].day).to eq 2
26
- expect(matches[0].month).to eq 12
27
- expect(matches[0].year).to eq 1997
28
- end
29
- end
30
- end
31
-
32
- # context 'without separator' do
33
- # context '5 digit date' do
34
- # let(:matches) { matcher.matches('13192boo') }
35
-
36
- # it 'finds matches' do
37
- # matches.should_not be_empty
38
- # end
39
-
40
- # it 'finds the correct matches' do
41
- # matches.count.should eq 2
42
- # matches[0].token.should eq '13192'
43
- # matches[0].separator.should eq ''
44
- # matches[0].day.should eq 13
45
- # matches[0].month.should eq 1
46
- # matches[0].year.should eq 1992
47
-
48
- # matches[1].token.should eq '13192'
49
- # matches[1].separator.should eq ''
50
- # matches[1].day.should eq 31
51
- # matches[1].month.should eq 1
52
- # matches[1].year.should eq 1992
53
- # end
54
- # end
55
- # end
56
-
57
- # describe '#extract_dates' do
58
- # {
59
- # '1234' => [
60
- # {:year => 2012, :month => 3, :day => 4},
61
- # {:year => 1934, :month => 2, :day => 1},
62
- # {:year => 1934, :month => 1, :day => 2}
63
- # ],
64
- # '12345' => [
65
- # {:year => 1945, :month => 3, :day => 12},
66
- # {:year => 1945, :month => 12, :day => 3},
67
- # {:year => 1945, :month => 1, :day => 23}
68
- # ],
69
- # '54321' => [
70
- # {:year => 1954, :month => 3, :day => 21}
71
- # ],
72
- # '151290' => [
73
- # {:year => 1990, :month => 12, :day => 15}
74
- # ],
75
- # '901215' => [
76
- # {:year => 1990, :month => 12, :day => 15}
77
- # ],
78
- # '1511990' => [
79
- # {:year => 1990, :month => 1, :day => 15}
80
- # ]
81
- # }.each do |token, expected_candidates|
82
- # it "finds the correct candidates for #{token}" do
83
- # matcher.extract_dates(token).should match_array expected_candidates
84
- # end
85
- # end
86
- # end
87
-
88
- # describe '#expand_year' do
89
- # {
90
- # 12 => 2012,
91
- # 01 => 2001,
92
- # 15 => 2015,
93
- # 19 => 2019,
94
- # 20 => 1920
95
- # }.each do |small, expanded|
96
- # it "expands #{small} to #{expanded}" do
97
- # matcher.expand_year(small).should eq expanded
98
- # end
99
- # end
100
- # end
101
-
102
- context 'invalid date' do
103
- let(:matches) { matcher.matches('testing0.x.1997') }
104
-
105
- it 'doesnt match' do
106
- expect(matches).to be_empty
107
- end
108
- end
109
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- describe Zxcvbn::Matchers::Dictionary do
6
- subject(:matcher) { described_class.new("Test dictionary", dictionary) }
7
-
8
- describe "#matches" do
9
- let(:matches) { matcher.matches(password) }
10
- let(:matched_words) { matches.map(&:matched_word) }
11
-
12
- context "Given a dictionary of English words" do
13
- let(:dictionary) { Zxcvbn::Data.new.ranked_dictionaries["english"] }
14
- let(:password) { "whatisinit" }
15
-
16
- it "finds all the matches" do
17
- expect(matched_words).to match_array %w[wha what ha hat a at tis i is sin i in i it]
18
- end
19
- end
20
-
21
- context "Given a custom dictionary" do
22
- let(:dictionary) { Zxcvbn::DictionaryRanker.rank_dictionary(%w[test AB10CD]) }
23
- let(:password) { "AB10CD" }
24
-
25
- it "matches uppercase passwords with normalised dictionary entries" do
26
- expect(matched_words).to match_array(%w[ab10cd])
27
- end
28
- end
29
- end
30
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Digits do
4
- let(:matcher) { subject }
5
- let(:matches) { matcher.matches('testing1239xx9712') }
6
-
7
- it 'sets the pattern name' do
8
- expect(matches.all? { |m| m.pattern == 'digits' }).to eql(true)
9
- end
10
-
11
- it 'finds the correct matches' do
12
- expect(matches.count).to eq(2)
13
- expect(matches[0].token).to eq '1239'
14
- end
15
- end
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::L33t do
4
- let(:matcher) { described_class.new([dictionary_matcher]) }
5
- let(:dictionary) { Zxcvbn::Data.new.ranked_dictionaries['english'] }
6
- let(:dictionary_matcher) { Zxcvbn::Matchers::Dictionary.new('english', dictionary) }
7
-
8
- describe '#relevant_l33t_substitutions' do
9
- it 'returns relevant l33t substitutions' do
10
- expect(matcher.relevent_l33t_subtable('p@ssw1rd24')).to eq(
11
- {'a' => ['4', '@'], 'i' => ['1'], 'l' => ['1'], 'z' => ['2']}
12
- )
13
- end
14
- end
15
-
16
- describe 'possible l33t substitutions' do
17
- context 'with 2 possible substitutions' do
18
- it 'returns the correct possible substitutions' do
19
- substitutions = {'a' => ['@'], 'i' => ['1']}
20
- expect(matcher.l33t_subs(substitutions)).to match_array([
21
- {'@' => 'a', '1' => 'i'}
22
- ])
23
- end
24
-
25
- it 'returns the correct possible substitutions with multiple options' do
26
- substitutions = {'a' => ['@', '4'], 'i' => ['1']}
27
- expect(matcher.l33t_subs(substitutions)).to match_array([
28
- {'@' => 'a', '1' => 'i'},
29
- {'4' => 'a', '1' => 'i'}
30
- ])
31
- end
32
- end
33
-
34
- context 'with 3 possible substitutions' do
35
- it 'returns the correct possible substitutions' do
36
- substitutions = {'a' => ['@'], 'i' => ['1'], 'z' => ['3']}
37
- expect(matcher.l33t_subs(substitutions)).to match_array([
38
- {'@' => 'a', '1' => 'i', '3' => 'z'}
39
- ])
40
- end
41
- end
42
-
43
- context 'with 4 possible substitutions' do
44
- it 'returns the correct possible substitutions' do
45
- substitutions = {'a' => ['@'], 'i' => ['1'], 'z' => ['3'], 'b' => ['8']}
46
- expect(matcher.l33t_subs(substitutions)).to match_array([
47
- {'@' => 'a', '1' => 'i', '3' => 'z', '8' => 'b'}
48
- ])
49
- end
50
- end
51
- end
52
-
53
- describe '#matches' do
54
- subject(:matches) { matcher.matches('p@ssword') }
55
-
56
- it "doesn't find 'password' because it's not in english.txt" do
57
- expect(matches.map(&:matched_word)).not_to include "password"
58
- end
59
-
60
- it 'finds the correct matches' do
61
- expect(matches.map(&:matched_word)).to match_array([
62
- 'pas',
63
- 'a',
64
- 'as',
65
- 'ass'
66
- ])
67
- end
68
-
69
- it 'sets the token correctly on those matches' do
70
- expect(matches.map(&:token)).to match_array([
71
- 'p@s',
72
- '@',
73
- '@s',
74
- '@ss'
75
- ])
76
- end
77
-
78
- it 'sets the substituions used' do
79
- expect(matches.map(&:sub)).to match_array([
80
- {'@' => 'a'},
81
- {'@' => 'a'},
82
- {'@' => 'a'},
83
- {'@' => 'a'}
84
- ])
85
- end
86
- end
87
- end
@@ -1,18 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Repeat do
4
- let(:matcher) { subject }
5
- let(:matches) { matcher.matches('bbbbbtestingaaa') }
6
-
7
- it 'sets the pattern name' do
8
- expect(matches.all? { |m| m.pattern == 'repeat' }).to eql(true)
9
- end
10
-
11
- it 'finds the repeated patterns' do
12
- expect(matches.count).to eq 2
13
- expect(matches[0].token).to eq 'bbbbb'
14
- expect(matches[0].repeated_char).to eq 'b'
15
- expect(matches[1].token).to eq 'aaa'
16
- expect(matches[1].repeated_char).to eq 'a'
17
- end
18
- end
@@ -1,21 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Sequences do
4
- let(:matcher) { subject }
5
- let(:matches) { matcher.matches('abcde87654') }
6
-
7
- it 'sets the pattern name' do
8
- expect(matches.all? { |m| m.pattern == 'sequence' }).to eql(true)
9
- end
10
-
11
- it 'finds the correct matches' do
12
- expect(matches.count).to eq(2)
13
- expect(matches[0].token).to eq 'abcde'
14
- expect(matches[1].token).to eq '87654'
15
- end
16
-
17
- it 'finds overlapping matches' do
18
- matches = matcher.matches('abcba')
19
- expect(matches.map(&:token)).to eq ['abc', 'cba']
20
- end
21
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Spatial do
4
- let(:matcher) { Zxcvbn::Matchers::Spatial.new(graphs) }
5
- let(:graphs) { Zxcvbn::Data.new.adjacency_graphs }
6
-
7
- describe '#matches' do
8
- let(:matches) { matcher.matches('rtyikm') }
9
-
10
- it 'finds the correct of matches' do
11
- expect(matches.count).to eq 3
12
- expect(matches[0].token).to eq 'rty'
13
- expect(matches[0].graph).to eq 'qwerty'
14
- expect(matches[1].token).to eq 'ikm'
15
- expect(matches[1].graph).to eq 'qwerty'
16
- expect(matches[2].token).to eq 'yik'
17
- expect(matches[2].graph).to eq 'dvorak'
18
- end
19
- end
20
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Matchers::Year do
4
- let(:matcher) { subject }
5
- let(:matches) { matcher.matches('testing1998') }
6
-
7
- it 'sets the pattern name' do
8
- expect(matches.all? { |m| m.pattern == 'year' }).to eql(true)
9
- end
10
-
11
- it 'finds the correct matches' do
12
- expect(matches.count).to eq(1)
13
- expect(matches[0].token).to eq '1998'
14
- end
15
- end
@@ -1,24 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Omnimatch do
4
- before(:all) do
5
- @omnimatch = described_class.new(Zxcvbn::Data.new)
6
- end
7
-
8
- def omnimatch(password)
9
- @omnimatch.matches(password)
10
- end
11
-
12
- def js_omnimatch(password)
13
- run_js(%'omnimatch("#{password}")')
14
- end
15
-
16
- TEST_PASSWORDS.each do |password|
17
- it "gives back the same results for #{password}" do
18
- js_results = js_omnimatch(password)
19
- ruby_results = omnimatch(password)
20
-
21
- expect(ruby_results).to match_js_results js_results
22
- end
23
- end
24
- end
data/spec/scorer_spec.rb DELETED
@@ -1,5 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::Scorer do
4
-
5
- end
@@ -1,106 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Zxcvbn::CrackTime do
4
- include Zxcvbn::CrackTime
5
-
6
- describe '#entropy_to_crack_time' do
7
- specify do
8
- expect(entropy_to_crack_time(15.433976574415976)).to eq 2.2134000000000014
9
- end
10
- end
11
-
12
- describe '#crack_time_to_score' do
13
- context 'crack time less than 10 to the power 2' do
14
- it 'returns 0' do
15
- expect(crack_time_to_score(90)).to eq 0
16
- end
17
- end
18
-
19
- context 'crack time in between 10**2 and 10**4' do
20
- it 'returns 1' do
21
- expect(crack_time_to_score(5000)).to eq 1
22
- end
23
- end
24
-
25
- context 'crack time in between 10**4 and 10**6' do
26
- it 'returns 2' do
27
- expect(crack_time_to_score(500_000)).to eq 2
28
- end
29
- end
30
-
31
- context 'crack time in between 10**6 and 10**8' do
32
- it 'returns 3' do
33
- expect(crack_time_to_score(50_000_000)).to eq 3
34
- end
35
- end
36
-
37
- context 'crack time above 10**8' do
38
- it 'returns 4' do
39
- expect(crack_time_to_score(110_000_000)).to eq 4
40
- end
41
- end
42
- end
43
-
44
- describe '#display_time' do
45
- let(:minute_to_seconds) { 60 }
46
- let(:hour_to_seconds) { minute_to_seconds * 60 }
47
- let(:day_to_seconds) { hour_to_seconds * 24 }
48
- let(:month_to_seconds) { day_to_seconds * 31 }
49
- let(:year_to_seconds) { month_to_seconds * 12 }
50
- let(:century_to_seconds) { year_to_seconds * 100 }
51
-
52
- context 'when less than a minute' do
53
- it 'should return instant' do
54
- [0, minute_to_seconds - 1].each do |seconds|
55
- expect(display_time(seconds)).to eql 'instant'
56
- end
57
- end
58
- end
59
-
60
- context 'when less than an hour' do
61
- it 'should return a readable time in minutes' do
62
- [60, (hour_to_seconds - 1)].each do |seconds|
63
- expect(display_time(seconds)).to match(/[0-9]+ minutes$/)
64
- end
65
- end
66
- end
67
-
68
- context 'when less than a day' do
69
- it 'should return a readable time in hours' do
70
- [hour_to_seconds, (day_to_seconds - 1)].each do |seconds|
71
- expect(display_time(seconds)).to match(/[0-9]+ hours$/)
72
- end
73
- end
74
- end
75
-
76
- context 'when less than 31 days' do
77
- it 'should return a readable time in days' do
78
- [day_to_seconds, month_to_seconds - 1].each do |seconds|
79
- expect(display_time(seconds)).to match(/[0-9]+ days$/)
80
- end
81
- end
82
- end
83
-
84
- context 'when less than 1 year' do
85
- it 'should return a readable time in days' do
86
- [month_to_seconds, (year_to_seconds - 1)].each do |seconds|
87
- expect(display_time(seconds)).to match(/[0-9]+ months$/)
88
- end
89
- end
90
- end
91
-
92
- context 'when less than a century' do
93
- it 'should return a readable time in days' do
94
- [year_to_seconds, (century_to_seconds - 1)].each do |seconds|
95
- expect(display_time(seconds)).to match(/[0-9]+ years$/)
96
- end
97
- end
98
- end
99
-
100
- context 'when a century or more' do
101
- it 'should return centuries' do
102
- expect(display_time(century_to_seconds)).to eql 'centuries'
103
- end
104
- end
105
- end
106
- end