12
12
//
13
13
// You should have received a copy of the GNU General Public License
14
14
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15
- use std:: io:: Read ;
16
15
17
- use test_case :: test_case ;
16
+ use rstest :: rstest ;
18
17
19
18
use crate :: errors:: CodecError ;
20
19
use crate :: representations:: {
21
20
CONTRACT_MAX_NAME_LENGTH , CONTRACT_MIN_NAME_LENGTH , ClarityName , ContractName , MAX_STRING_LEN ,
22
21
} ;
23
22
use crate :: stacks_common:: codec:: StacksMessageCodec ;
24
23
25
- #[ test_case( "hello" ; "valid_name" ) ]
26
- #[ test_case( "hello-dash" ; "dash" ) ]
27
- #[ test_case( "hello_underscore" ; "underscore" ) ]
28
- #[ test_case( "test123" ; "numbers" ) ]
29
- #[ test_case( "a" ; "single_letter" ) ]
30
- #[ test_case( "set-token-uri!" ; "exclamation_mark" ) ]
31
- #[ test_case( "is-owner?" ; "question_mark" ) ]
32
- #[ test_case( "math+" ; "plus" ) ]
33
- #[ test_case( "greater-than<" ; "less_than" ) ]
34
- #[ test_case( "less-than>" ; "greater_than" ) ]
35
- #[ test_case( "<=" ; "less_than_or_equal_to" ) ]
36
- #[ test_case( ">=" ; "greater_than_or_equal_to" ) ]
37
- #[ test_case( "*" ; "asterisk" ) ]
38
- #[ test_case( "/" ; "slash" ) ]
39
- #[ test_case( "-" ; "dash-only" ) ]
40
- #[ test_case( "=" ; "equals" ) ]
41
- fn test_clarity_name_valid ( name : & str ) {
24
+ #[ rstest]
25
+ #[ case:: valid_name( "hello" ) ]
26
+ #[ case:: dash( "hello-dash" ) ]
27
+ #[ case:: underscore( "hello_underscore" ) ]
28
+ #[ case:: numbers( "test123" ) ]
29
+ #[ case:: single_letter( "a" ) ]
30
+ #[ case:: exclamation_mark( "set-token-uri!" ) ]
31
+ #[ case:: question_mark( "is-owner?" ) ]
32
+ #[ case:: plus( "math+" ) ]
33
+ #[ case:: less_than( "greater-than<" ) ]
34
+ #[ case:: greater_than( "less-than>" ) ]
35
+ #[ case:: less_than_or_equal_to( "<=" ) ]
36
+ #[ case:: greater_than_or_equal_to( ">=" ) ]
37
+ #[ case:: asterisk( "*" ) ]
38
+ #[ case:: slash( "/" ) ]
39
+ #[ case:: dash_only( "-" ) ]
40
+ #[ case:: equals( "=" ) ]
41
+ fn test_clarity_name_valid ( #[ case] name : & str ) {
42
42
let clarity_name = ClarityName :: try_from ( name. to_string ( ) )
43
43
. unwrap_or_else ( |_| panic ! ( "Should parse valid clarity name: {name}" ) ) ;
44
44
assert_eq ! ( clarity_name. as_str( ) , name) ;
45
45
}
46
46
47
- #[ test_case( "" ; "empty" ) ]
48
- #[ test_case( "123abc" ; "starts_with_number" ) ]
49
- #[ test_case( "hello world" ; "contains_space" ) ]
50
- #[ test_case( "hello@world" ; "contains_at" ) ]
51
- #[ test_case( "hello#world" ; "contains_hash" ) ]
52
- #[ test_case( "hello$world" ; "contains_dollar" ) ]
53
- #[ test_case( "hello%world" ; "contains_percent" ) ]
54
- #[ test_case( "hello&world" ; "contains_ampersand" ) ]
55
- #[ test_case( "hello.world" ; "contains_dot" ) ]
56
- #[ test_case( "hello,world" ; "contains_comma" ) ]
57
- #[ test_case( "hello;world" ; "contains_semicolon" ) ]
58
- #[ test_case( "hello:world" ; "contains_colon" ) ]
59
- #[ test_case( "hello|world" ; "contains_pipe" ) ]
60
- #[ test_case( "hello\\ world" ; "contains_backslash" ) ]
61
- #[ test_case( "hello\" world" ; "contains_quote" ) ]
62
- #[ test_case( "hello'world" ; "contains_apostrophe" ) ]
63
- #[ test_case( "hello[world" ; "contains_bracket_open" ) ]
64
- #[ test_case( "hello]world" ; "contains_bracket_close" ) ]
65
- #[ test_case( "hello{world" ; "contains_curly_open" ) ]
66
- #[ test_case( "hello}world" ; "contains_curly_close" ) ]
67
- #[ test_case( "hello(world" ; "contains_parenthesis_open" ) ]
68
- #[ test_case( "hello)world" ; "contains_parenthesis_close" ) ]
69
- #[ test_case( & "a" . repeat( MAX_STRING_LEN as usize + 1 ) ; "too_long" ) ]
70
- fn test_clarity_name_invalid ( name : & str ) {
47
+ #[ rstest]
48
+ #[ case:: empty( "" ) ]
49
+ #[ case:: starts_with_number( "123abc" ) ]
50
+ #[ case:: contains_space( "hello world" ) ]
51
+ #[ case:: contains_at( "hello@world" ) ]
52
+ #[ case:: contains_hash( "hello#world" ) ]
53
+ #[ case:: contains_dollar( "hello$world" ) ]
54
+ #[ case:: contains_percent( "hello%world" ) ]
55
+ #[ case:: contains_ampersand( "hello&world" ) ]
56
+ #[ case:: contains_dot( "hello.world" ) ]
57
+ #[ case:: contains_comma( "hello,world" ) ]
58
+ #[ case:: contains_semicolon( "hello;world" ) ]
59
+ #[ case:: contains_colon( "hello:world" ) ]
60
+ #[ case:: contains_pipe( "hello|world" ) ]
61
+ #[ case:: contains_backslash( "hello\\ world" ) ]
62
+ #[ case:: contains_quote( "hello\" world" ) ]
63
+ #[ case:: contains_apostrophe( "hello'world" ) ]
64
+ #[ case:: contains_bracket_open( "hello[world" ) ]
65
+ #[ case:: contains_bracket_close( "hello]world" ) ]
66
+ #[ case:: contains_curly_open( "hello{world" ) ]
67
+ #[ case:: contains_curly_close( "hello}world" ) ]
68
+ #[ case:: contains_parenthesis_open( "hello(world" ) ]
69
+ #[ case:: contains_parenthesis_close( "hello)world" ) ]
70
+ #[ case:: too_long( & "a" . repeat( MAX_STRING_LEN as usize + 1 ) ) ]
71
+ fn test_clarity_name_invalid ( #[ case] name : & str ) {
71
72
let result = ClarityName :: try_from ( name. to_string ( ) ) ;
72
73
assert ! ( result. is_err( ) ) ;
73
74
assert ! ( matches!(
@@ -76,9 +77,10 @@ fn test_clarity_name_invalid(name: &str) {
76
77
) ) ;
77
78
}
78
79
79
- #[ test_case( "test-name" ) ]
80
- #[ test_case( & "a" . repeat( MAX_STRING_LEN as usize ) ; "max-length" ) ]
81
- fn test_clarity_name_serialization ( name : & str ) {
80
+ #[ rstest]
81
+ #[ case( "test-name" ) ]
82
+ #[ case:: max_length( & "a" . repeat( MAX_STRING_LEN as usize ) ) ]
83
+ fn test_clarity_name_serialization ( #[ case] name : & str ) {
82
84
let name = ClarityName :: try_from ( name. to_string ( ) ) . unwrap ( ) ;
83
85
84
86
let mut buffer = Vec :: new ( ) ;
@@ -95,59 +97,62 @@ fn test_clarity_name_serialization(name: &str) {
95
97
}
96
98
97
99
// the first byte is the length of the buffer.
98
- #[ test_case( vec![ 4 , 0xFF , 0xFE , 0xFD , 0xFC ] . as_slice( ) , "Failed to parse Clarity name: could not contruct from utf8" ; "invalid_utf8" ) ]
99
- #[ test_case( vec![ 2 , b'2' , b'i' ] . as_slice( ) , "Failed to parse Clarity name: InvalidClarityName(\" ClarityName\" , \" 2i\" )" ; "invalid_name" ) ] // starts with number
100
- #[ test_case( vec![ MAX_STRING_LEN + 1 ] . as_slice( ) , "Failed to deserialize clarity name: too long" ; "too_long" ) ]
101
- #[ test_case( vec![ 3 , b'a' ] . as_slice( ) , "failed to fill whole buffer" ; "wrong_length" ) ]
102
- fn test_clarity_name_deserialization_errors < R : Read > ( mut buffer : R , error_message : & str ) {
103
- let result = ClarityName :: consensus_deserialize ( & mut buffer) ;
100
+ #[ rstest]
101
+ #[ case:: invalid_utf8( vec![ 4 , 0xFF , 0xFE , 0xFD , 0xFC ] , "Failed to parse Clarity name: could not contruct from utf8" ) ]
102
+ #[ case:: invalid_name( vec![ 2 , b'2' , b'i' ] , "Failed to parse Clarity name: InvalidClarityName(\" ClarityName\" , \" 2i\" )" ) ] // starts with number
103
+ #[ case:: too_long( vec![ MAX_STRING_LEN + 1 ] , "Failed to deserialize clarity name: too long" ) ]
104
+ #[ case:: wrong_length( vec![ 3 , b'a' ] , "failed to fill whole buffer" ) ]
105
+ fn test_clarity_name_deserialization_errors ( #[ case] buffer : Vec < u8 > , #[ case] error_message : & str ) {
106
+ let result = ClarityName :: consensus_deserialize ( & mut buffer. as_slice ( ) ) ;
104
107
assert ! ( result. is_err( ) ) ;
105
108
assert_eq ! ( result. unwrap_err( ) . to_string( ) , error_message) ;
106
109
}
107
110
108
- #[ test_case( "hello" ; "valid_name" ) ]
109
- #[ test_case( "contract-name" ; "dash" ) ]
110
- #[ test_case( "hello_world" ; "underscore" ) ]
111
- #[ test_case( "test123" ; "numbers" ) ]
112
- #[ test_case( "__transient" ; "transient" ) ]
113
- #[ test_case( "a" ; "min_length" ) ]
114
- #[ test_case( & "a" . repeat( CONTRACT_MAX_NAME_LENGTH ) ; "max_length" ) ]
115
- #[ test_case( & "a" . repeat( MAX_STRING_LEN as usize ) ; "max_string_len" ) ]
116
- fn test_contract_name_valid ( name : & str ) {
111
+ #[ rstest]
112
+ #[ case:: valid_name( "hello" ) ]
113
+ #[ case:: dash( "contract-name" ) ]
114
+ #[ case:: underscore( "hello_world" ) ]
115
+ #[ case:: numbers( "test123" ) ]
116
+ #[ case:: transient( "__transient" ) ]
117
+ #[ case:: min_length( "a" ) ]
118
+ #[ case:: max_length( & "a" . repeat( CONTRACT_MAX_NAME_LENGTH ) ) ]
119
+ #[ case:: max_string_len( & "a" . repeat( MAX_STRING_LEN as usize ) ) ]
120
+ fn test_contract_name_valid ( #[ case] name : & str ) {
117
121
let contract_name = ContractName :: try_from ( name. to_string ( ) )
118
122
. unwrap_or_else ( |_| panic ! ( "Should parse valid contract name: {name}" ) ) ;
119
123
assert_eq ! ( contract_name. as_str( ) , name) ;
120
124
}
121
125
122
- #[ test_case( "" ; "emtpy" ) ]
123
- #[ test_case( "123contract" ; "starts_with_number" ) ]
124
- #[ test_case( "hello world" ; "contains_space" ) ]
125
- #[ test_case( "hello@world" ; "contains_at" ) ]
126
- #[ test_case( "hello.world" ; "contains_dot" ) ]
127
- #[ test_case( "hello!world" ; "contains_exclamation" ) ]
128
- #[ test_case( "hello?world" ; "contains_question" ) ]
129
- #[ test_case( "hello+world" ; "contains_plus" ) ]
130
- #[ test_case( "hello*world" ; "contains_asterisk" ) ]
131
- #[ test_case( "hello=world" ; "contains_equals" ) ]
132
- #[ test_case( "hello/world" ; "contains_slash" ) ]
133
- #[ test_case( "hello<world" ; "contains_less_than" ) ]
134
- #[ test_case( "hello>world" ; "contains_greater_than" ) ]
135
- #[ test_case( "hello,world" ; "contains_comma" ) ]
136
- #[ test_case( "hello;world" ; "contains_semicolon" ) ]
137
- #[ test_case( "hello:world" ; "contains_colon" ) ]
138
- #[ test_case( "hello|world" ; "contains_pipe" ) ]
139
- #[ test_case( "hello\\ world" ; "contains_backslash" ) ]
140
- #[ test_case( "hello\" world" ; "contains_quote" ) ]
141
- #[ test_case( "hello'world" ; "contains_apostrophe" ) ]
142
- #[ test_case( "hello[world" ; "contains_bracket_open" ) ]
143
- #[ test_case( "hello]world" ; "contains_bracket_close" ) ]
144
- #[ test_case( "hello{world" ; "contains_curly_open" ) ]
145
- #[ test_case( "hello}world" ; "contains_curly_close" ) ]
146
- #[ test_case( "hello(world" ; "contains_parenthesis_open" ) ]
147
- #[ test_case( "hello)world" ; "contains_parenthesis_close" ) ]
148
- #[ test_case( & "a" . repeat( CONTRACT_MIN_NAME_LENGTH - 1 ) ; "too_short" ) ]
149
- #[ test_case( & "a" . repeat( MAX_STRING_LEN as usize + 1 ) ; "too_long" ) ]
150
- fn test_contract_name_invalid ( name : & str ) {
126
+ #[ rstest]
127
+ #[ case:: empty( "" ) ]
128
+ #[ case:: starts_with_number( "123contract" ) ]
129
+ #[ case:: contains_space( "hello world" ) ]
130
+ #[ case:: contains_at( "hello@world" ) ]
131
+ #[ case:: contains_dot( "hello.world" ) ]
132
+ #[ case:: contains_exclamation( "hello!world" ) ]
133
+ #[ case:: contains_question( "hello?world" ) ]
134
+ #[ case:: contains_plus( "hello+world" ) ]
135
+ #[ case:: contains_asterisk( "hello*world" ) ]
136
+ #[ case:: contains_equals( "hello=world" ) ]
137
+ #[ case:: contains_slash( "hello/world" ) ]
138
+ #[ case:: contains_less_than( "hello<world" ) ]
139
+ #[ case:: contains_greater_than( "hello>world" ) ]
140
+ #[ case:: contains_comma( "hello,world" ) ]
141
+ #[ case:: contains_semicolon( "hello;world" ) ]
142
+ #[ case:: contains_colon( "hello:world" ) ]
143
+ #[ case:: contains_pipe( "hello|world" ) ]
144
+ #[ case:: contains_backslash( "hello\\ world" ) ]
145
+ #[ case:: contains_quote( "hello\" world" ) ]
146
+ #[ case:: contains_apostrophe( "hello'world" ) ]
147
+ #[ case:: contains_bracket_open( "hello[world" ) ]
148
+ #[ case:: contains_bracket_close( "hello]world" ) ]
149
+ #[ case:: contains_curly_open( "hello{world" ) ]
150
+ #[ case:: contains_curly_close( "hello}world" ) ]
151
+ #[ case:: contains_parenthesis_open( "hello(world" ) ]
152
+ #[ case:: contains_parenthesis_close( "hello)world" ) ]
153
+ #[ case:: too_short( & "a" . repeat( CONTRACT_MIN_NAME_LENGTH - 1 ) ) ]
154
+ #[ case:: too_long( & "a" . repeat( MAX_STRING_LEN as usize + 1 ) ) ]
155
+ fn test_contract_name_invalid ( #[ case] name : & str ) {
151
156
let result = ContractName :: try_from ( name. to_string ( ) ) ;
152
157
assert ! ( result. is_err( ) ) ;
153
158
assert ! ( matches!(
@@ -156,14 +161,15 @@ fn test_contract_name_invalid(name: &str) {
156
161
) ) ;
157
162
}
158
163
159
- #[ test_case( "test-contract" ; "valid_name" ) ]
160
- #[ test_case( "contract-name" ; "dash" ) ]
161
- #[ test_case( "hello_world" ; "underscore" ) ]
162
- #[ test_case( "test123" ; "numbers" ) ]
163
- #[ test_case( "__transient" ; "transient" ) ]
164
- #[ test_case( "a" ; "min_length" ) ]
165
- #[ test_case( & "a" . repeat( CONTRACT_MAX_NAME_LENGTH ) ; "max_length" ) ]
166
- fn test_contract_name_serialization ( name : & str ) {
164
+ #[ rstest]
165
+ #[ case:: valid_name( "test-contract" ) ]
166
+ #[ case:: dash( "contract-name" ) ]
167
+ #[ case:: underscore( "hello_world" ) ]
168
+ #[ case:: numbers( "test123" ) ]
169
+ #[ case:: transient( "__transient" ) ]
170
+ #[ case:: min_length( "a" ) ]
171
+ #[ case:: max_length( & "a" . repeat( CONTRACT_MAX_NAME_LENGTH ) ) ]
172
+ fn test_contract_name_serialization ( #[ case] name : & str ) {
167
173
let name = ContractName :: try_from ( name. to_string ( ) ) . unwrap ( ) ;
168
174
let mut buffer = Vec :: with_capacity ( ( name. len ( ) + 1 ) as usize ) ;
169
175
name. consensus_serialize ( & mut buffer)
@@ -176,9 +182,10 @@ fn test_contract_name_serialization(name: &str) {
176
182
assert_eq ! ( deserialized, name) ;
177
183
}
178
184
179
- #[ test_case( & "a" . repeat( CONTRACT_MAX_NAME_LENGTH + 1 ) ; "too_long" ) ]
180
- fn test_contract_name_serialization_too_long_or_short ( name : & str ) {
181
- let name = ContractName :: try_from ( name. to_string ( ) ) . expect ( "should parse" ) ;
185
+ #[ test]
186
+ fn test_contract_name_serialization_too_long ( ) {
187
+ let name =
188
+ ContractName :: try_from ( "a" . repeat ( CONTRACT_MAX_NAME_LENGTH + 1 ) ) . expect ( "should parse" ) ;
182
189
let mut buffer = Vec :: with_capacity ( ( name. len ( ) + 1 ) as usize ) ;
183
190
let result = name. consensus_serialize ( & mut buffer) ;
184
191
assert ! ( result. is_err( ) ) ;
@@ -192,12 +199,13 @@ fn test_contract_name_serialization_too_long_or_short(name: &str) {
192
199
}
193
200
194
201
// the first byte is the length of the buffer.
195
- #[ test_case( vec![ 4 , 0xFF , 0xFE , 0xFD , 0xFC ] . as_slice( ) , "Failed to parse Contract name: could not construct from utf8" ; "invalid_utf8" ) ]
196
- #[ test_case( vec![ 2 , b'2' , b'i' ] . as_slice( ) , "Failed to parse Contract name: InvalidContractName(\" ContractName\" , \" 2i\" )" ; "invalid_name" ) ] // starts with number
197
- #[ test_case( vec![ MAX_STRING_LEN + 1 ] . as_slice( ) , & format!( "Failed to deserialize contract name: too short or too long: {}" , MAX_STRING_LEN + 1 ) ; "too_long" ) ]
198
- #[ test_case( vec![ 3 , b'a' ] . as_slice( ) , "failed to fill whole buffer" ; "wrong_length" ) ]
199
- fn test_contract_name_deserialization_errors < R : Read > ( mut buffer : R , error_message : & str ) {
200
- let result = ContractName :: consensus_deserialize ( & mut buffer) ;
202
+ #[ rstest]
203
+ #[ case:: invalid_utf8( vec![ 4 , 0xFF , 0xFE , 0xFD , 0xFC ] , "Failed to parse Contract name: could not construct from utf8" ) ]
204
+ #[ case:: invalid_name( vec![ 2 , b'2' , b'i' ] , "Failed to parse Contract name: InvalidContractName(\" ContractName\" , \" 2i\" )" ) ] // starts with number
205
+ #[ case:: too_long( vec![ MAX_STRING_LEN + 1 ] , & format!( "Failed to deserialize contract name: too short or too long: {}" , MAX_STRING_LEN + 1 ) ) ]
206
+ #[ case:: wrong_length( vec![ 3 , b'a' ] , "failed to fill whole buffer" ) ]
207
+ fn test_contract_name_deserialization_errors ( #[ case] buffer : Vec < u8 > , #[ case] error_message : & str ) {
208
+ let result = ContractName :: consensus_deserialize ( & mut buffer. as_slice ( ) ) ;
201
209
assert ! ( result. is_err( ) ) ;
202
210
assert_eq ! ( result. unwrap_err( ) . to_string( ) , error_message) ;
203
211
}
0 commit comments