suture 0.5.0 → 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 +4 -4
- data/.travis.yml +3 -2
- data/CHANGELOG.md +22 -1
- data/README.md +192 -4
- data/Rakefile +13 -1
- data/lib/suture/adapter/log.rb +1 -1
- data/lib/suture/comparator.rb +47 -1
- data/lib/suture/error/invalid_test_plan.rb +7 -0
- data/lib/suture/error/result_mismatch.rb +1 -2
- data/lib/suture/error/verification_failed.rb +7 -5
- data/lib/suture/util/numbers.rb +7 -0
- data/lib/suture/value/result.rb +2 -0
- data/lib/suture/verify/tests_patient.rb +8 -0
- data/lib/suture/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65850d2b933384f85c0cd13ec67fe92efcb08320
|
4
|
+
data.tar.gz: ba005e2f0e87b693f89948102559dfccfba7720b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7132a9cfa0499d89c786c7ccea1c7ed3da896ec786d3249b1aa3d00433eb0387d3be8917e3bb589f917f888624ab4bab71dc3c2f751a599a100422c09b717f2f
|
7
|
+
data.tar.gz: cd7f1fea872d8887a51f8b65d03cd5bff5189d9d4032141c0862c02265aec1c2acd4552e24e77e611fbb10e57ebd62796d2a956edf754c6dcde57df43438f0ff
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,28 @@
|
|
2
2
|
|
3
3
|
## [Unreleased](https://github.com/testdouble/suture/tree/HEAD)
|
4
4
|
|
5
|
-
[Full Changelog](https://github.com/testdouble/suture/compare/v0.
|
5
|
+
[Full Changelog](https://github.com/testdouble/suture/compare/v0.4.0...HEAD)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- API to delete a seam's recordings from the database [\#32](https://github.com/testdouble/suture/issues/32)
|
10
|
+
|
11
|
+
**Closed issues:**
|
12
|
+
|
13
|
+
- Justification for building a custom Docker image instead of using the canonical Ruby one [\#57](https://github.com/testdouble/suture/issues/57)
|
14
|
+
- staging/prod: dup arguments [\#56](https://github.com/testdouble/suture/issues/56)
|
15
|
+
- Add progress bar [\#54](https://github.com/testdouble/suture/issues/54)
|
16
|
+
- warn if no calls are found for the provided seam name [\#51](https://github.com/testdouble/suture/issues/51)
|
17
|
+
- Log out an error every time a suture raises [\#50](https://github.com/testdouble/suture/issues/50)
|
18
|
+
- Validate test plans [\#28](https://github.com/testdouble/suture/issues/28)
|
19
|
+
- Support permitted error types [\#24](https://github.com/testdouble/suture/issues/24)
|
20
|
+
|
21
|
+
**Merged pull requests:**
|
22
|
+
|
23
|
+
- Remove an unnecessary space \[ci skip\] [\#52](https://github.com/testdouble/suture/pull/52) ([JuanitoFatas](https://github.com/JuanitoFatas))
|
24
|
+
|
25
|
+
## [v0.4.0](https://github.com/testdouble/suture/tree/v0.4.0) (2016-08-29)
|
26
|
+
[Full Changelog](https://github.com/testdouble/suture/compare/v0.3.3...v0.4.0)
|
6
27
|
|
7
28
|
**Closed issues:**
|
8
29
|
|
data/README.md
CHANGED
@@ -262,7 +262,7 @@ unit tests around new units that shook out from the activity. Having good tests
|
|
262
262
|
for well-factored code is the best guard against seeing it slip once again into
|
263
263
|
poorly-understood "legacy" code.
|
264
264
|
|
265
|
-
##
|
265
|
+
## Staging
|
266
266
|
|
267
267
|
Once you've changed the code, you still may not be confident enough to delete it
|
268
268
|
entirely. It's possible (even likely) that your local exploratory testing didn't
|
@@ -292,7 +292,7 @@ implementations, and will raise an error if they don't return the same value.
|
|
292
292
|
Obviously, this setting is only helpful if the paths don't trigger major or
|
293
293
|
destructive side effects.
|
294
294
|
|
295
|
-
##
|
295
|
+
## Production
|
296
296
|
|
297
297
|
You're _almost_ ready to delete the old code path and switch production over to
|
298
298
|
the new one, but fear lingers: maybe there's an edge case your testing to this
|
@@ -408,11 +408,155 @@ where you call Suture, like `Suture.create(:foo, { :comparator => my_thing })`
|
|
408
408
|
|
409
409
|
#### Suture.create
|
410
410
|
|
411
|
-
|
411
|
+
`Suture.create(name, [options hash])`
|
412
|
+
|
413
|
+
* _name_ (Required) - a unique name for the seam, by which any recordings will be
|
414
|
+
identified. This should match the name used for any calls to `Suture.verify` by
|
415
|
+
your automated tests
|
416
|
+
|
417
|
+
* _old_ - (Required) - something that responds to `call` for the provided `args`
|
418
|
+
of the seam and either is the legacy code path (e.g.
|
419
|
+
`OldCode.new.method(:old_path)`) or invokes it (inside an anonymous Proc or
|
420
|
+
lambda)
|
421
|
+
|
422
|
+
* _args_ - (Required) - an array of arguments to be passed to the `old` or `new`
|
423
|
+
|
424
|
+
* _new_ - like old, but either references or invokes the code path designed to
|
425
|
+
replace the `old` legacy code path. When set, Suture will default to invoking
|
426
|
+
the `new` path at the exclusion of the `old` path (unless a mode flag like
|
427
|
+
`record_calls`, `call_both`, or `fallback_on_error` suggests differently)
|
428
|
+
|
429
|
+
* _database_path_ - (Default: `"db/suture.sqlite3"`) - a path relative to the
|
430
|
+
current working directory to the Sqlite3 database Suture uses to record and
|
431
|
+
playback calls
|
432
|
+
|
433
|
+
* _record_calls_ - (Default: false) - when set to true, the `old` path is called
|
434
|
+
(regardless of whether `new` is set) and its arguments and result (be it a return
|
435
|
+
value or an expected raised error) is recorded into the Suture database for the
|
436
|
+
purpose of more coverage for calls to `Suture.verify`. [Read
|
437
|
+
more](#3-record-the-current-behavior)
|
438
|
+
|
439
|
+
* _call_both_ - (Default: false) - when set to true, the `new` path is invoked,
|
440
|
+
then the `old` path is invoked, each with the seam's `args`. The return value
|
441
|
+
from each is compared with the `comparator`, and if they are not equivalent, then
|
442
|
+
a `Suture::Error::ResultMismatch` is raised. Intended after the `new` path is
|
443
|
+
initially developed and to be run in pre-production environments. [Read
|
444
|
+
more](#staging)
|
445
|
+
|
446
|
+
* _fallback_on_error_ - (Default: false) - designed to be run in production after
|
447
|
+
the initial development of the new code path, when set to true, Suture will
|
448
|
+
invoke the `new` code path. If `new` raises an error that isn't an
|
449
|
+
`expected_error_type`, then Suture will invoke the `old` path with the same args
|
450
|
+
in an attempt to recover a working state for the user. [Read more](#production)
|
451
|
+
|
452
|
+
* _raise_on_result_mismatch_ - (Default: true) - when set to true, the
|
453
|
+
`call_both` mode will merely log incidents of result mismatches, as opposed to
|
454
|
+
raising `Suture::Error::ResultMismatch`.
|
455
|
+
|
456
|
+
* _comparator_ - (Default: `Suture::Comparator.new`) - determines how return
|
457
|
+
values from the Suture are compared when invoking `Suture.verify` or when
|
458
|
+
`call_both` mode is activated. By default, results will be considered equivalent
|
459
|
+
if `==` returns true or if they `Marshal.dump` to the same string. If this
|
460
|
+
default isn't appropriate for the return value of your seam, [read
|
461
|
+
on](#creating-a-custom-comparator)
|
462
|
+
|
463
|
+
* _expected_error_types_ - (Default: `[]`) - if the seam is expected to raise
|
464
|
+
certain types of errors, don't consider them to be exceptional cases. For
|
465
|
+
example, if your `:widget` seam is known to raise `WidgetError` objects in
|
466
|
+
certain cases, setting `:expected_error_types => [WidgetError]` will result in:
|
467
|
+
* `Suture.create` will record expected errors when `record_calls` is enabled
|
468
|
+
* `Suture.verify` will compare recorded and actual raised errors that are
|
469
|
+
`kind_of?` any recorded error type (regardless of whether `Suture.verify` is
|
470
|
+
passed a redundant list of `expected_error_types`)
|
471
|
+
* `Suture.create`, when `fallback_on_error` is enabled, will allow expected
|
472
|
+
errors raised by the `new` path to propogate, as opposed to logging &
|
473
|
+
rescuing them before calling the `old` path as a fallback
|
474
|
+
* Additionally, `Suture.verify` can be passed `expected_error_types` to squelch
|
475
|
+
warning logs that result from unexpectedly raised errors
|
476
|
+
|
477
|
+
* _disable_ - (Default: false) - when enabled, Suture will attempt to revert to
|
478
|
+
the original behavior of the `old` path and take no special action. Useful in
|
479
|
+
cases where a bug is discovered in a deployed environment and you simply want
|
480
|
+
to hit the brakes on any new code path experiments by setting
|
481
|
+
`SUTURE_DISABLE=true` globally
|
482
|
+
|
483
|
+
* _dup_args_ - (Default: false) - when enabled, Suture will call `dup` on each
|
484
|
+
of the args passed to the `old` and/or `new` code paths. Useful when the code
|
485
|
+
path(s) mutate the arguments in such a way as to prevent `call_both` or
|
486
|
+
`fallback_on_error` from being effective
|
487
|
+
|
488
|
+
* _after_new_ - a `call`-able hook that runs after `new` is invoked. If `new`
|
489
|
+
raises an error, it is not invoked
|
490
|
+
|
491
|
+
* _after_old_ - a `call`-able hook that runs after `old` is invoked. If `old`
|
492
|
+
raises an error, it is not invoked
|
493
|
+
|
494
|
+
* _on_new_error_ - a `call`-able hook that is invoked after `new` raises an
|
495
|
+
unexpected error (see `expected_error_types`).
|
496
|
+
|
497
|
+
* _on_old_error_ - a `call`-able hook that is invoked after `old` raises an
|
498
|
+
unexpected error (see `expected_error_types`).
|
412
499
|
|
413
500
|
#### Suture.verify
|
414
501
|
|
415
|
-
|
502
|
+
Many of the settings for `Suture.verify` are analogous to the same settings in
|
503
|
+
`Suture.create` and are generally expected to be configured in the same way, as
|
504
|
+
if symmetrically with the `Suture.create` call of the seam under test:
|
505
|
+
|
506
|
+
* _name_ - (Required) - should be the same name as a seam for which some number
|
507
|
+
of recorded calls exist
|
508
|
+
|
509
|
+
* _subject_ - (Required) - a `call`-able that will be invoked with each recorded
|
510
|
+
set of `args` and have its result compared to that of each recording. This is
|
511
|
+
used in lieu of `old` or `new`, since the subject of a `Suture.verify` test might
|
512
|
+
be either (or neither!)
|
513
|
+
|
514
|
+
* _verify_only_ - (Default: nil) - when set to an ID, Suture.verify` will only
|
515
|
+
run against recorded calls for the matching ID. This option is meant to be used
|
516
|
+
to focus work on resolving a single verification failure
|
517
|
+
|
518
|
+
* _fail_fast_ - (Default: false) - `Suture.verify` will, by default, run against
|
519
|
+
every single recording, aggregating and reporting on all errors (just like, say,
|
520
|
+
RSpec or Minitest would). However, if the seam is slow to invoke or if you
|
521
|
+
confidently expect all of the recordings to pass verification, `fail_fast` is an
|
522
|
+
appropriate option to set.
|
523
|
+
|
524
|
+
* _call_limit_ - (Default: nil) - when set to a number, Suture will only verify
|
525
|
+
up to the set number of recorded calls. Because Suture randomizes the order of
|
526
|
+
verifications by default, you can see this as setting Suture.verify to sample a
|
527
|
+
random smattering of `call_limit` recordings as a smell test. Potentially useful
|
528
|
+
when a seam is very slow
|
529
|
+
|
530
|
+
* _time_limit_ - (Default: nil) - when set to a number (in seconds), Suture will
|
531
|
+
stop running verifications against recordings once `time_limit` seconds has
|
532
|
+
elapsed. Useful when a seam is very slow to invoke
|
533
|
+
|
534
|
+
* _error_message_limit_ - (Default: nil) - when set to a number, Suture will only
|
535
|
+
print up to `error_message_limit` failure messages. That way, if you currently
|
536
|
+
have hundreds of verifications failing, your console isn't overwhelmed by them on
|
537
|
+
each run of `Suture.verify`
|
538
|
+
|
539
|
+
* _random_seed_ - (Default: it's random!) - a randomized seed used to shuffle
|
540
|
+
the recordings before verifying them against the `subject` code path. If set to
|
541
|
+
`nil`, the recordings will be invoked in insertion-order. If set to a specific
|
542
|
+
number, that number will be used as the random seed (useful when re-running a
|
543
|
+
particular verification failure that can't be reproduced otherwise)
|
544
|
+
|
545
|
+
* _comparator_ - (Default: `Suture::Comparator`) - If a custom comparator is used
|
546
|
+
by the seam in `Suture.create`, then the same comparator should probably be
|
547
|
+
used by `Suture.verify` to ensure the results are comparable. [Read
|
548
|
+
more](#creating-a-custom-comparator) on creating custom comparators
|
549
|
+
)
|
550
|
+
|
551
|
+
* _database_path_ - (Default: `"db/suture.sqlite3"`) - as with `Suture.create`, a
|
552
|
+
custom database path can be set for almost any invocation of Suture, and
|
553
|
+
`Suture.verify is no exception`
|
554
|
+
|
555
|
+
* _after_subject_ - a `call`-able hook that runs after `subject` is invoked. If
|
556
|
+
`subject` raises an error, it is not invoked
|
557
|
+
|
558
|
+
* _on_new_subject_ - a `call`-able hook that is invoked after `subject` raises an
|
559
|
+
unexpected error (see `expected_error_types`)
|
416
560
|
|
417
561
|
### Creating a custom comparator
|
418
562
|
|
@@ -472,6 +616,50 @@ Suture.verify(:my_type, {
|
|
472
616
|
})
|
473
617
|
```
|
474
618
|
|
619
|
+
#### Comparing two ActiveRecord objects
|
620
|
+
|
621
|
+
Let's face it, a massive proportion of legacy Ruby code in the wild involves
|
622
|
+
ActiveRecord objects to some extent, and it's important that Suture be equipped
|
623
|
+
to compare them gracefully. If Suture's default comparator (`Suture::Comparator`)
|
624
|
+
detects two ActiveRecord model instances being compared, it will behave
|
625
|
+
differently, by this logic:
|
626
|
+
|
627
|
+
1. Instead of comparing the objects with `==` (which returns true so long as the
|
628
|
+
`id` attribute matdhes), Suture will compare the objects' `attributes` hashes
|
629
|
+
instead
|
630
|
+
2. The built-in `updated_at` and `created_at` will typically differ when code
|
631
|
+
is executed at different times and are usually not meaningful to application
|
632
|
+
logic, Suture will ignore these attributes by default
|
633
|
+
|
634
|
+
Other attributes may or may not matter (for instance, other timestamp fields,
|
635
|
+
or the `id` of the object), in those cases, you can instantiate the comparator
|
636
|
+
yourself and tell it which attributes to exclude, like so:
|
637
|
+
|
638
|
+
``` ruby
|
639
|
+
Suture.verify :thing,
|
640
|
+
:subject => Thing.new.method(:stuff),
|
641
|
+
:comparator => Suture::Comparator.new(
|
642
|
+
:active_record_excluded_attributes => [
|
643
|
+
:id,
|
644
|
+
:quality,
|
645
|
+
:created_at,
|
646
|
+
:updated_at
|
647
|
+
]
|
648
|
+
)
|
649
|
+
```
|
650
|
+
|
651
|
+
If `Thing#stuff` returns an instance of an ActiveRecord model, the four
|
652
|
+
attributes listed above will be ignored when comparing with recorded results.
|
653
|
+
|
654
|
+
In all of the above cases, `:comparator` can be set on both `Suture.create` and
|
655
|
+
`Suture.verify` and typically ought to be symmetrical for most seams.
|
656
|
+
|
657
|
+
## Examples
|
658
|
+
|
659
|
+
This repository contains these examples available for your perusal:
|
660
|
+
|
661
|
+
* [A Rails app of the Gilded Rose kata](example/rails_app)
|
662
|
+
|
475
663
|
## Troubleshooting
|
476
664
|
|
477
665
|
Some ideas if you can't get a particular verification to work or if you keep
|
data/Rakefile
CHANGED
@@ -26,6 +26,18 @@ Rake::TestTask.new(:test) do |t|
|
|
26
26
|
]
|
27
27
|
end
|
28
28
|
|
29
|
+
task :example do
|
30
|
+
Dir.chdir("example/rails_app") do
|
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
|
+
|
29
41
|
if Gem.ruby_version >= Gem::Version.new("2.2.2")
|
30
42
|
require 'github_changelog_generator/task'
|
31
43
|
GitHubChangelogGenerator::RakeTask.new :changelog
|
@@ -39,4 +51,4 @@ if Gem.ruby_version >= Gem::Version.new("2.2.2")
|
|
39
51
|
end
|
40
52
|
|
41
53
|
|
42
|
-
task :default => :test
|
54
|
+
task :default => [:test, :example]
|
data/lib/suture/adapter/log.rb
CHANGED
data/lib/suture/comparator.rb
CHANGED
@@ -1,7 +1,53 @@
|
|
1
1
|
module Suture
|
2
2
|
class Comparator
|
3
|
+
DEFAULT_ACTIVE_RECORD_EXCLUDED_ATTRIBUTES = [:updated_at, :created_at]
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@options = {
|
7
|
+
:active_record_excluded_attributes => (
|
8
|
+
options[:active_record_excluded_attributes] ||
|
9
|
+
DEFAULT_ACTIVE_RECORD_EXCLUDED_ATTRIBUTES
|
10
|
+
).map(&:to_s)
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
3
14
|
def call(recorded, actual)
|
4
|
-
recorded
|
15
|
+
is_equalivalent?(recorded, actual) ||
|
16
|
+
Marshal.dump(recorded) == Marshal.dump(actual)
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"#{self.class}.new(#{@options.inspect})"
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def compare_active_record(recorded, actual)
|
26
|
+
actual.kind_of?(recorded.class) &&
|
27
|
+
without_excluded_attrs(recorded.attributes) ==
|
28
|
+
without_excluded_attrs(actual.attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def without_excluded_attrs(hash)
|
34
|
+
hash.reject do |k, v|
|
35
|
+
@options[:active_record_excluded_attributes].include?(k.to_s)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_equalivalent?(recorded, actual)
|
40
|
+
if is_active_record?(recorded, actual)
|
41
|
+
compare_active_record(recorded, actual)
|
42
|
+
else
|
43
|
+
recorded == actual
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def is_active_record?(recorded, actual)
|
48
|
+
defined?(ActiveRecord::Base) &&
|
49
|
+
recorded.kind_of?(ActiveRecord::Base) &&
|
50
|
+
actual.kind_of?(ActiveRecord::Base)
|
5
51
|
end
|
6
52
|
end
|
7
53
|
end
|
@@ -7,7 +7,7 @@ module Suture::Error
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def message
|
10
|
-
|
10
|
+
<<-MSG.gsub(/^ {8}/,'')
|
11
11
|
The results from the old & new code paths did not match for the seam
|
12
12
|
#{@plan.name.inspect} and Suture is raising this error because the `:call_both`
|
13
13
|
option is enabled, because both code paths are expected to return the
|
@@ -52,7 +52,6 @@ module Suture::Error
|
|
52
52
|
too disruptive and logging is sufficient for monitoring results, you may
|
53
53
|
disable this error by setting `:raise_on_result_mismatch` to false.
|
54
54
|
MSG
|
55
|
-
|
56
55
|
end
|
57
56
|
end
|
58
57
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "suture/adapter/progress_bar"
|
2
|
+
require "suture/util/numbers"
|
2
3
|
|
3
4
|
module Suture::Error
|
4
5
|
class VerificationFailed < StandardError
|
@@ -47,6 +48,7 @@ module Suture::Error
|
|
47
48
|
results.passed.size,
|
48
49
|
results.all.size
|
49
50
|
)
|
51
|
+
percent = Suture::Util::Numbers.percent(results.passed.size, results.all.size)
|
50
52
|
<<-MSG.gsub(/^ {8}/,'')
|
51
53
|
## Progress
|
52
54
|
|
@@ -54,7 +56,7 @@ module Suture::Error
|
|
54
56
|
|
55
57
|
#{bar}
|
56
58
|
|
57
|
-
Of #{results.all.size} recorded interactions, #{results.passed.size} are currently passing.
|
59
|
+
Of #{results.all.size} recorded interactions, #{results.passed.size} are currently passing. That's #{percent}%!
|
58
60
|
MSG
|
59
61
|
end
|
60
62
|
|
@@ -66,13 +68,13 @@ module Suture::Error
|
|
66
68
|
|
67
69
|
```
|
68
70
|
{
|
69
|
-
:comparator => #{describe_comparator(plan.comparator)}
|
70
71
|
:database_path => #{plan.database_path.inspect},
|
71
72
|
:fail_fast => #{plan.fail_fast},
|
72
73
|
:call_limit => #{plan.call_limit.inspect},#{" # (no limit)" if plan.call_limit.nil?}
|
73
74
|
:time_limit => #{plan.time_limit.inspect},#{plan.time_limit.nil? ? " # (no limit)" : " # (in seconds)"}
|
74
75
|
:error_message_limit => #{plan.error_message_limit.inspect},#{" # (no limit)" if plan.error_message_limit.nil?}
|
75
|
-
:random_seed => #{plan.random_seed.inspect}
|
76
|
+
:random_seed => #{plan.random_seed.inspect},#{" # (insertion order)" if plan.random_seed.nil?}
|
77
|
+
:comparator => #{describe_comparator(plan.comparator)}
|
76
78
|
}
|
77
79
|
```
|
78
80
|
MSG
|
@@ -80,9 +82,9 @@ module Suture::Error
|
|
80
82
|
|
81
83
|
def describe_comparator(comparator)
|
82
84
|
if comparator.kind_of?(Proc)
|
83
|
-
"Proc
|
85
|
+
"Proc # (in: `#{describe_source_location(*comparator.source_location)}`)"
|
84
86
|
elsif comparator.respond_to?(:method) && comparator.method(:call)
|
85
|
-
"#{comparator.
|
87
|
+
"#{comparator.inspect}.new, # (in: `#{describe_source_location(*comparator.method(:call).source_location)}`)"
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
data/lib/suture/value/result.rb
CHANGED
@@ -4,6 +4,7 @@ require "suture/adapter/dictaphone"
|
|
4
4
|
require "suture/value/test_results"
|
5
5
|
require "suture/util/shuffle"
|
6
6
|
require "suture/util/timer"
|
7
|
+
require "suture/error/invalid_test_plan"
|
7
8
|
require "backports/1.9.2/random"
|
8
9
|
|
9
10
|
module Suture
|
@@ -15,6 +16,7 @@ module Suture
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def test(test_plan)
|
19
|
+
validate_test_plan!(test_plan)
|
18
20
|
experienced_failure_in_life = false
|
19
21
|
timer = Suture::Util::Timer.new(test_plan.time_limit) unless test_plan.time_limit.nil?
|
20
22
|
test_cases = build_test_cases(test_plan)
|
@@ -35,6 +37,12 @@ module Suture
|
|
35
37
|
|
36
38
|
private
|
37
39
|
|
40
|
+
def validate_test_plan!(test_plan)
|
41
|
+
if !test_plan.subject || !test_plan.subject.respond_to?(:call)
|
42
|
+
raise Suture::Error::InvalidTestPlan.new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
def should_skip?(test_plan, failed_fast, call_count, timer)
|
39
47
|
(test_plan.fail_fast && failed_fast) ||
|
40
48
|
(test_plan.call_limit && call_count >= test_plan.call_limit) ||
|
data/lib/suture/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: suture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sqlite3
|
@@ -197,6 +197,7 @@ files:
|
|
197
197
|
- lib/suture/create/validates_plan.rb
|
198
198
|
- lib/suture/delete.rb
|
199
199
|
- lib/suture/error/invalid_plan.rb
|
200
|
+
- lib/suture/error/invalid_test_plan.rb
|
200
201
|
- lib/suture/error/observation_conflict.rb
|
201
202
|
- lib/suture/error/result_mismatch.rb
|
202
203
|
- lib/suture/error/schema_version.rb
|
@@ -208,6 +209,7 @@ files:
|
|
208
209
|
- lib/suture/surgeon/remediator.rb
|
209
210
|
- lib/suture/util/compares_results.rb
|
210
211
|
- lib/suture/util/env.rb
|
212
|
+
- lib/suture/util/numbers.rb
|
211
213
|
- lib/suture/util/scalpel.rb
|
212
214
|
- lib/suture/util/shuffle.rb
|
213
215
|
- lib/suture/util/timer.rb
|