Skip to content

Commit f6d5b2a

Browse files
Add open_neighbors
1 parent 0e702dc commit f6d5b2a

File tree

1 file changed

+208
-36
lines changed

1 file changed

+208
-36
lines changed

cminesweeper/src/lib.rs

Lines changed: 208 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,56 @@ macro_rules! get_ref_from_ptr {
110110
};
111111
}
112112

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+
113163
// Based on this https://s3.amazonaws.com/temp.michaelfbryan.com/objects/index.html
114164
#[repr(C)]
115165
pub struct COpenedField {
@@ -153,49 +203,32 @@ pub extern "C" fn minesweeper_new_game(
153203
}
154204

155205
#[no_mangle]
156-
pub extern "C" fn minesweeper_game_open(
206+
pub extern "C" fn minesweeper_game_open_neighbors(
157207
game_ptr: *mut Game,
158208
row: GameSizeType,
159209
column: GameSizeType,
160210
c_open_info_ptr: *mut COpenInfo,
161211
c_ei_ptr: *mut CErrorInfo,
162212
) {
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+
}
178222

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);
199232
}
200233

201234
#[no_mangle]
@@ -794,4 +827,143 @@ mod test {
794827
let mut elapsed_seconds = 0;
795828
minesweeper_game_get_elapsed_seconds(game_ptr, &mut elapsed_seconds, std::ptr::null_mut());
796829
}
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+
}
797969
}

0 commit comments

Comments
 (0)