minitest-strict 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/CHANGELOG.md +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +156 -0
- data/lib/minitest/strict/version.rb +8 -0
- data/lib/minitest/strict.rb +141 -0
- metadata +71 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ab7f3cff1adfd1e6a69afec2832299ca911bf2732cb3c205c9c116edfaf094eb
|
|
4
|
+
data.tar.gz: 8f45b484e5c08cd7c25498c028ff3f00540ef5b494561adbe964917fb2ebff87
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2e7508a3ff72d562ca069ea2fa8a5b9330ff6066121beb8f4162849673cac097dbb2cceba10b8a03884a90285f11924846763bd834c1b56029bf87240e76544e
|
|
7
|
+
data.tar.gz: bef6939ad19d6ecfea699367bbfd51f69e9a0fee664927f14ff254d0efe349e0403443c5c34804d290810fbe7974c687007958e547ae646c40bb590c038fa8bd
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-02-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `assert_true` / `refute_true` — assert a value is literally `true`, not just truthy
|
|
13
|
+
- `assert_false` / `refute_false` — assert a value is literally `false`, not just falsey
|
|
14
|
+
- `assert_eql` / `refute_eql` — assert equality using `eql?` instead of `==`
|
|
15
|
+
- Strict `assert_predicate` / `refute_predicate` — require predicates to return `true` or `false`
|
|
16
|
+
- Strict `assert_operator` / `refute_operator` — require operators to return `true` or `false`
|
|
17
|
+
- Strict `assert_nil` / `refute_nil` — use `equal?` identity check instead of `nil?`
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Erik Berlin
|
|
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,156 @@
|
|
|
1
|
+
# `minitest-strict`
|
|
2
|
+
|
|
3
|
+
[](https://github.com/sferik/minitest-strict/actions/workflows/test.yml)
|
|
4
|
+
[](https://github.com/sferik/minitest-strict/actions/workflows/lint.yml)
|
|
5
|
+
[](https://github.com/sferik/minitest-strict/actions/workflows/rdoc_coverage.yml)
|
|
6
|
+
[](https://github.com/sferik/minitest-strict/actions/workflows/mutant.yml)
|
|
7
|
+
[](https://github.com/sferik/minitest-strict/actions/workflows/steep.yml)
|
|
8
|
+
[](https://badge.fury.io/rb/minitest-strict)
|
|
9
|
+
|
|
10
|
+
#### Strict assertions for [Minitest](https://github.com/minitest/minitest).
|
|
11
|
+
|
|
12
|
+
## Motivation
|
|
13
|
+
|
|
14
|
+
Minitest's built-in assertions are lenient in ways that can mask bugs:
|
|
15
|
+
|
|
16
|
+
- `assert`, `assert_predicate`, and `assert_operator` pass for any truthy return value, not just `true`. A predicate method that accidentally returns `1`, `"yes"`, or an object will silently pass.
|
|
17
|
+
- `refute`, `refute_predicate`, and `refute_operator` pass for any falsey return value, not just `false`. A method that returns `nil` instead of `false` won't be caught.
|
|
18
|
+
- `assert_nil` and `refute_nil` call `nil?`, which can be overridden on an object and mask bugs.
|
|
19
|
+
- There's no built-in assertion that a value is exactly `true` or exactly `false`.
|
|
20
|
+
- There's no built-in assertion for `eql?` equality (e.g. distinguishing `1` from `1.0`).
|
|
21
|
+
|
|
22
|
+
`minitest-strict` fixes all of this. It redefines several Minitest assertions to require strict boolean return values and adds `assert_true`, `assert_false`, and `assert_eql` (with corresponding refutations).
|
|
23
|
+
|
|
24
|
+
Strict assertions also make mutation testing with [Mutant](https://github.com/mbj/mutant) more effective. When assertions accept only exact boolean values, mutations like replacing `true` with `false` or swapping `nil` for `false` are reliably caught — mutations that lenient assertions would let survive.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Add to your Gemfile:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
gem "minitest-strict"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then require it in your test helper:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
require "minitest/autorun"
|
|
38
|
+
require "minitest/strict"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## New Assertions
|
|
42
|
+
|
|
43
|
+
### `assert_true` / `refute_true`
|
|
44
|
+
|
|
45
|
+
Passes only when the value is exactly `true` — not merely truthy.
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
assert_true true # pass
|
|
49
|
+
assert_true 1 # fail
|
|
50
|
+
assert_true "yes" # fail
|
|
51
|
+
assert_true nil # fail
|
|
52
|
+
|
|
53
|
+
refute_true false # pass
|
|
54
|
+
refute_true nil # pass
|
|
55
|
+
refute_true 1 # pass
|
|
56
|
+
refute_true true # fail
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `assert_false` / `refute_false`
|
|
60
|
+
|
|
61
|
+
Passes only when the value is exactly `false` — not merely falsey.
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
assert_false false # pass
|
|
65
|
+
assert_false nil # fail
|
|
66
|
+
assert_false 0 # fail
|
|
67
|
+
assert_false "" # fail
|
|
68
|
+
|
|
69
|
+
refute_false true # pass
|
|
70
|
+
refute_false nil # pass
|
|
71
|
+
refute_false 0 # pass
|
|
72
|
+
refute_false false # fail
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `assert_eql` / `refute_eql`
|
|
76
|
+
|
|
77
|
+
> [!NOTE]
|
|
78
|
+
> `1 == 1.0` is `true` in Ruby, but `1.eql?(1.0)` is `false`. Be mindful of this distinction when comparing numeric values.
|
|
79
|
+
|
|
80
|
+
Uses `eql?` instead of `==` for a stricter equality check. This distinguishes values that are `==` but not the same type.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
assert_eql 1, 1 # pass
|
|
84
|
+
assert_eql "foo", "foo" # pass
|
|
85
|
+
assert_eql 1, 1.0 # fail — 1 == 1.0 is true, but 1.eql?(1.0) is false
|
|
86
|
+
|
|
87
|
+
refute_eql 1, 1.0 # pass
|
|
88
|
+
refute_eql 1, 2 # pass
|
|
89
|
+
refute_eql 1, 1 # fail
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Strict Redefinitions
|
|
93
|
+
|
|
94
|
+
> [!IMPORTANT]
|
|
95
|
+
> The following Minitest assertions are **redefined** to require exact boolean return values. Existing tests may fail if the methods under test return truthy/falsey values instead of `true`/`false`.
|
|
96
|
+
|
|
97
|
+
### `assert_predicate` / `refute_predicate`
|
|
98
|
+
|
|
99
|
+
> [!WARNING]
|
|
100
|
+
> Methods like `Numeric#nonzero?` return `self` or `nil` instead of `true` or `false`. These will fail with minitest-strict's `assert_predicate` and `refute_predicate`.
|
|
101
|
+
|
|
102
|
+
Standard Minitest accepts any truthy/falsey return value. minitest-strict requires predicates to return exactly `true` or `false`.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
assert_predicate "", :empty? # pass — String#empty? returns true
|
|
106
|
+
assert_predicate "hello", :empty? # fail — returns false
|
|
107
|
+
|
|
108
|
+
# Catches methods that return truthy values other than true:
|
|
109
|
+
assert_predicate 1, :nonzero? # fail — returns 1, not true
|
|
110
|
+
|
|
111
|
+
refute_predicate "hello", :empty? # pass — returns false
|
|
112
|
+
refute_predicate "", :empty? # fail — returns true
|
|
113
|
+
|
|
114
|
+
# Catches methods that return falsey values other than false:
|
|
115
|
+
refute_predicate 0, :nonzero? # fail — returns nil, not false
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `assert_operator` / `refute_operator`
|
|
119
|
+
|
|
120
|
+
Requires operators to return exactly `true` or `false`.
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
assert_operator 1, :<, 2 # pass — returns true
|
|
124
|
+
assert_operator 2, :<, 1 # fail — returns false
|
|
125
|
+
|
|
126
|
+
refute_operator 2, :<, 1 # pass — returns false
|
|
127
|
+
refute_operator 1, :<, 2 # fail — returns true
|
|
128
|
+
|
|
129
|
+
# Catches operators that return non-boolean values:
|
|
130
|
+
obj.define_singleton_method(:<=>) { |_| 1 }
|
|
131
|
+
assert_operator obj, :<=>, 2 # fail — returns 1, not true
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `assert_nil` / `refute_nil`
|
|
135
|
+
|
|
136
|
+
> [!NOTE]
|
|
137
|
+
> The standard Minitest implementation calls `nil?`, which can be overridden. minitest-strict uses `equal?` (identity) instead, so only the actual `nil` object passes.
|
|
138
|
+
|
|
139
|
+
Uses `equal?` (identity) instead of `nil?`, so objects that override `nil?` can't fool the check.
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
assert_nil nil # pass
|
|
143
|
+
assert_nil false # fail
|
|
144
|
+
|
|
145
|
+
# Can't be tricked by overriding nil?
|
|
146
|
+
obj.define_singleton_method(:nil?) { true }
|
|
147
|
+
assert_nil obj # fail — obj is not nil
|
|
148
|
+
|
|
149
|
+
refute_nil 1 # pass
|
|
150
|
+
refute_nil false # pass
|
|
151
|
+
refute_nil nil # fail
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require "minitest/assertions"
|
|
2
|
+
require_relative "strict/version"
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Minitest extensions for strict boolean assertions.
|
|
6
|
+
|
|
7
|
+
module Minitest
|
|
8
|
+
##
|
|
9
|
+
# Strict assertion methods that require literal +true+ or +false+
|
|
10
|
+
# return values instead of truthy or falsey.
|
|
11
|
+
module Assertions
|
|
12
|
+
##
|
|
13
|
+
# Fails unless +obj+ is literally +true+ (not just truthy).
|
|
14
|
+
|
|
15
|
+
def assert_true obj, msg = nil
|
|
16
|
+
msg = message(msg) { "Expected #{mu_pp obj} to be true" }
|
|
17
|
+
assert obj.equal?(true), msg
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Fails unless +obj+ is literally +false+ (not just falsey).
|
|
22
|
+
|
|
23
|
+
def assert_false obj, msg = nil
|
|
24
|
+
msg = message(msg) { "Expected #{mu_pp obj} to be false" }
|
|
25
|
+
assert obj.equal?(false), msg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Fails if +obj+ is literally +true+.
|
|
30
|
+
|
|
31
|
+
def refute_true obj, msg = nil
|
|
32
|
+
msg = message(msg) { "Expected true to not be true" }
|
|
33
|
+
refute obj.equal?(true), msg
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Fails if +obj+ is literally +false+.
|
|
38
|
+
|
|
39
|
+
def refute_false obj, msg = nil
|
|
40
|
+
msg = message(msg) { "Expected false to not be false" }
|
|
41
|
+
refute obj.equal?(false), msg
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Fails unless +act+ is eql? to +exp+. Uses +Object#eql?+ for
|
|
46
|
+
# equality without type coercion. Eg:
|
|
47
|
+
#
|
|
48
|
+
# assert_eql 1, 1 # pass
|
|
49
|
+
# assert_eql 1, 1.0 # fail
|
|
50
|
+
|
|
51
|
+
def assert_eql exp, act, msg = nil
|
|
52
|
+
msg = message(msg) { "Expected #{mu_pp act} to be eql? to #{mu_pp exp}" }
|
|
53
|
+
assert exp.eql?(act), msg
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Fails if +act+ is eql? to +exp+.
|
|
58
|
+
|
|
59
|
+
def refute_eql exp, act, msg = nil
|
|
60
|
+
msg = message(msg) { "Expected #{mu_pp act} to not be eql? to #{mu_pp exp}" }
|
|
61
|
+
refute exp.eql?(act), msg
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Strict redefinitions -- require boolean return values
|
|
65
|
+
|
|
66
|
+
silence = $VERBOSE
|
|
67
|
+
$VERBOSE = nil
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# Fails unless +o1+ is +op+. Requires +op+ to return literal
|
|
71
|
+
# +true+, not just a truthy value.
|
|
72
|
+
#
|
|
73
|
+
# assert_predicate str, :empty?
|
|
74
|
+
|
|
75
|
+
def assert_predicate o1, op, msg = nil
|
|
76
|
+
assert_respond_to o1, op, include_all: true
|
|
77
|
+
msg = message(msg) { "Expected #{mu_pp o1} to be #{op}" }
|
|
78
|
+
assert_equal true, o1.__send__(op), msg
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
# Fails if +o1+ is +op+. Requires +op+ to return literal
|
|
83
|
+
# +false+, not just a falsey value.
|
|
84
|
+
#
|
|
85
|
+
# refute_predicate str, :empty?
|
|
86
|
+
|
|
87
|
+
def refute_predicate o1, op, msg = nil
|
|
88
|
+
assert_respond_to o1, op, include_all: true
|
|
89
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op}" }
|
|
90
|
+
assert_equal false, o1.__send__(op), msg
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# For testing with binary operators. Requires the operator to
|
|
95
|
+
# return literal +true+, not just a truthy value. Falls through
|
|
96
|
+
# to assert_predicate if +o2+ is not given. Eg:
|
|
97
|
+
#
|
|
98
|
+
# assert_operator 5, :<=, 4
|
|
99
|
+
|
|
100
|
+
def assert_operator o1, op, o2 = UNDEFINED, msg = nil
|
|
101
|
+
return assert_predicate o1, op, msg if o2 == UNDEFINED
|
|
102
|
+
|
|
103
|
+
assert_respond_to o1, op, include_all: true
|
|
104
|
+
msg = message(msg) { "Expected #{mu_pp o1} to be #{op} #{mu_pp o2}" }
|
|
105
|
+
assert_equal true, o1.__send__(op, o2), msg
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
##
|
|
109
|
+
# For testing with binary operators. Requires the operator to
|
|
110
|
+
# return literal +false+, not just a falsey value. Falls through
|
|
111
|
+
# to refute_predicate if +o2+ is not given. Eg:
|
|
112
|
+
#
|
|
113
|
+
# refute_operator 1, :>, 2
|
|
114
|
+
|
|
115
|
+
def refute_operator o1, op, o2 = UNDEFINED, msg = nil
|
|
116
|
+
return refute_predicate o1, op, msg if o2 == UNDEFINED
|
|
117
|
+
|
|
118
|
+
assert_respond_to o1, op, include_all: true
|
|
119
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op} #{mu_pp o2}" }
|
|
120
|
+
assert_equal false, o1.__send__(op, o2), msg
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# Fails unless +obj+ is nil. Uses +equal?+ for identity check.
|
|
125
|
+
|
|
126
|
+
def assert_nil obj, msg = nil
|
|
127
|
+
msg = message(msg) { "Expected #{mu_pp obj} to be nil" }
|
|
128
|
+
assert obj.equal?(nil), msg
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
##
|
|
132
|
+
# Fails if +obj+ is nil. Uses +equal?+ for identity check.
|
|
133
|
+
|
|
134
|
+
def refute_nil obj, msg = nil
|
|
135
|
+
msg = message(msg) { "Expected nil to not be nil" }
|
|
136
|
+
refute obj.equal?(nil), msg
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
$VERBOSE = silence
|
|
140
|
+
end
|
|
141
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: minitest-strict
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Erik Berlin
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: minitest
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '5.21'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '7'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '5.21'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '7'
|
|
32
|
+
description: Redefines Minitest assertions to require strict boolean return values
|
|
33
|
+
and adds assert_true, assert_false, and assert_eql.
|
|
34
|
+
email:
|
|
35
|
+
- sferik@gmail.com
|
|
36
|
+
executables: []
|
|
37
|
+
extensions: []
|
|
38
|
+
extra_rdoc_files: []
|
|
39
|
+
files:
|
|
40
|
+
- CHANGELOG.md
|
|
41
|
+
- LICENSE.txt
|
|
42
|
+
- README.md
|
|
43
|
+
- lib/minitest/strict.rb
|
|
44
|
+
- lib/minitest/strict/version.rb
|
|
45
|
+
homepage: https://github.com/sferik/minitest-strict
|
|
46
|
+
licenses:
|
|
47
|
+
- MIT
|
|
48
|
+
metadata:
|
|
49
|
+
rubygems_mfa_required: 'true'
|
|
50
|
+
source_code_uri: https://github.com/sferik/minitest-strict
|
|
51
|
+
bug_tracker_uri: https://github.com/sferik/minitest-strict/issues
|
|
52
|
+
changelog_uri: https://github.com/sferik/minitest-strict/blob/main/CHANGELOG.md
|
|
53
|
+
documentation_uri: https://www.rubydoc.info/gems/minitest-strict
|
|
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.2'
|
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '0'
|
|
67
|
+
requirements: []
|
|
68
|
+
rubygems_version: 4.0.6
|
|
69
|
+
specification_version: 4
|
|
70
|
+
summary: Strict assertions for Minitest
|
|
71
|
+
test_files: []
|