@@ -110,6 +110,56 @@ macro_rules! get_ref_from_ptr {
110
110
} ;
111
111
}
112
112
113
+ fn open_common (
114
+ game_ptr : * mut Game ,
115
+ row : GameSizeType ,
116
+ column : GameSizeType ,
117
+ c_open_info_ptr : * mut COpenInfo ,
118
+ c_ei_ptr : * mut CErrorInfo ,
119
+ open_func : fn (
120
+ & mut Game ,
121
+ GameSizeType ,
122
+ GameSizeType ,
123
+ ) -> Result < minesweeper:: OpenInfo , & ' static str > ,
124
+ ) {
125
+ initialize_to_ok ! ( c_ei_ptr) ;
126
+ let game = get_mut_ref_from_ptr ! ( game_ptr, c_ei_ptr) ;
127
+ let c_open_info = get_mut_ref_from_ptr ! ( c_open_info_ptr, c_ei_ptr) ;
128
+
129
+ if c_open_info. newly_opened_fields_length != 0 {
130
+ return_error ! ( c_ei_ptr, CError :: InvalidInput ) ;
131
+ }
132
+ if c_open_info. newly_opened_fields_max_length == 0 {
133
+ return_error ! ( c_ei_ptr, CError :: InsufficientBuffer ) ;
134
+ }
135
+ if c_open_info. newly_opened_fields_ptr . is_null ( ) {
136
+ return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
137
+ }
138
+
139
+ let open_info = return_or_assign ! ( open_func( game, row, column) , c_ei_ptr) ;
140
+
141
+ if open_info. newly_opened_fields . len ( ) as ArraySizeType
142
+ > c_open_info. newly_opened_fields_max_length
143
+ {
144
+ return ;
145
+ }
146
+ c_open_info. result = open_info. result ;
147
+ let c_newly_opened_fields: & mut [ COpenedField ] = unsafe {
148
+ slice:: from_raw_parts_mut (
149
+ c_open_info. newly_opened_fields_ptr ,
150
+ c_open_info. newly_opened_fields_max_length as usize ,
151
+ )
152
+ } ;
153
+ let mut index: usize = 0 ;
154
+ for ( coords, field_type) in open_info. newly_opened_fields {
155
+ c_newly_opened_fields[ index] . row = coords. 0 ;
156
+ c_newly_opened_fields[ index] . column = coords. 1 ;
157
+ c_newly_opened_fields[ index] . field_type = field_type. clone ( ) ;
158
+ index = index + 1 ;
159
+ }
160
+ c_open_info. newly_opened_fields_length = index as ArraySizeType ;
161
+ }
162
+
113
163
// Based on this https://s3.amazonaws.com/temp.michaelfbryan.com/objects/index.html
114
164
#[ repr( C ) ]
115
165
pub struct COpenedField {
@@ -153,49 +203,32 @@ pub extern "C" fn minesweeper_new_game(
153
203
}
154
204
155
205
#[ no_mangle]
156
- pub extern "C" fn minesweeper_game_open (
206
+ pub extern "C" fn minesweeper_game_open_neighbors (
157
207
game_ptr : * mut Game ,
158
208
row : GameSizeType ,
159
209
column : GameSizeType ,
160
210
c_open_info_ptr : * mut COpenInfo ,
161
211
c_ei_ptr : * mut CErrorInfo ,
162
212
) {
163
- initialize_to_ok ! ( c_ei_ptr) ;
164
- let game = get_mut_ref_from_ptr ! ( game_ptr, c_ei_ptr) ;
165
- let c_open_info = get_mut_ref_from_ptr ! ( c_open_info_ptr, c_ei_ptr) ;
166
-
167
- if c_open_info. newly_opened_fields_length != 0 {
168
- return_error ! ( c_ei_ptr, CError :: InvalidInput ) ;
169
- }
170
- if c_open_info. newly_opened_fields_max_length == 0 {
171
- return_error ! ( c_ei_ptr, CError :: InsufficientBuffer ) ;
172
- }
173
- if c_open_info. newly_opened_fields_ptr . is_null ( ) {
174
- return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
175
- }
176
-
177
- let open_info = return_or_assign ! ( game. open( row, column) , c_ei_ptr) ;
213
+ open_common (
214
+ game_ptr,
215
+ row,
216
+ column,
217
+ c_open_info_ptr,
218
+ c_ei_ptr,
219
+ Game :: open_neighbors,
220
+ ) ;
221
+ }
178
222
179
- if open_info. newly_opened_fields . len ( ) as ArraySizeType
180
- > c_open_info. newly_opened_fields_max_length
181
- {
182
- return ;
183
- }
184
- c_open_info. result = open_info. result ;
185
- let c_newly_opened_fields: & mut [ COpenedField ] = unsafe {
186
- slice:: from_raw_parts_mut (
187
- c_open_info. newly_opened_fields_ptr ,
188
- c_open_info. newly_opened_fields_max_length as usize ,
189
- )
190
- } ;
191
- let mut index: usize = 0 ;
192
- for ( coords, field_type) in open_info. newly_opened_fields {
193
- c_newly_opened_fields[ index] . row = coords. 0 ;
194
- c_newly_opened_fields[ index] . column = coords. 1 ;
195
- c_newly_opened_fields[ index] . field_type = field_type. clone ( ) ;
196
- index = index + 1 ;
197
- }
198
- c_open_info. newly_opened_fields_length = index as ArraySizeType ;
223
+ #[ no_mangle]
224
+ pub extern "C" fn minesweeper_game_open (
225
+ game_ptr : * mut Game ,
226
+ row : GameSizeType ,
227
+ column : GameSizeType ,
228
+ c_open_info_ptr : * mut COpenInfo ,
229
+ c_ei_ptr : * mut CErrorInfo ,
230
+ ) {
231
+ open_common ( game_ptr, row, column, c_open_info_ptr, c_ei_ptr, Game :: open) ;
199
232
}
200
233
201
234
#[ no_mangle]
@@ -794,4 +827,143 @@ mod test {
794
827
let mut elapsed_seconds = 0 ;
795
828
minesweeper_game_get_elapsed_seconds ( game_ptr, & mut elapsed_seconds, std:: ptr:: null_mut ( ) ) ;
796
829
}
830
+
831
+ #[ test]
832
+ fn open_neighbors ( ) {
833
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
834
+ let width = get_width ( game_ptr) ;
835
+ let height = get_height ( game_ptr) ;
836
+ let mut buffered_open_info = create_open_info_for ( game_ptr) ;
837
+ let mut buffered_error_info = create_error_info ( 100 ) ;
838
+
839
+ minesweeper_game_open_neighbors (
840
+ game_ptr,
841
+ 1 ,
842
+ 1 ,
843
+ & mut buffered_open_info. data ,
844
+ & mut buffered_error_info. data ,
845
+ ) ;
846
+ assert_ok ! ( buffered_error_info. data) ;
847
+ assert ! ( buffered_open_info. data. newly_opened_fields_length == 0 ) ;
848
+ assert_eq ! ( CError :: Ok , buffered_error_info. data. error_code) ;
849
+
850
+ destroy_game ( & mut game_ptr) ;
851
+ }
852
+
853
+ #[ test]
854
+ fn open_neighbors_with_nullptr_as_game ( ) {
855
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
856
+ let mut error_info = create_empty_error_info ( ) ;
857
+ minesweeper_game_open_neighbors (
858
+ std:: ptr:: null_mut ( ) ,
859
+ 0 ,
860
+ 0 ,
861
+ & mut buffered_open_info. data ,
862
+ & mut error_info,
863
+ ) ;
864
+ assert_eq ! ( CError :: NullPointerAsInput , error_info. error_code) ;
865
+ }
866
+
867
+ #[ test]
868
+ fn open_neighbors_with_nullptr_as_open_info_ptr ( ) {
869
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
870
+ let mut error_info = create_empty_error_info ( ) ;
871
+ minesweeper_game_open_neighbors ( game_ptr, 0 , 0 , std:: ptr:: null_mut ( ) , & mut error_info) ;
872
+ assert_eq ! ( CError :: NullPointerAsInput , error_info. error_code) ;
873
+ destroy_game ( & mut game_ptr) ;
874
+ }
875
+
876
+ #[ test]
877
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
878
+ fn open_neighbors_with_nullptr_as_error_info_ptr ( ) {
879
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
880
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
881
+ minesweeper_game_open_neighbors (
882
+ game_ptr,
883
+ 0 ,
884
+ 0 ,
885
+ & mut buffered_open_info. data ,
886
+ std:: ptr:: null_mut ( ) ,
887
+ ) ;
888
+ }
889
+
890
+ #[ test]
891
+ fn open_neighbors_with_not_empty_newly_opened_fields ( ) {
892
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
893
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
894
+ buffered_open_info. data . newly_opened_fields_length = 1 ;
895
+ let mut error_info = create_empty_error_info ( ) ;
896
+ minesweeper_game_open_neighbors (
897
+ game_ptr,
898
+ 0 ,
899
+ 0 ,
900
+ & mut buffered_open_info. data ,
901
+ & mut error_info,
902
+ ) ;
903
+ assert_eq ! ( CError :: InvalidInput , error_info. error_code) ;
904
+ destroy_game ( & mut game_ptr) ;
905
+ }
906
+
907
+ #[ test]
908
+ fn open_neighbors_with_nullptr_as_newly_opened_fields ( ) {
909
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
910
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
911
+ buffered_open_info. data . newly_opened_fields_ptr = std:: ptr:: null_mut ( ) ;
912
+ let mut error_info = create_empty_error_info ( ) ;
913
+ minesweeper_game_open_neighbors (
914
+ game_ptr,
915
+ 0 ,
916
+ 0 ,
917
+ & mut buffered_open_info. data ,
918
+ & mut error_info,
919
+ ) ;
920
+ assert_eq ! ( CError :: NullPointerAsInput , error_info. error_code) ;
921
+ destroy_game ( & mut game_ptr) ;
922
+ }
923
+
924
+ #[ test]
925
+ fn open_neighbors_with_zero_buffer ( ) {
926
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
927
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
928
+ buffered_open_info. data . newly_opened_fields_max_length = 0 ;
929
+ let mut error_info = create_empty_error_info ( ) ;
930
+ minesweeper_game_open_neighbors (
931
+ game_ptr,
932
+ 0 ,
933
+ 0 ,
934
+ & mut buffered_open_info. data ,
935
+ & mut error_info,
936
+ ) ;
937
+ assert_eq ! ( CError :: InsufficientBuffer , error_info. error_code) ;
938
+ destroy_game ( & mut game_ptr) ;
939
+ }
940
+
941
+ #[ test]
942
+ fn open_neighbors_with_too_big_indices ( ) {
943
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
944
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
945
+ let mut error_info = create_empty_error_info ( ) ;
946
+
947
+ let width = get_width ( game_ptr) ;
948
+ minesweeper_game_open_neighbors (
949
+ game_ptr,
950
+ 0 ,
951
+ width,
952
+ & mut buffered_open_info. data ,
953
+ & mut error_info,
954
+ ) ;
955
+ assert_eq ! ( CError :: UnexpectedError , error_info. error_code) ;
956
+
957
+ error_info = create_empty_error_info ( ) ;
958
+ let height = get_width ( game_ptr) ;
959
+ minesweeper_game_open_neighbors (
960
+ game_ptr,
961
+ height,
962
+ 0 ,
963
+ & mut buffered_open_info. data ,
964
+ & mut error_info,
965
+ ) ;
966
+ assert_eq ! ( CError :: UnexpectedError , error_info. error_code) ;
967
+ destroy_game ( & mut game_ptr) ;
968
+ }
797
969
}
0 commit comments