test_suite_time_machine 1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +224 -0
- data/CHANGELOG.md +3 -0
- data/LICENCE.txt +21 -0
- data/README.md +103 -0
- data/Rakefile +10 -0
- data/lib/test_suite_time_machine/version.rb +3 -0
- data/lib/test_suite_time_machine.rb +149 -0
- data/sig/test_suite_time_machine.rbs +4 -0
- data/test_suite_time_machine.gemspec +31 -0
- metadata +72 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e7327c01503b11ebf46af35ebc39484b6b2d39be94326279e7de5aab88716336
|
|
4
|
+
data.tar.gz: 8f8c2e0aaaebd345003f17db241fdb51f42efb7d08bc6ffcaebbe295e50fa167
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f50eabb434c67a34cacaab07453f08357f0c7509e3f2dc34b7b97e38bae2033d98d3f31119625b3ea14ea2e5546b7c84b40e61d5ec10ddff5cbb4ae41c2026d5
|
|
7
|
+
data.tar.gz: 2295cb61a6fc4ab7a8dd77c76680e5a59988123e22f3bbbe76d8f813364ee43c02b67546b6685e1f2c4fdeb44948804e667777c81de7339ef681db2dc4d34f6c
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.1
|
|
3
|
+
|
|
4
|
+
Style/StringLiterals:
|
|
5
|
+
Enabled: true
|
|
6
|
+
EnforcedStyle: double_quotes
|
|
7
|
+
|
|
8
|
+
Style/StringLiteralsInInterpolation:
|
|
9
|
+
Enabled: true
|
|
10
|
+
EnforcedStyle: double_quotes
|
|
11
|
+
|
|
12
|
+
Layout/LineLength:
|
|
13
|
+
Max: 120
|
|
14
|
+
|
|
15
|
+
# New
|
|
16
|
+
|
|
17
|
+
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
|
18
|
+
Enabled: true
|
|
19
|
+
Gemspec/DevelopmentDependencies: # new in 1.44
|
|
20
|
+
Enabled: true
|
|
21
|
+
Gemspec/RequireMFA: # new in 1.23
|
|
22
|
+
Enabled: true
|
|
23
|
+
Layout/LineContinuationLeadingSpace: # new in 1.31
|
|
24
|
+
Enabled: true
|
|
25
|
+
Layout/LineContinuationSpacing: # new in 1.31
|
|
26
|
+
Enabled: true
|
|
27
|
+
Layout/LineEndStringConcatenationIndentation: # new in 1.18
|
|
28
|
+
Enabled: true
|
|
29
|
+
Layout/SpaceBeforeBrackets: # new in 1.7
|
|
30
|
+
Enabled: true
|
|
31
|
+
Lint/AmbiguousAssignment: # new in 1.7
|
|
32
|
+
Enabled: true
|
|
33
|
+
Lint/AmbiguousOperatorPrecedence: # new in 1.21
|
|
34
|
+
Enabled: true
|
|
35
|
+
Lint/AmbiguousRange: # new in 1.19
|
|
36
|
+
Enabled: true
|
|
37
|
+
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
|
38
|
+
Enabled: true
|
|
39
|
+
Lint/DeprecatedConstants: # new in 1.8
|
|
40
|
+
Enabled: true
|
|
41
|
+
Lint/DuplicateBranch: # new in 1.3
|
|
42
|
+
Enabled: true
|
|
43
|
+
Lint/DuplicateMagicComment: # new in 1.37
|
|
44
|
+
Enabled: true
|
|
45
|
+
Lint/DuplicateMatchPattern: # new in 1.50
|
|
46
|
+
Enabled: true
|
|
47
|
+
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
|
|
48
|
+
Enabled: true
|
|
49
|
+
Lint/EmptyBlock: # new in 1.1
|
|
50
|
+
Enabled: true
|
|
51
|
+
Lint/EmptyClass: # new in 1.3
|
|
52
|
+
Enabled: true
|
|
53
|
+
Lint/EmptyInPattern: # new in 1.16
|
|
54
|
+
Enabled: true
|
|
55
|
+
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
|
|
56
|
+
Enabled: true
|
|
57
|
+
Lint/LambdaWithoutLiteralBlock: # new in 1.8
|
|
58
|
+
Enabled: true
|
|
59
|
+
Lint/MixedCaseRange: # new in 1.53
|
|
60
|
+
Enabled: true
|
|
61
|
+
Lint/NoReturnInBeginEndBlocks: # new in 1.2
|
|
62
|
+
Enabled: true
|
|
63
|
+
Lint/NonAtomicFileOperation: # new in 1.31
|
|
64
|
+
Enabled: true
|
|
65
|
+
Lint/NumberedParameterAssignment: # new in 1.9
|
|
66
|
+
Enabled: true
|
|
67
|
+
Lint/OrAssignmentToConstant: # new in 1.9
|
|
68
|
+
Enabled: true
|
|
69
|
+
Lint/RedundantDirGlobSort: # new in 1.8
|
|
70
|
+
Enabled: true
|
|
71
|
+
Lint/RedundantRegexpQuantifiers: # new in 1.53
|
|
72
|
+
Enabled: true
|
|
73
|
+
Lint/RefinementImportMethods: # new in 1.27
|
|
74
|
+
Enabled: true
|
|
75
|
+
Lint/RequireRangeParentheses: # new in 1.32
|
|
76
|
+
Enabled: true
|
|
77
|
+
Lint/RequireRelativeSelfPath: # new in 1.22
|
|
78
|
+
Enabled: true
|
|
79
|
+
Lint/SymbolConversion: # new in 1.9
|
|
80
|
+
Enabled: true
|
|
81
|
+
Lint/ToEnumArguments: # new in 1.1
|
|
82
|
+
Enabled: true
|
|
83
|
+
Lint/TripleQuotes: # new in 1.9
|
|
84
|
+
Enabled: true
|
|
85
|
+
Lint/UnexpectedBlockArity: # new in 1.5
|
|
86
|
+
Enabled: true
|
|
87
|
+
Lint/UnmodifiedReduceAccumulator: # new in 1.1
|
|
88
|
+
Enabled: true
|
|
89
|
+
Lint/UselessRescue: # new in 1.43
|
|
90
|
+
Enabled: true
|
|
91
|
+
Lint/UselessRuby2Keywords: # new in 1.23
|
|
92
|
+
Enabled: true
|
|
93
|
+
Metrics/CollectionLiteralLength: # new in 1.47
|
|
94
|
+
Enabled: true
|
|
95
|
+
Naming/BlockForwarding: # new in 1.24
|
|
96
|
+
Enabled: true
|
|
97
|
+
Security/CompoundHash: # new in 1.28
|
|
98
|
+
Enabled: true
|
|
99
|
+
Security/IoMethods: # new in 1.22
|
|
100
|
+
Enabled: true
|
|
101
|
+
Style/ArgumentsForwarding: # new in 1.1
|
|
102
|
+
Enabled: true
|
|
103
|
+
Style/ArrayIntersect: # new in 1.40
|
|
104
|
+
Enabled: true
|
|
105
|
+
Style/CollectionCompact: # new in 1.2
|
|
106
|
+
Enabled: true
|
|
107
|
+
Style/ComparableClamp: # new in 1.44
|
|
108
|
+
Enabled: true
|
|
109
|
+
Style/ConcatArrayLiterals: # new in 1.41
|
|
110
|
+
Enabled: true
|
|
111
|
+
Style/DataInheritance: # new in 1.49
|
|
112
|
+
Enabled: true
|
|
113
|
+
Style/DirEmpty: # new in 1.48
|
|
114
|
+
Enabled: true
|
|
115
|
+
Style/DocumentDynamicEvalDefinition: # new in 1.1
|
|
116
|
+
Enabled: true
|
|
117
|
+
Style/EmptyHeredoc: # new in 1.32
|
|
118
|
+
Enabled: true
|
|
119
|
+
Style/EndlessMethod: # new in 1.8
|
|
120
|
+
Enabled: true
|
|
121
|
+
Style/EnvHome: # new in 1.29
|
|
122
|
+
Enabled: true
|
|
123
|
+
Style/ExactRegexpMatch: # new in 1.51
|
|
124
|
+
Enabled: true
|
|
125
|
+
Style/FetchEnvVar: # new in 1.28
|
|
126
|
+
Enabled: true
|
|
127
|
+
Style/FileEmpty: # new in 1.48
|
|
128
|
+
Enabled: true
|
|
129
|
+
Style/FileRead: # new in 1.24
|
|
130
|
+
Enabled: true
|
|
131
|
+
Style/FileWrite: # new in 1.24
|
|
132
|
+
Enabled: true
|
|
133
|
+
Style/HashConversion: # new in 1.10
|
|
134
|
+
Enabled: true
|
|
135
|
+
Style/HashExcept: # new in 1.7
|
|
136
|
+
Enabled: true
|
|
137
|
+
Style/IfWithBooleanLiteralBranches: # new in 1.9
|
|
138
|
+
Enabled: true
|
|
139
|
+
Style/InPatternThen: # new in 1.16
|
|
140
|
+
Enabled: true
|
|
141
|
+
Style/MagicCommentFormat: # new in 1.35
|
|
142
|
+
Enabled: true
|
|
143
|
+
Style/MapCompactWithConditionalBlock: # new in 1.30
|
|
144
|
+
Enabled: true
|
|
145
|
+
Style/MapToHash: # new in 1.24
|
|
146
|
+
Enabled: true
|
|
147
|
+
Style/MapToSet: # new in 1.42
|
|
148
|
+
Enabled: true
|
|
149
|
+
Style/MinMaxComparison: # new in 1.42
|
|
150
|
+
Enabled: true
|
|
151
|
+
Style/MultilineInPatternThen: # new in 1.16
|
|
152
|
+
Enabled: true
|
|
153
|
+
Style/NegatedIfElseCondition: # new in 1.2
|
|
154
|
+
Enabled: true
|
|
155
|
+
Style/NestedFileDirname: # new in 1.26
|
|
156
|
+
Enabled: true
|
|
157
|
+
Style/NilLambda: # new in 1.3
|
|
158
|
+
Enabled: true
|
|
159
|
+
Style/NumberedParameters: # new in 1.22
|
|
160
|
+
Enabled: true
|
|
161
|
+
Style/NumberedParametersLimit: # new in 1.22
|
|
162
|
+
Enabled: true
|
|
163
|
+
Style/ObjectThen: # new in 1.28
|
|
164
|
+
Enabled: true
|
|
165
|
+
Style/OpenStructUse: # new in 1.23
|
|
166
|
+
Enabled: true
|
|
167
|
+
Style/OperatorMethodCall: # new in 1.37
|
|
168
|
+
Enabled: true
|
|
169
|
+
Style/QuotedSymbols: # new in 1.16
|
|
170
|
+
Enabled: true
|
|
171
|
+
Style/RedundantArgument: # new in 1.4
|
|
172
|
+
Enabled: true
|
|
173
|
+
Style/RedundantArrayConstructor: # new in 1.52
|
|
174
|
+
Enabled: true
|
|
175
|
+
Style/RedundantConstantBase: # new in 1.40
|
|
176
|
+
Enabled: true
|
|
177
|
+
Style/RedundantCurrentDirectoryInPath: # new in 1.53
|
|
178
|
+
Enabled: true
|
|
179
|
+
Style/RedundantDoubleSplatHashBraces: # new in 1.41
|
|
180
|
+
Enabled: true
|
|
181
|
+
Style/RedundantEach: # new in 1.38
|
|
182
|
+
Enabled: true
|
|
183
|
+
Style/RedundantFilterChain: # new in 1.52
|
|
184
|
+
Enabled: true
|
|
185
|
+
Style/RedundantHeredocDelimiterQuotes: # new in 1.45
|
|
186
|
+
Enabled: true
|
|
187
|
+
Style/RedundantInitialize: # new in 1.27
|
|
188
|
+
Enabled: true
|
|
189
|
+
Style/RedundantLineContinuation: # new in 1.49
|
|
190
|
+
Enabled: true
|
|
191
|
+
Style/RedundantRegexpArgument: # new in 1.53
|
|
192
|
+
Enabled: true
|
|
193
|
+
Style/RedundantRegexpConstructor: # new in 1.52
|
|
194
|
+
Enabled: true
|
|
195
|
+
Style/RedundantSelfAssignmentBranch: # new in 1.19
|
|
196
|
+
Enabled: true
|
|
197
|
+
Style/RedundantStringEscape: # new in 1.37
|
|
198
|
+
Enabled: true
|
|
199
|
+
Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
|
|
200
|
+
Enabled: true
|
|
201
|
+
Style/SelectByRegexp: # new in 1.22
|
|
202
|
+
Enabled: true
|
|
203
|
+
Style/StringChars: # new in 1.12
|
|
204
|
+
Enabled: true
|
|
205
|
+
Style/SwapValues: # new in 1.1
|
|
206
|
+
Enabled: true
|
|
207
|
+
Style/YAMLFileRead: # new in 1.53
|
|
208
|
+
Enabled: true
|
|
209
|
+
|
|
210
|
+
# Changed
|
|
211
|
+
|
|
212
|
+
Style/FrozenStringLiteralComment:
|
|
213
|
+
Enabled: false
|
|
214
|
+
Style/Documentation:
|
|
215
|
+
Enabled: false
|
|
216
|
+
Layout/CaseIndentation:
|
|
217
|
+
Enabled: false
|
|
218
|
+
Layout/EndAlignment:
|
|
219
|
+
Enabled: false
|
|
220
|
+
Metrics/BlockLength:
|
|
221
|
+
Exclude:
|
|
222
|
+
- spec/**/*
|
|
223
|
+
Metrics/MethodLength:
|
|
224
|
+
Max: 15
|
data/CHANGELOG.md
ADDED
data/LICENCE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT Licence (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Elliot Crosby-McCullough
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Test Suite Time Machine (TSTM)
|
|
2
|
+
|
|
3
|
+
This library operates on the principle that time is a variable like any other,
|
|
4
|
+
and should be controlled for in a test suite. It builds on top of Timecop to
|
|
5
|
+
provide an intuitive interface to set and manipulate time at different levels
|
|
6
|
+
of your test suite, whether to set a specific time for a single test, or to
|
|
7
|
+
pretend to run the entire suite on New Year's Day 2038.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
12
|
+
|
|
13
|
+
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
|
14
|
+
|
|
15
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
16
|
+
|
|
17
|
+
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Full suite
|
|
22
|
+
|
|
23
|
+
Use `TestSuiteTimeMachine.pretend_it_is(datetime)` to set and freeze the time for the entire test suite.
|
|
24
|
+
Usually this is done in your `rails_helper` or `spec_helper` file
|
|
25
|
+
immediately after your gems are loaded.
|
|
26
|
+
|
|
27
|
+
This is also your opportunity to pass in a specific date and time
|
|
28
|
+
if you want to run your suite on that specific date.
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
TestSuiteTimeMachine.pretend_it_is(ENV.fetch('TEST_DATE_AND_TIME', 'real_world'))
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The options are:
|
|
35
|
+
- `'real_world'` - the default, uses the real date and time
|
|
36
|
+
- `'n.days.from_now'` - e.g. `'1.day.from_now'`
|
|
37
|
+
- Any Ruby-parseable timestamp, usually ISO8601
|
|
38
|
+
|
|
39
|
+
TSTM will always return to this baseline after each test.
|
|
40
|
+
|
|
41
|
+
### Group-level
|
|
42
|
+
|
|
43
|
+
To set the date/time for a given group of tests, such as a `describe` block, or `context` block, use `TestSuiteTimeMachine.travel_permanently_to(...)` before the tests in question. This will move and freeze time as specified, and return to the baseline after the test has finished.
|
|
44
|
+
|
|
45
|
+
### Test-level
|
|
46
|
+
|
|
47
|
+
Once you're in the test itself, use the following methods to manipulate time as needed:
|
|
48
|
+
|
|
49
|
+
- `TestSuiteTimeMachine.advance` - move time forward by 1 second
|
|
50
|
+
- `TestSuiteTimeMachine.advance_time_by(seconds)` - move time forward by the specified number of seconds
|
|
51
|
+
- `TestSuiteTimeMachine.advance_time_to(datetime)` - move time forward to the specified datetime
|
|
52
|
+
|
|
53
|
+
You cannot use these methods to move time backwards; if you arbitrarily step backwards and forwards in a test, it confuses people.
|
|
54
|
+
|
|
55
|
+
If you need to move backwards in time e.g. to set up some records
|
|
56
|
+
created in the past, either use `travel_permanently_to` to set the
|
|
57
|
+
time for the entire test group, or use `travel_temporarily_to` to set the time for the duration of the given block.
|
|
58
|
+
|
|
59
|
+
### RSpec
|
|
60
|
+
|
|
61
|
+
If you're using RSpec, TSTM provides a set of helpers for clarity
|
|
62
|
+
and convenience, as well as reducing coupling between your tests
|
|
63
|
+
and this library.
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
RSpec.configure do |config|
|
|
67
|
+
config.include TestSuiteTimeMachine::RSpecHelpers
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This provides the following functionality:
|
|
72
|
+
- adds `set_time(...)` as an alias for `TestSuiteTimeMachine.travel_permanently_to(...)`
|
|
73
|
+
- adds `advance_time` as an alias for `TestSuiteTimeMachine.advance`
|
|
74
|
+
- adds `advance_time_by(seconds)` as an alias for `TestSuiteTimeMachine.advance_time_by(seconds)`
|
|
75
|
+
- adds `advance_time_to(datetime)` as an alias for `TestSuiteTimeMachine.advance_time_to(datetime)`
|
|
76
|
+
- adds `travel_temporarily_to(datetime)` as an alias for `TestSuiteTimeMachine.travel_temporarily_to(datetime)`
|
|
77
|
+
|
|
78
|
+
It also adds the RSpec tag `time` which is a succinct way of invoking
|
|
79
|
+
`travel_temporarily_to` for a given test.
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
RSpec.describe "Santa's schedule" do
|
|
83
|
+
context "when it Christmas Eve", time: '2023-12-24 10:00' do
|
|
84
|
+
it "is extremely busy" do
|
|
85
|
+
# ...
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
94
|
+
|
|
95
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
96
|
+
|
|
97
|
+
## Contributing
|
|
98
|
+
|
|
99
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/SmartCasual/test_suite_time_machine
|
|
100
|
+
|
|
101
|
+
## Licence
|
|
102
|
+
|
|
103
|
+
The gem is available as open source under the terms of the [MIT Licence](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require_relative "test_suite_time_machine/version"
|
|
2
|
+
require "timecop"
|
|
3
|
+
|
|
4
|
+
module TestSuiteTimeMachine
|
|
5
|
+
DAY = 60 * 60 * 24
|
|
6
|
+
|
|
7
|
+
def self.pretend_it_is(datetime)
|
|
8
|
+
if baseline
|
|
9
|
+
raise TimeTravelError, "TestSuiteTimeMachine.pretend_it_is cannot be called more than once per test run (currently set to `#{baseline}`, use `travel_temporarily_to` instead)." # rubocop:disable Layout/LineLength
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
datetime = "real_world" if datetime.nil? || datetime.strip.empty?
|
|
13
|
+
|
|
14
|
+
self.baseline = Timecop.baseline = case datetime
|
|
15
|
+
when "real_world"
|
|
16
|
+
now
|
|
17
|
+
when /\A(\d+).days.from_now\z/
|
|
18
|
+
days_from_now(::Regexp.last_match(1).to_i)
|
|
19
|
+
else
|
|
20
|
+
parse(datetime)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Timecop.safe_mode = false
|
|
24
|
+
Timecop.freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.travel_temporarily_to(*datetime, freeze: true, &block)
|
|
28
|
+
raise TimeTravelError, "TestSuiteTimeMachine.travel_temporarily_to requires a block" unless block_given?
|
|
29
|
+
|
|
30
|
+
if freeze
|
|
31
|
+
Timecop.freeze(*datetime, &block)
|
|
32
|
+
else
|
|
33
|
+
Timecop.travel(*datetime, &block)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.advance_time_to(datetime, **kwargs)
|
|
38
|
+
if parse(datetime) < now
|
|
39
|
+
raise TimeTravelError,
|
|
40
|
+
"TestSuiteTimeMachine.advance_time_to cannot be called with a date in the past (#{datetime})"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
travel_permanently_to(datetime, **kwargs)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.advance_time_by(duration, **kwargs)
|
|
47
|
+
advance_time_to(now + duration, **kwargs)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.advance
|
|
51
|
+
advance_time_by(1) # 1 second
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.travel_permanently_to(*datetime, freeze: true)
|
|
55
|
+
if freeze
|
|
56
|
+
Timecop.freeze(*datetime)
|
|
57
|
+
else
|
|
58
|
+
Timecop.travel(*datetime)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.reset
|
|
63
|
+
unless baseline # rubocop:disable Style/IfUnlessModifier
|
|
64
|
+
raise TimeTravelError, "a baseline time must be set first (#{baseline})"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Timecop.return_to_baseline
|
|
68
|
+
Timecop.freeze(baseline)
|
|
69
|
+
|
|
70
|
+
if now.to_i != baseline.to_i # rubocop:disable Style/GuardClause
|
|
71
|
+
raise TimeTravelError, "Time leak! Expected '#{now}' to be at baseline '#{baseline}' after a reset"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.revert_to_real_world_time
|
|
76
|
+
Timecop.return.tap do
|
|
77
|
+
Timecop.safe_mode = true
|
|
78
|
+
self.baseline = nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.unfreeze!
|
|
83
|
+
Timecop.travel(now)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.baseline
|
|
87
|
+
Thread.current[:tstm_baseline_set]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.baseline=(datetime)
|
|
91
|
+
Thread.current[:tstm_baseline_set] = datetime
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.now
|
|
95
|
+
if Time.respond_to?(:zone)
|
|
96
|
+
Time.zone.now
|
|
97
|
+
else
|
|
98
|
+
Time.now
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.parse(datetime)
|
|
103
|
+
return datetime unless datetime.is_a?(String)
|
|
104
|
+
|
|
105
|
+
if Time.respond_to?(:zone)
|
|
106
|
+
Time.zone.parse(datetime)
|
|
107
|
+
else
|
|
108
|
+
Time.parse(datetime)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.days_from_now(days)
|
|
113
|
+
if days.respond_to?(:days)
|
|
114
|
+
days.days.from_now
|
|
115
|
+
else
|
|
116
|
+
now + (days * DAY)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
module RSpecHelpers
|
|
121
|
+
def set_time(...)
|
|
122
|
+
TestSuiteTimeMachine.travel_permanently_to(...)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def advance_time
|
|
126
|
+
TestSuiteTimeMachine.advance
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def advance_time_by(...)
|
|
130
|
+
TestSuiteTimeMachine.advance_time_by(...)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def advance_time_to(...)
|
|
134
|
+
TestSuiteTimeMachine.advance_time_to(...)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def travel_temporarily_to(...)
|
|
138
|
+
TestSuiteTimeMachine.travel_temporarily_to(...)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.included(config)
|
|
142
|
+
config.before(:each, :time) do |example|
|
|
143
|
+
set_time(example.metadata[:time])
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class TimeTravelError < StandardError; end
|
|
149
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative "lib/test_suite_time_machine/version"
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "test_suite_time_machine"
|
|
5
|
+
spec.version = TestSuiteTimeMachine::VERSION
|
|
6
|
+
spec.authors = ["Elliot Crosby-McCullough"]
|
|
7
|
+
spec.email = ["elliot.cm@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = "A small utility to help manage the current date and time in your test suite."
|
|
10
|
+
spec.description = "Built atop Timecop, this gem provides a more intuitive interface for managing the current date and time across the test suite." # rubocop:disable Layout/LineLength
|
|
11
|
+
spec.homepage = "https://github.com/SmartCasual/test_suite_time_machine"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
14
|
+
|
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
16
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
17
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
18
|
+
|
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
21
|
+
spec.files = Dir.chdir(__dir__) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
23
|
+
(File.expand_path(f) == __FILE__) ||
|
|
24
|
+
f.start_with?(*%w[bin/ spec/ .git .github Gemfile])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
spec.add_dependency "timecop", "~> 0.9"
|
|
30
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: test_suite_time_machine
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Elliot Crosby-McCullough
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2023-07-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: timecop
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.9'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.9'
|
|
27
|
+
description: Built atop Timecop, this gem provides a more intuitive interface for
|
|
28
|
+
managing the current date and time across the test suite.
|
|
29
|
+
email:
|
|
30
|
+
- elliot.cm@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- ".rspec"
|
|
36
|
+
- ".rubocop.yml"
|
|
37
|
+
- CHANGELOG.md
|
|
38
|
+
- LICENCE.txt
|
|
39
|
+
- README.md
|
|
40
|
+
- Rakefile
|
|
41
|
+
- lib/test_suite_time_machine.rb
|
|
42
|
+
- lib/test_suite_time_machine/version.rb
|
|
43
|
+
- sig/test_suite_time_machine.rbs
|
|
44
|
+
- test_suite_time_machine.gemspec
|
|
45
|
+
homepage: https://github.com/SmartCasual/test_suite_time_machine
|
|
46
|
+
licenses:
|
|
47
|
+
- MIT
|
|
48
|
+
metadata:
|
|
49
|
+
homepage_uri: https://github.com/SmartCasual/test_suite_time_machine
|
|
50
|
+
source_code_uri: https://github.com/SmartCasual/test_suite_time_machine
|
|
51
|
+
changelog_uri: https://github.com/SmartCasual/test_suite_time_machine/blob/main/CHANGELOG.md
|
|
52
|
+
rubygems_mfa_required: 'true'
|
|
53
|
+
post_install_message:
|
|
54
|
+
rdoc_options: []
|
|
55
|
+
require_paths:
|
|
56
|
+
- lib
|
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 3.1.0
|
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '0'
|
|
67
|
+
requirements: []
|
|
68
|
+
rubygems_version: 3.4.17
|
|
69
|
+
signing_key:
|
|
70
|
+
specification_version: 4
|
|
71
|
+
summary: A small utility to help manage the current date and time in your test suite.
|
|
72
|
+
test_files: []
|