suture 1.1.1 → 1.2.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/main.yml +31 -0
- data/.gitignore +1 -1
- data/.standard.yml +7 -0
- data/CHANGELOG.md +32 -3
- data/Gemfile +9 -1
- data/Gemfile.lock +120 -0
- data/README.md +38 -25
- data/Rakefile +15 -48
- data/bin/console +0 -4
- data/lib/suture/adapter/dictaphone.rb +1 -2
- data/lib/suture/comparator.rb +4 -4
- data/lib/suture/create/builds_plan.rb +6 -6
- data/lib/suture/create/chooses_surgeon.rb +1 -1
- data/lib/suture/create/validates_plan.rb +10 -10
- data/lib/suture/error/invalid_plan.rb +6 -6
- data/lib/suture/error/observation_conflict.rb +1 -1
- data/lib/suture/error/result_mismatch.rb +1 -1
- data/lib/suture/error/schema_version.rb +1 -1
- data/lib/suture/error/verification_failed.rb +11 -13
- data/lib/suture/reset.rb +0 -1
- data/lib/suture/surgeon/auditor.rb +5 -7
- data/lib/suture/surgeon/no_op.rb +1 -1
- data/lib/suture/surgeon/observer.rb +2 -3
- data/lib/suture/surgeon/remediator.rb +6 -8
- data/lib/suture/util/compares_results.rb +1 -1
- data/lib/suture/util/env.rb +5 -5
- data/lib/suture/util/scalpel.rb +5 -6
- data/lib/suture/util/shuffle.rb +1 -1
- data/lib/suture/value/observation.rb +1 -1
- data/lib/suture/value/plan.rb +4 -4
- data/lib/suture/value/result.rb +1 -1
- data/lib/suture/value/test_plan.rb +12 -12
- data/lib/suture/value/test_results.rb +0 -1
- data/lib/suture/verify/administers_test.rb +2 -2
- data/lib/suture/verify/interprets_results.rb +0 -2
- data/lib/suture/verify/prescribes_test_plan.rb +5 -5
- data/lib/suture/verify/tests_patient.rb +2 -3
- data/lib/suture/verify.rb +0 -1
- data/lib/suture/version.rb +1 -1
- data/lib/suture/wrap/logger.rb +35 -15
- data/lib/suture/wrap/sqlite.rb +2 -2
- data/lib/suture.rb +0 -1
- data/suture.gemspec +14 -27
- metadata +8 -108
- data/.travis.yml +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1326f7c00beb85b3516536b4a7c04783360dde2a15af83be7434201a112967b6
|
|
4
|
+
data.tar.gz: e099889a2efeccbafe0ef83733bd9b3488b6ec7c6e2eed43d2e640a09c0f0650
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f198879578e76762c39a27ee395efbff86038f1f6c746ded31f46436761db14053d7f4a7c09abb327c6d28f822fdfb2cdbbeb4da6f1f30912f568fd480c36a5e
|
|
7
|
+
data.tar.gz: 4d8ddf4805fbe995f7c5a45cc1e64649f70c64e441127c2b2d9b0f2dccec9b8009529e9a49f6348e2ef94c0a23d71a9a3bae178d66bdf33401295284cab12eff
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Ruby
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
name: Ruby ${{ matrix.ruby }}
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
ruby:
|
|
17
|
+
- '3.2'
|
|
18
|
+
- '3.3'
|
|
19
|
+
- '3.4'
|
|
20
|
+
- '4.0'
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- name: Set up Ruby
|
|
25
|
+
uses: ruby/setup-ruby@v1
|
|
26
|
+
with:
|
|
27
|
+
ruby-version: ${{ matrix.ruby }}
|
|
28
|
+
bundler-cache: true
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: bundle exec rake
|
|
31
|
+
|
data/.gitignore
CHANGED
data/.standard.yml
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [v1.2.0](https://github.com/testdouble/suture/tree/v1.2.0) (2026-09-18)
|
|
4
|
+
[Full Changelog](https://github.com/testdouble/suture/compare/v1.1.2...v1.2.0)
|
|
5
|
+
|
|
6
|
+
**Implemented enhancements:**
|
|
7
|
+
|
|
8
|
+
- Add support for Ruby 3.4 and 4.0, including fixes for missing stdlib gem dependencies
|
|
9
|
+
|
|
10
|
+
## [v1.1.2](https://github.com/testdouble/suture/tree/v1.1.2) (2018-11-12)
|
|
11
|
+
[Full Changelog](https://github.com/testdouble/suture/compare/v1.1.1...v1.1.2)
|
|
12
|
+
|
|
13
|
+
**Closed issues:**
|
|
14
|
+
|
|
15
|
+
- task to explode tests from recorded suture data? [\#69](https://github.com/testdouble/suture/issues/69)
|
|
16
|
+
|
|
17
|
+
**Merged pull requests:**
|
|
18
|
+
|
|
19
|
+
- Standardize [\#71](https://github.com/testdouble/suture/pull/71) ([searls](https://github.com/searls))
|
|
20
|
+
- Fix couple typos in README.md [\#70](https://github.com/testdouble/suture/pull/70) ([sharipov-ru](https://github.com/sharipov-ru))
|
|
21
|
+
- Make minor sentence changes to the README [\#66](https://github.com/testdouble/suture/pull/66) ([alexcameron89](https://github.com/alexcameron89))
|
|
22
|
+
- Add a Docker image [\#58](https://github.com/testdouble/suture/pull/58) ([seeflanigan](https://github.com/seeflanigan))
|
|
23
|
+
|
|
24
|
+
## [v1.1.1](https://github.com/testdouble/suture/tree/v1.1.1) (2016-09-19)
|
|
25
|
+
[Full Changelog](https://github.com/testdouble/suture/compare/v1.1.0...v1.1.1)
|
|
26
|
+
|
|
27
|
+
**Closed issues:**
|
|
28
|
+
|
|
29
|
+
- call\_both: if raise\_on\_result\_mismatch is false and return\_old\_on\_result\_mismatch is true, rescue errors from :new path [\#64](https://github.com/testdouble/suture/issues/64)
|
|
30
|
+
|
|
31
|
+
**Merged pull requests:**
|
|
32
|
+
|
|
33
|
+
- Allow graceful fallback by call\_both when new code path raises [\#65](https://github.com/testdouble/suture/pull/65) ([searls](https://github.com/searls))
|
|
34
|
+
|
|
3
35
|
## [v1.1.0](https://github.com/testdouble/suture/tree/v1.1.0) (2016-09-18)
|
|
4
36
|
[Full Changelog](https://github.com/testdouble/suture/compare/v1.0.0...v1.1.0)
|
|
5
37
|
|
|
@@ -111,6 +143,3 @@
|
|
|
111
143
|
- Create/Initialize a sqlite database [\#2](https://github.com/testdouble/suture/issues/2)
|
|
112
144
|
- Create a new Suture [\#1](https://github.com/testdouble/suture/issues/1)
|
|
113
145
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
suture (1.2.0)
|
|
5
|
+
backports
|
|
6
|
+
bar-of-progress (>= 0.1.3)
|
|
7
|
+
bigdecimal
|
|
8
|
+
sqlite3
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: https://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
ast (2.4.2)
|
|
14
|
+
attr_extras (7.1.0)
|
|
15
|
+
backports (3.24.1)
|
|
16
|
+
bar-of-progress (0.1.3)
|
|
17
|
+
base64 (0.1.1)
|
|
18
|
+
bigdecimal (4.1.3)
|
|
19
|
+
concurrent-ruby (1.3.8)
|
|
20
|
+
diff-lcs (1.5.0)
|
|
21
|
+
erb (6.0.7)
|
|
22
|
+
gimme (0.5.0)
|
|
23
|
+
io-console (0.9.4)
|
|
24
|
+
irb (1.18.0)
|
|
25
|
+
pp (>= 0.6.0)
|
|
26
|
+
prism (>= 1.3.0)
|
|
27
|
+
rdoc (>= 4.0.0)
|
|
28
|
+
reline (>= 0.4.2)
|
|
29
|
+
json (2.6.3)
|
|
30
|
+
language_server-protocol (3.17.0.3)
|
|
31
|
+
lint_roller (1.1.0)
|
|
32
|
+
logger (1.7.0)
|
|
33
|
+
optimist (3.1.0)
|
|
34
|
+
ostruct (0.6.3)
|
|
35
|
+
parallel (1.23.0)
|
|
36
|
+
parser (3.2.2.3)
|
|
37
|
+
ast (~> 2.4.1)
|
|
38
|
+
racc
|
|
39
|
+
patience_diff (1.2.0)
|
|
40
|
+
optimist (~> 3.0)
|
|
41
|
+
pp (0.6.4)
|
|
42
|
+
prettyprint
|
|
43
|
+
prettyprint (0.2.0)
|
|
44
|
+
prism (1.9.0)
|
|
45
|
+
racc (1.7.1)
|
|
46
|
+
rainbow (3.1.1)
|
|
47
|
+
rake (13.0.6)
|
|
48
|
+
rbs (4.1.3)
|
|
49
|
+
logger
|
|
50
|
+
prism (>= 1.6.0)
|
|
51
|
+
tsort
|
|
52
|
+
rdoc (8.0.0)
|
|
53
|
+
erb
|
|
54
|
+
prism (>= 1.6.0)
|
|
55
|
+
rbs (>= 4.0.0)
|
|
56
|
+
tsort
|
|
57
|
+
regexp_parser (2.8.1)
|
|
58
|
+
reline (0.7.0)
|
|
59
|
+
io-console (~> 0.5)
|
|
60
|
+
rexml (3.4.4)
|
|
61
|
+
rubocop (1.56.4)
|
|
62
|
+
base64 (~> 0.1.1)
|
|
63
|
+
json (~> 2.3)
|
|
64
|
+
language_server-protocol (>= 3.17.0)
|
|
65
|
+
parallel (~> 1.10)
|
|
66
|
+
parser (>= 3.2.2.3)
|
|
67
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
68
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
69
|
+
rexml (>= 3.2.5, < 4.0)
|
|
70
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
|
71
|
+
ruby-progressbar (~> 1.7)
|
|
72
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
73
|
+
rubocop-ast (1.29.0)
|
|
74
|
+
parser (>= 3.2.1.0)
|
|
75
|
+
rubocop-performance (1.19.1)
|
|
76
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
77
|
+
rubocop-ast (>= 0.4.0)
|
|
78
|
+
ruby-progressbar (1.13.0)
|
|
79
|
+
sqlite3 (2.9.6-arm64-darwin)
|
|
80
|
+
sqlite3 (2.9.6-x86_64-linux-gnu)
|
|
81
|
+
standard (1.31.1)
|
|
82
|
+
language_server-protocol (~> 3.17.0.2)
|
|
83
|
+
lint_roller (~> 1.0)
|
|
84
|
+
rubocop (~> 1.56.2)
|
|
85
|
+
standard-custom (~> 1.0.0)
|
|
86
|
+
standard-performance (~> 1.2)
|
|
87
|
+
standard-custom (1.0.2)
|
|
88
|
+
lint_roller (~> 1.0)
|
|
89
|
+
rubocop (~> 1.50)
|
|
90
|
+
standard-performance (1.2.0)
|
|
91
|
+
lint_roller (~> 1.1)
|
|
92
|
+
rubocop-performance (~> 1.19.0)
|
|
93
|
+
super_diff (0.10.0)
|
|
94
|
+
attr_extras (>= 6.2.4)
|
|
95
|
+
diff-lcs
|
|
96
|
+
patience_diff
|
|
97
|
+
tldr (0.6.0)
|
|
98
|
+
concurrent-ruby (~> 1.2)
|
|
99
|
+
super_diff (~> 0.10)
|
|
100
|
+
tsort (0.2.0)
|
|
101
|
+
unicode-display_width (2.4.2)
|
|
102
|
+
|
|
103
|
+
PLATFORMS
|
|
104
|
+
arm64-darwin-22
|
|
105
|
+
arm64-darwin-24
|
|
106
|
+
arm64-darwin-25
|
|
107
|
+
x86_64-linux
|
|
108
|
+
|
|
109
|
+
DEPENDENCIES
|
|
110
|
+
gimme
|
|
111
|
+
irb
|
|
112
|
+
logger
|
|
113
|
+
ostruct
|
|
114
|
+
rake
|
|
115
|
+
standard
|
|
116
|
+
suture!
|
|
117
|
+
tldr
|
|
118
|
+
|
|
119
|
+
BUNDLED WITH
|
|
120
|
+
4.0.20
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Suture 🏥
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/testdouble/suture) [](https://codeclimate.com/github/testdouble/suture) [](https://codeclimate.com/github/testdouble/suture/coverage)
|
|
4
4
|
|
|
5
5
|
A refactoring tool for Ruby, designed to make it safe to change code you don't
|
|
6
6
|
confidently understand. In fact, changing untrustworthy code is so fraught,
|
|
@@ -9,11 +9,21 @@ Suture hopes to make it safer to completely reimplement a code path.
|
|
|
9
9
|
Suture provides help to the entire lifecycle of refactoring poorly-understood
|
|
10
10
|
code, from local development, to a staging environment, and even in production.
|
|
11
11
|
|
|
12
|
+
# Video
|
|
13
|
+
|
|
14
|
+
Suture was unveiled at Ruby Kaigi 2016 as one approach that can make
|
|
15
|
+
refactors less scary and more predictable. You can watch the 45 minute screencast
|
|
16
|
+
here:
|
|
17
|
+
|
|
18
|
+
[<img width="803" alt="screen shot 2016-09-20 at 9 44 43 am" src="https://cloud.githubusercontent.com/assets/79303/18653743/e669d304-7f16-11e6-84e7-c86b8f88132c.png" alt="A presentation on Suture">](http://blog.testdouble.com/posts/2016-09-16-surgical-refactors-with-suture.html)
|
|
19
|
+
|
|
20
|
+
# Walk-through guide
|
|
21
|
+
|
|
12
22
|
Refactoring or reimplementing important code is an involved process! Instead of
|
|
13
23
|
listing out Suture's API without sufficient exposition, here is an example that
|
|
14
|
-
|
|
24
|
+
will take you through each stage of the lifecycle.
|
|
15
25
|
|
|
16
|
-
##
|
|
26
|
+
## Development
|
|
17
27
|
|
|
18
28
|
Suppose you have a really nasty worker method:
|
|
19
29
|
|
|
@@ -58,9 +68,12 @@ class LegacyWorker
|
|
|
58
68
|
end
|
|
59
69
|
```
|
|
60
70
|
|
|
61
|
-
As you can see, the call to `MyMailer.send` is left at the original call site
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
As you can see, the call to `MyMailer.send` is left at the original call site.
|
|
72
|
+
`MyMailer.send` is effectively a void method being invoked for its side effect,
|
|
73
|
+
which would make it difficult to test. By creating `LegacyWorker#call`, we can
|
|
74
|
+
now express the work more clearly in terms of repeatable inputs (`id`) and
|
|
75
|
+
outputs (`thing.result`), which will help us verify that our refactor is working
|
|
76
|
+
later.
|
|
64
77
|
|
|
65
78
|
Since any changes to the code while it's untested are very dangerous, it's
|
|
66
79
|
important to minimize changes made for the sake of creating a clear seam.
|
|
@@ -89,10 +102,10 @@ LegacyWorker without taking any other meaningful action.
|
|
|
89
102
|
|
|
90
103
|
### 3. Record the current behavior
|
|
91
104
|
|
|
92
|
-
Next, we want to start observing how the legacy worker is actually called
|
|
93
|
-
arguments are sent to it and what
|
|
94
|
-
as we use our app locally, we can later
|
|
95
|
-
implementations behave the same way.
|
|
105
|
+
Next, we want to start observing how the legacy worker is actually called. What
|
|
106
|
+
arguments are being sent to it and what value does it returns (or, what error
|
|
107
|
+
does it raise)? By recording the calls as we use our app locally, we can later
|
|
108
|
+
test that the old and new implementations behave the same way.
|
|
96
109
|
|
|
97
110
|
First, we tell Suture to start recording calls by setting the environment
|
|
98
111
|
variable `SUTURE_RECORD_CALLS` to something truthy (e.g.
|
|
@@ -101,8 +114,8 @@ any calls to our seam will record the arguments passed to the legacy code path
|
|
|
101
114
|
and the return value.
|
|
102
115
|
|
|
103
116
|
As you use the application (whether it's a queue system, a web app, or a CLI),
|
|
104
|
-
the calls will be saved to a sqlite database.
|
|
105
|
-
external data sources or services,
|
|
117
|
+
the calls will be saved to a sqlite database. Keep in mind that if the legacy code
|
|
118
|
+
path relies on external data sources or services, your recorded inputs and
|
|
106
119
|
outputs will rely on them as well. You may want to narrow the scope of your
|
|
107
120
|
seam accordingly (e.g. to receive an object as an argument instead of a database
|
|
108
121
|
id).
|
|
@@ -146,7 +159,7 @@ expected value. It's a good idea to run this against the legacy code first,
|
|
|
146
159
|
for two reasons:
|
|
147
160
|
|
|
148
161
|
* running the characterization tests against the legacy code path will ensure
|
|
149
|
-
the test environment has the data needed to behave the same way as when it was
|
|
162
|
+
that the test environment has the data needed to behave the same way as when it was
|
|
150
163
|
recorded (it may be appropriate to take a snapshot of the database before you
|
|
151
164
|
start recording and load it before you run your tests)
|
|
152
165
|
|
|
@@ -158,13 +171,13 @@ start recording and load it before you run your tests)
|
|
|
158
171
|
subordinate to it) to make sure our characterization test sufficiently
|
|
159
172
|
exercises it
|
|
160
173
|
* identify incidental coverage of code paths that are outside the scope of
|
|
161
|
-
what we hope to refactor
|
|
174
|
+
what we hope to refactor. This will help to see if `LegacyWorker` has
|
|
162
175
|
side effects we didn't anticipate and should additionally write tests for
|
|
163
176
|
|
|
164
177
|
### 5. Specify and test a path for new code
|
|
165
178
|
|
|
166
|
-
Once
|
|
167
|
-
can start work on a `NewWorker`. To get started, we
|
|
179
|
+
Once the automated characterization test of our recordings is passing, then we
|
|
180
|
+
can start work on a `NewWorker`. To get started, we update our Suture
|
|
168
181
|
configuration:
|
|
169
182
|
|
|
170
183
|
``` ruby
|
|
@@ -214,7 +227,7 @@ end
|
|
|
214
227
|
```
|
|
215
228
|
|
|
216
229
|
Obviously, this should fail until `NewWorker`'s implementation covers all the
|
|
217
|
-
cases we recorded from `LegacyWorker`.
|
|
230
|
+
cases that we recorded from `LegacyWorker`.
|
|
218
231
|
|
|
219
232
|
Remember, characterization tests aren't designed to be kept around forever. Once
|
|
220
233
|
you're confident that the new implementation is sufficient, it's typically better
|
|
@@ -225,21 +238,21 @@ implementation and its component parts.
|
|
|
225
238
|
|
|
226
239
|
This step is the hardest part and there's not much Suture can do to make it
|
|
227
240
|
any easier. How you go about implementing your improvements depends on whether
|
|
228
|
-
you intend to rewrite the legacy code path or refactor it. Some
|
|
229
|
-
approach
|
|
241
|
+
you intend to rewrite the legacy code path or refactor it. Some comments on each
|
|
242
|
+
approach follow:
|
|
230
243
|
|
|
231
244
|
#### Reimplementing
|
|
232
245
|
|
|
233
246
|
The best time to rewrite a piece of software is when you have a better
|
|
234
|
-
understanding of the real-world process it models than the original authors did
|
|
247
|
+
understanding of the real-world process that it models than the original authors did
|
|
235
248
|
when they first wrote it. If that's the case, it's likely you'll think of more
|
|
236
249
|
reliable names and abstractions than they did.
|
|
237
250
|
|
|
238
251
|
As for workflow, consider writing the new implementation like you would any other
|
|
239
|
-
new part of the system
|
|
252
|
+
new part of the system. The added benefit is being able to run the
|
|
240
253
|
characterization tests as a progress indicator and a backstop for any missed edge
|
|
241
254
|
cases. The ultimate goal of this workflow should be to incrementally arrive at a
|
|
242
|
-
clean design that completely passes the characterization test run by
|
|
255
|
+
clean design that completely passes the characterization test run by running
|
|
243
256
|
`Suture.verify`.
|
|
244
257
|
|
|
245
258
|
#### Refactoring
|
|
@@ -323,7 +336,7 @@ Suture.config({
|
|
|
323
336
|
```
|
|
324
337
|
|
|
325
338
|
When your new code path raises an error with the above settings, it will
|
|
326
|
-
|
|
339
|
+
propagate and log the error to the specified file.
|
|
327
340
|
|
|
328
341
|
### Custom error handlers
|
|
329
342
|
|
|
@@ -478,7 +491,7 @@ certain cases, setting `:expected_error_types => [WidgetError]` will result in:
|
|
|
478
491
|
`kind_of?` any recorded error type (regardless of whether `Suture.verify` is
|
|
479
492
|
passed a redundant list of `expected_error_types`)
|
|
480
493
|
* `Suture.create`, when `fallback_on_error` is enabled, will allow expected
|
|
481
|
-
errors raised by the `new` path to
|
|
494
|
+
errors raised by the `new` path to propagate, as opposed to logging &
|
|
482
495
|
rescuing them before calling the `old` path as a fallback
|
|
483
496
|
|
|
484
497
|
* _disable_ - (Default: `false`) - when enabled, Suture will attempt to revert to
|
|
@@ -641,7 +654,7 @@ detects two ActiveRecord model instances being compared, it will behave
|
|
|
641
654
|
differently, by this logic:
|
|
642
655
|
|
|
643
656
|
1. Instead of comparing the objects with `==` (which returns true so long as the
|
|
644
|
-
`id` attribute
|
|
657
|
+
`id` attribute matches), Suture will compare the objects' `attributes` hashes
|
|
645
658
|
instead
|
|
646
659
|
2. The built-in `updated_at` and `created_at` will typically differ when code
|
|
647
660
|
is executed at different times and are usually not meaningful to application
|
data/Rakefile
CHANGED
|
@@ -1,54 +1,21 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
2
|
require "rake/testtask"
|
|
3
|
+
require "tldr/rake"
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
t.libs << "test"
|
|
6
|
-
t.libs << "lib"
|
|
7
|
-
t.test_files = FileList['test/helper.rb', 'test/**/*_test.rb']
|
|
8
|
-
end
|
|
5
|
+
TLDR::Task.new(:name => :unit)
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
TLDR::Task.new(:name => :safe, :config => TLDR::Config.new(
|
|
8
|
+
:parallel => false,
|
|
9
|
+
:load_paths => ["safe", "lib"],
|
|
10
|
+
:helper_paths => ["safe/helper.rb"],
|
|
11
|
+
:paths => FileList["safe/**/*_test.rb"]
|
|
12
|
+
))
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'safe/support/code_climate',
|
|
22
|
-
'test/helper.rb',
|
|
23
|
-
'test/**/*_test.rb',
|
|
24
|
-
'safe/helper.rb',
|
|
25
|
-
'safe/**/*_test.rb'
|
|
26
|
-
]
|
|
27
|
-
end
|
|
14
|
+
TLDR::Task.new(:name => :test, :config => TLDR::Config.new(
|
|
15
|
+
:load_paths => ["safe", "test", "lib"],
|
|
16
|
+
:helper_paths => ["test/helper.rb", "safe/helper.rb"],
|
|
17
|
+
:paths => FileList["test/**/*_test.rb", "safe/**/*_test.rb"]
|
|
18
|
+
))
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
passed = system <<-SH
|
|
32
|
-
BUNDLE_GEMFILE="$PWD/Gemfile" bundle install --quiet
|
|
33
|
-
BUNDLE_GEMFILE="$PWD/Gemfile" bundle exec rake suture
|
|
34
|
-
SH
|
|
35
|
-
if !passed
|
|
36
|
-
raise StandardError.new("Rails example failed!")
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
if Gem.ruby_version >= Gem::Version.new("2.2.2")
|
|
42
|
-
require 'github_changelog_generator/task'
|
|
43
|
-
GitHubChangelogGenerator::RakeTask.new :changelog
|
|
44
|
-
task :changelog_commit do
|
|
45
|
-
require "suture"
|
|
46
|
-
cmd = "git commit -m \"Changelog for #{Suture::VERSION}\" -- CHANGELOG.md"
|
|
47
|
-
puts "-------> #{cmd}"
|
|
48
|
-
system cmd
|
|
49
|
-
end
|
|
50
|
-
Rake::Task["release:rubygem_push"].enhance([:changelog, :changelog_commit])
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
task :default => [:test, :example]
|
|
20
|
+
require "standard/rake"
|
|
21
|
+
task :default => [:test, :"standard:fix"]
|
data/bin/console
CHANGED
|
@@ -6,9 +6,5 @@ require "suture"
|
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
|
8
8
|
|
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
-
# require "pry"
|
|
11
|
-
# Pry.start
|
|
12
|
-
|
|
13
9
|
require "irb"
|
|
14
10
|
IRB.start
|
|
@@ -19,7 +19,6 @@ module Suture::Adapter
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
def record(returned_value)
|
|
24
23
|
record_result(Suture::Value::Result.returned(returned_value))
|
|
25
24
|
end
|
|
@@ -48,7 +47,7 @@ module Suture::Adapter
|
|
|
48
47
|
Suture::Wrap::Sqlite.delete(@db, :observations, "where name = ?", [name.to_s])
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
private
|
|
52
51
|
|
|
53
52
|
def record_result(result)
|
|
54
53
|
Suture::Wrap::Sqlite.insert(
|
data/lib/suture/comparator.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Suture
|
|
|
23
23
|
protected
|
|
24
24
|
|
|
25
25
|
def compare_active_record(recorded, actual)
|
|
26
|
-
actual.
|
|
26
|
+
actual.is_a?(recorded.class) &&
|
|
27
27
|
without_excluded_attrs(recorded.attributes) ==
|
|
28
28
|
without_excluded_attrs(actual.attributes)
|
|
29
29
|
end
|
|
@@ -31,7 +31,7 @@ module Suture
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
33
|
def without_excluded_attrs(hash)
|
|
34
|
-
hash.reject do |k,
|
|
34
|
+
hash.reject do |k, _v|
|
|
35
35
|
@options[:active_record_excluded_attributes].include?(k.to_s)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -46,8 +46,8 @@ module Suture
|
|
|
46
46
|
|
|
47
47
|
def is_active_record?(recorded, actual)
|
|
48
48
|
defined?(ActiveRecord::Base) &&
|
|
49
|
-
recorded.
|
|
50
|
-
actual.
|
|
49
|
+
recorded.is_a?(ActiveRecord::Base) &&
|
|
50
|
+
actual.is_a?(ActiveRecord::Base)
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -4,15 +4,15 @@ require "suture/util/env"
|
|
|
4
4
|
module Suture
|
|
5
5
|
class BuildsPlan
|
|
6
6
|
UN_ENV_IABLE_OPTIONS = [:name, :old, :new, :args, :comparator, :after_new,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
:after_old, :on_new_error, :on_old_error,
|
|
8
|
+
:expected_error_types]
|
|
9
9
|
|
|
10
10
|
def build(name, options = {})
|
|
11
11
|
Value::Plan.new(
|
|
12
|
-
Suture.config
|
|
13
|
-
merge(options)
|
|
14
|
-
merge(:name => name)
|
|
15
|
-
merge(Suture::Util::Env.to_map(UN_ENV_IABLE_OPTIONS))
|
|
12
|
+
Suture.config
|
|
13
|
+
.merge(options)
|
|
14
|
+
.merge(:name => name)
|
|
15
|
+
.merge(Suture::Util::Env.to_map(UN_ENV_IABLE_OPTIONS))
|
|
16
16
|
)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -12,7 +12,7 @@ module Suture
|
|
|
12
12
|
return Surgeon::NoOp.new if plan.disable
|
|
13
13
|
if plan.record_calls
|
|
14
14
|
if plan.new
|
|
15
|
-
log_warn <<-MSG.gsub(/^ {12}/,
|
|
15
|
+
log_warn <<-MSG.gsub(/^ {12}/, "")
|
|
16
16
|
Seam #{plan.name.inspect} has a :new code path defined, but because
|
|
17
17
|
it is set to :record_calls, we will invoke the :old code path
|
|
18
18
|
instead. If this is not what you intend, set :record_calls to false.
|
|
@@ -13,10 +13,10 @@ module Suture
|
|
|
13
13
|
:test => lambda { |name| name.to_s.size < 256 },
|
|
14
14
|
:message => "must be less than 256 characters"
|
|
15
15
|
},
|
|
16
|
-
:old => CALLABLE_VALIDATION =
|
|
16
|
+
:old => CALLABLE_VALIDATION = {
|
|
17
17
|
:test => lambda { |old| old.respond_to?(:call) },
|
|
18
18
|
:message => "must respond to `call` (e.g. `dog.method(:bark)` or `->(*args){ dog.bark(*args) }`)"
|
|
19
|
-
}
|
|
19
|
+
},
|
|
20
20
|
:new => CALLABLE_VALIDATION,
|
|
21
21
|
:comparator => CALLABLE_VALIDATION.merge(
|
|
22
22
|
:message => "must respond to `call` (e.g. `MyComparator.new` or `->(recorded, actual) { recorded == actual }`)"
|
|
@@ -26,7 +26,7 @@ module Suture
|
|
|
26
26
|
CONFLICTS = [
|
|
27
27
|
lambda { |plan|
|
|
28
28
|
if plan.record_calls && !plan.database_path
|
|
29
|
-
<<-MSG.gsub(/^ {12}/,
|
|
29
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
30
30
|
:record_calls is enabled, but :database_path is nil, so Suture
|
|
31
31
|
doesn't know where to record calls to the seam.
|
|
32
32
|
MSG
|
|
@@ -34,7 +34,7 @@ module Suture
|
|
|
34
34
|
},
|
|
35
35
|
lambda { |plan|
|
|
36
36
|
if plan.record_calls && plan.call_both
|
|
37
|
-
<<-MSG.gsub(/^ {12}/,
|
|
37
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
38
38
|
:record_calls & :call_both are both enabled and conflict with one
|
|
39
39
|
another. :record_calls will only invoke the old code path (intended
|
|
40
40
|
for characterization of the old code path and initial development
|
|
@@ -51,7 +51,7 @@ module Suture
|
|
|
51
51
|
},
|
|
52
52
|
lambda { |plan|
|
|
53
53
|
if plan.record_calls && plan.fallback_on_error
|
|
54
|
-
<<-MSG.gsub(/^ {12}/,
|
|
54
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
55
55
|
:record_calls & :fallback_on_error are both enabled and conflict with
|
|
56
56
|
one another. :record_calls will only invoke the old code path
|
|
57
57
|
(intended for characterization of the old code path and initial
|
|
@@ -63,7 +63,7 @@ module Suture
|
|
|
63
63
|
},
|
|
64
64
|
lambda { |plan|
|
|
65
65
|
if plan.call_both && plan.fallback_on_error
|
|
66
|
-
<<-MSG.gsub(/^ {12}/,
|
|
66
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
67
67
|
:call_both & :fallback_on_error are both enabled and conflict with
|
|
68
68
|
one another. :call_both is designed for pre-production environments
|
|
69
69
|
and will call both the old and new code paths to compare their
|
|
@@ -75,7 +75,7 @@ module Suture
|
|
|
75
75
|
},
|
|
76
76
|
lambda { |plan|
|
|
77
77
|
if plan.call_both && !plan.new.respond_to?(:call)
|
|
78
|
-
<<-MSG.gsub(/^ {12}/,
|
|
78
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
79
79
|
:call_both is set but :new is either not set or is not callable. In
|
|
80
80
|
order to call both code paths, both :old and :new must be set and
|
|
81
81
|
callable
|
|
@@ -84,7 +84,7 @@ module Suture
|
|
|
84
84
|
},
|
|
85
85
|
lambda { |plan|
|
|
86
86
|
if plan.fallback_on_error && !plan.new.respond_to?(:call)
|
|
87
|
-
<<-MSG.gsub(/^ {12}/,
|
|
87
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
88
88
|
:fallback_on_error is set but :new is either not set or is not
|
|
89
89
|
callable. This mode is designed for after the :new code path has
|
|
90
90
|
been developed and run in production-like environments, where :old
|
|
@@ -96,7 +96,7 @@ module Suture
|
|
|
96
96
|
},
|
|
97
97
|
lambda { |plan|
|
|
98
98
|
if !plan.raise_on_result_mismatch && !plan.call_both
|
|
99
|
-
<<-MSG.gsub(/^ {12}/,
|
|
99
|
+
<<-MSG.gsub(/^ {12}/, "")
|
|
100
100
|
:raise_on_result_mismatch was disabled but :call_both is not enabled.
|
|
101
101
|
This option only applies to the :call_both mode, and will have no
|
|
102
102
|
impact when set for other modes
|
|
@@ -125,7 +125,7 @@ module Suture
|
|
|
125
125
|
|
|
126
126
|
def invalid_attrs(plan)
|
|
127
127
|
VALIDATIONS.select { |name, rule|
|
|
128
|
-
next unless attr = plan.send(name)
|
|
128
|
+
next unless (attr = plan.send(name))
|
|
129
129
|
!rule[:test].call(attr)
|
|
130
130
|
}
|
|
131
131
|
end
|