summaryrefslogtreecommitdiff
path: root/src/uci
diff options
context:
space:
mode:
authorAargh Rai <aargh.rai+git@gmail.com>2026-08-27 22:21:14 +0530
committerAargh Rai <aargh.rai+git@gmail.com>2026-08-27 22:21:14 +0530
commit93f1e82cedbf2fcd45ac413cbf2a654e0f65f0b3 (patch)
tree5af71701d99071adf348735518b8dd1f560c3475 /src/uci
parent5a02743c0c9563f41a8c3821a7bbce4fc3b0b839 (diff)
uci testsHEADmaster
Diffstat (limited to 'src/uci')
-rw-r--r--src/uci/response.c659
-rw-r--r--src/uci/state.c156
2 files changed, 793 insertions, 22 deletions
diff --git a/src/uci/response.c b/src/uci/response.c
index 81459d6..f3fc2d9 100644
--- a/src/uci/response.c
+++ b/src/uci/response.c
@@ -3,6 +3,33 @@
#include <stdlib.h>
#include "uci/internals/response.h"
+
+// Tokenize a UCI message into a command. Supports double-quoted strings so
+// that multi-word values (e.g. FEN positions) survive tokenization.
+void load_from_message(uci_cmd_t* cmd, const char* message) {
+ char token[MAX_TOKEN_SIZE];
+ int i = 0, k = 0;
+ bool quoted = false;
+
+ while (message[i] != 0 && message[i] != '\n' && message[i] != '\r') {
+ if (message[i] == '"') {
+ quoted = !quoted;
+ i++;
+ continue;
+ }
+ if (message[i] == ' ' && !quoted) {
+ if (k == 0) { i++; continue; }
+ i++;
+ token[k] = 0;
+ uci_cmd_add(cmd, token);
+ k = 0;
+ continue;
+ }
+ token[k++] = message[i++];
+ }
+ token[k] = 0;
+ uci_cmd_add(cmd, token);
+}
#include "uci/state.h"
#include "fen.h"
@@ -50,23 +77,30 @@ void handle_idle(uci_state_t *state, uci_cmd_t cmd) {
char buffer[2048] = {0};
char name[64] = {0};
char *cursor = name;
- for (int i = 1; i < cmd.args_count; i++) {
- assert((long)cursor - (long)buffer < 2048);
+ int limit = 64;
+ int i = 1;
+ if (i < cmd.args_count && strcmp(uci_cmd_get_arg(cmd, i), "name") == 0) i++;
+ for (; i < cmd.args_count; i++) {
+ assert((long)cursor - (long)(limit == 64 ? name : buffer) < limit);
char *arg = uci_cmd_get_arg(cmd, i);
if (strcmp(arg, "value") == 0) {
- *(--cursor) = 0;
+ if (cursor > name && *(cursor - 1) == ' ') cursor--;
+ *cursor = 0;
cursor = buffer;
+ limit = 2048;
continue;
}
- cursor = stpncpy(cursor, arg, MAX_TOKEN_SIZE);
+ while (*arg) *(cursor++) = *(arg++);
*(cursor++) = ' ';
}
- *(--cursor) = 0;
+ if (cursor > name && *(cursor - 1) == ' ') cursor--;
+ if (cursor > buffer && *(cursor - 1) == ' ') cursor--;
+ *cursor = 0;
apply_option(state, name, buffer);
} else if (strcmp(cmd.root, "ucinewgame") == 0) {
} else if (strcmp(cmd.root, "position") == 0) {
int k = 0;
- char* mode = uci_cmd_get_arg(cmd, 0);
+ char* mode = uci_cmd_get_arg(cmd, k++);
if (strcmp(mode, "startpos") == 0) {
struct fen_load fen = load_fen(
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
@@ -83,13 +117,8 @@ void handle_idle(uci_state_t *state, uci_cmd_t cmd) {
state->position = fen.position;
} else { assert(0 && "Invalid argument for position command"); }
- if (cmd.args_count >= k) return;
+ if (cmd.args_count <= k) return;
assert(strcmp(uci_cmd_get_arg(cmd, k++), "moves") == 0);
- assert(state->moves->count <= cmd.args_count - k);
- int old_move_count = state->moves->count;
- state->moves->count = cmd.args_count - k;
-
- k += old_move_count;
for (; k < cmd.args_count; k++) {
char* move = uci_cmd_get_arg(cmd, k);
add_ipc_move(
@@ -102,15 +131,6 @@ void handle_idle(uci_state_t *state, uci_cmd_t cmd) {
}
} else if (strcmp(cmd.root, "stop") == 0) {
} else if (strcmp(cmd.root, "quit") == 0) {
- free(cmd.args);
-
- int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t);
- for (int i = 0; i < settings_count; i++) {
- option_setting_t setting = state->option_settings[i];
- if (OPTION_STRING != setting.type) continue;
- free(setting.value.string->data);
- }
-
state->signal = UCI_SIGNAL_QUIT;
} else if (strcmp(cmd.root, "isready") == 0) {
state->current_state = UCI_STATE_SYNC;
@@ -210,3 +230,600 @@ void handle_halt(uci_state_t *state, uci_cmd_t cmd) {
// ---
state->current_state = UCI_STATE_IDLE;
}
+
+#ifdef TEST_MOD
+#include <stdbool.h>
+#include <unistd.h>
+
+static uci_cmd_t __make_cmd(const char *line) {
+ uci_cmd_t cmd;
+ uci_cmd_init(&cmd);
+ load_from_message(&cmd, line);
+ return cmd;
+}
+
+static void __free_cmd(uci_cmd_t cmd) { uci_cmd_deinit(cmd); }
+
+static char *__capture_uci(
+ void (*handler)(uci_state_t *, uci_cmd_t),
+ uci_state_t *state,
+ const char *line,
+ char *out,
+ int out_size
+) {
+ int pipefd[2];
+ if (pipe(pipefd) != 0) { out[0] = 0; return out; }
+ int saved = dup(STDOUT_FILENO);
+ dup2(pipefd[1], STDOUT_FILENO);
+ close(pipefd[1]);
+
+ uci_cmd_t cmd = __make_cmd(line);
+ handler(state, cmd);
+ __free_cmd(cmd);
+
+ fflush(stdout);
+ dup2(saved, STDOUT_FILENO);
+ close(saved);
+
+ int n = read(pipefd[0], out, out_size - 1);
+ close(pipefd[0]);
+ out[n > 0 ? n : 0] = 0;
+ return out;
+}
+
+// ---- UCI handshake ----
+
+bool test_uci_handshake_id_and_uciok() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ char out[2048];
+ __capture_uci(handle_initial, &state, "uci", out, sizeof(out));
+
+ bool ok = true;
+ ok &= strstr(out, "id name Gacrux") != NULL;
+ ok &= strstr(out, "id author") != NULL;
+ ok &= strstr(out, "uciok") != NULL;
+ ok &= state.current_state == UCI_STATE_IDLE;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_uci_handshake_prints_all_options() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ char out[4096];
+ __capture_uci(handle_initial, &state, "uci", out, sizeof(out));
+
+ bool ok = true;
+ ok &= strstr(out, "option name Threads type spin") != NULL;
+ ok &= strstr(out, "option name Hash type spin") != NULL;
+ ok &= strstr(out, "option name Clear Hash type button") != NULL;
+ ok &= strstr(out, "option name UCI_ShowCurrLine type check") != NULL;
+ ok &= strstr(out, "option name UCI_LimitStrength type check") != NULL;
+ ok &= strstr(out, "option name UCI_Elo type spin") != NULL;
+ ok &= strstr(out, "option name UCI_AnalyseMode type check") != NULL;
+ ok &= strstr(out, "option name UCI_Opponent type string") != NULL;
+ ok &= strstr(out, "option name UCI_EngineAbout type string") != NULL;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- isready ----
+
+bool test_isready_returns_readyok() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_sync, &state, "isready", out, sizeof(out));
+
+ bool ok = true;
+ ok &= strstr(out, "readyok") != NULL;
+ ok &= state.current_state == UCI_STATE_IDLE;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_isready_transitions_to_idle() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_SYNC;
+
+ char out[256];
+ __capture_uci(handle_uci, &state, "isready", out, sizeof(out));
+
+ bool ok = true;
+ ok &= strstr(out, "readyok") != NULL;
+ ok &= state.current_state == UCI_STATE_IDLE;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- debug ----
+
+bool test_debug_on_sets_flag() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "debug on", out, sizeof(out));
+
+ bool ok = state.debug == true;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_debug_off_clears_flag() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+ state.debug = true;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "debug off", out, sizeof(out));
+
+ bool ok = state.debug == false;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- setoption ----
+
+bool test_setoption_spin() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name Threads value 4", out, sizeof(out));
+
+ bool ok = state.threads == 4;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_spin_clamps_too_low() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name Threads value 0", out, sizeof(out));
+
+ bool ok = state.threads == 1;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_spin_clamps_too_high() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name Threads value 99", out, sizeof(out));
+
+ bool ok = state.threads == 1;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_check_true() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name UCI_AnalyseMode value true", out, sizeof(out));
+
+ bool ok = state.uci_analysemode == true;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_check_false() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+ state.uci_analysemode = true;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name UCI_AnalyseMode value false", out, sizeof(out));
+
+ bool ok = state.uci_analysemode == false;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_button() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name Clear Hash", out, sizeof(out));
+
+ bool ok = state.clear_hash == true;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_string() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name UCI_Opponent value Magnus", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.uci_opponent.length == 6;
+ ok &= memcmp(state.uci_opponent.data, "Magnus", 6) == 0;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_setoption_hash_changes_value() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "setoption name Hash value 128", out, sizeof(out));
+
+ bool ok = state.hash == 128;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- position ----
+
+bool test_position_startpos_loads() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ ipc_moves_t moves;
+ ipc_moves_init(&moves);
+ state.moves = &moves;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "position startpos", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.position.bitboards[WHITE_PAWN] != 0;
+ ok &= state.position.turn == WHITE_TURN;
+
+ ipc_moves_deinit(&moves);
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_position_fen_loads() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ ipc_moves_t moves;
+ ipc_moves_init(&moves);
+ state.moves = &moves;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "position fen \"k7/8/KQ6/8/8/8/8/8 w - - 0 1\"", out, sizeof(out));
+
+ bool ok = state.position.bitboards[WHITE_QUEEN] != 0;
+
+ ipc_moves_deinit(&moves);
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_position_startpos_moves() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ ipc_moves_t moves;
+ ipc_moves_init(&moves);
+ state.moves = &moves;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "position startpos moves e2e4", out, sizeof(out));
+
+ bool ok = state.moves->count == 1;
+ if (ok) {
+ ok &= state.moves->data[0].from == 33;
+ ok &= state.moves->data[0].to == 35;
+ }
+
+ ipc_moves_deinit(&moves);
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- go ----
+
+bool test_go_depth_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go depth 10", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.go_args.depth == 10;
+ ok &= state.current_state == UCI_STATE_ACTIVE;
+ ok &= state.signal == UCI_SIGNAL_GO;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_wtime_btime_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "go wtime 60000 btime 60000 winc 1000 binc 1000", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.go_args.wtime == 60000;
+ ok &= state.go_args.btime == 60000;
+ ok &= state.go_args.winc == 1000;
+ ok &= state.go_args.binc == 1000;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_nodes_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go nodes 50000", out, sizeof(out));
+
+ bool ok = state.go_args.nodes == 50000;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_movetime_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go movetime 5000", out, sizeof(out));
+
+ bool ok = state.go_args.movetime == 5000;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_movestogo_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go movestogo 30", out, sizeof(out));
+
+ bool ok = state.go_args.movestogo == 30;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_mate_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go mate 3", out, sizeof(out));
+
+ bool ok = state.go_args.mate == 3;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_infinite_sets_flag() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go infinite", out, sizeof(out));
+
+ bool ok = state.go_args.infinite == true;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_ponder_sets_flag() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go ponder", out, sizeof(out));
+
+ bool ok = state.go_args.ponder == true;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_combined_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state,
+ "go depth 6 wtime 30000 btime 30000 winc 500 movestogo 20", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.go_args.depth == 6;
+ ok &= state.go_args.wtime == 30000;
+ ok &= state.go_args.btime == 30000;
+ ok &= state.go_args.winc == 500;
+ ok &= state.go_args.movestogo == 20;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_go_perft_sets_args() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "go perft 5", out, sizeof(out));
+
+ bool ok = state.go_args.perft == 5;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+// ---- state machine transitions ----
+
+bool test_active_stop_transitions_to_idle() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_ACTIVE;
+
+ char out[256];
+ __capture_uci(handle_active, &state, "stop", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.current_state == UCI_STATE_HALT;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_halt_sets_stop_signal() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_HALT;
+
+ char out[256];
+ __capture_uci(handle_halt, &state, "", out, sizeof(out));
+
+ bool ok = true;
+ ok &= state.signal == UCI_SIGNAL_STOP;
+ ok &= state.current_state == UCI_STATE_IDLE;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_active_isready_transitions_to_ping() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_ACTIVE;
+
+ char out[256];
+ __capture_uci(handle_active, &state, "isready", out, sizeof(out));
+
+ bool ok = state.current_state == UCI_STATE_PING;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_quit_sets_signal() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "quit", out, sizeof(out));
+
+ bool ok = state.signal == UCI_SIGNAL_QUIT;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_new_game_accepted() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.current_state = UCI_STATE_IDLE;
+
+ char out[256];
+ __capture_uci(handle_idle, &state, "ucinewgame", out, sizeof(out));
+
+ bool ok = state.current_state == UCI_STATE_IDLE;
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_full_handshake_sequence() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ ipc_moves_t moves;
+ ipc_moves_init(&moves);
+ state.moves = &moves;
+
+ char out[2048];
+
+ __capture_uci(handle_uci, &state, "uci", out, sizeof(out));
+ bool ok = state.current_state == UCI_STATE_IDLE;
+ ok &= strstr(out, "uciok") != NULL;
+
+ __capture_uci(handle_idle, &state, "isready", out, sizeof(out));
+ ok &= state.current_state == UCI_STATE_SYNC;
+
+ __capture_uci(handle_uci, &state, "isready", out, sizeof(out));
+ ok &= state.current_state == UCI_STATE_IDLE;
+ ok &= strstr(out, "readyok") != NULL;
+
+ __capture_uci(handle_idle, &state,
+ "setoption name Threads value 2", out, sizeof(out));
+ ok &= state.threads == 2;
+
+ __capture_uci(handle_idle, &state, "position startpos", out, sizeof(out));
+ ok &= state.position.bitboards[WHITE_PAWN] != 0;
+
+ __capture_uci(handle_idle, &state, "go depth 5", out, sizeof(out));
+ ok &= state.current_state == UCI_STATE_ACTIVE;
+ ok &= state.go_args.depth == 5;
+
+ __capture_uci(handle_active, &state, "stop", out, sizeof(out));
+ ok &= state.current_state == UCI_STATE_HALT;
+
+ __capture_uci(handle_halt, &state, "", out, sizeof(out));
+ ok &= state.current_state == UCI_STATE_IDLE;
+
+ ipc_moves_deinit(&moves);
+ uci_state_deinit(&state);
+ return ok;
+}
+#endif
diff --git a/src/uci/state.c b/src/uci/state.c
index 183f849..e108492 100644
--- a/src/uci/state.c
+++ b/src/uci/state.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <string.h>
#include "uci/state.h"
@@ -180,7 +181,16 @@ void uci_state_init(uci_state_t *state) {
);
}
-void uci_state_deinit(uci_state_t *state) {}
+void uci_state_deinit(uci_state_t *state) {
+ int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t);
+ for (int i = 0; i < settings_count; i++) {
+ option_setting_t *s = &state->option_settings[i];
+ if (s->type == OPTION_STRING && s->value.string && s->value.string->data) {
+ free(s->value.string->data);
+ s->value.string->data = NULL;
+ }
+ }
+}
void apply_option(uci_state_t *state, char *name, char *buffer) {
int settings_count = sizeof(state->option_settings)/sizeof(option_setting_t);
@@ -218,3 +228,147 @@ void apply_option(uci_state_t *state, char *name, char *buffer) {
}
}
+#ifdef TEST_MOD
+#include <stdbool.h>
+
+bool test_uci_state_init_defaults() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ bool ok = true;
+ ok &= state.signal == UCI_SIGNAL_NONE;
+ ok &= state.current_state == UCI_STATE_INITIAL;
+ ok &= state.threads == 1;
+ ok &= state.hash == 256;
+ ok &= state.clear_hash == false;
+ ok &= state.uci_showcurrline == false;
+ ok &= state.uci_showrefutations == false;
+ ok &= state.uci_limitstrength == false;
+ ok &= state.uci_elo == 800;
+ ok &= state.uci_analysemode == false;
+ ok &= strcmp(state.name, "Gacrux") == 0;
+ ok &= strcmp(state.author, "Aargh Rai <aarghrai.com>") == 0;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_spin_valid() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "Threads", "4");
+ bool ok = state.threads == 4;
+
+ apply_option(&state, "Hash", "128");
+ ok &= state.hash == 128;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_spin_below_min() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "Threads", "0");
+ bool ok = state.threads == 1;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_spin_above_max() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "Threads", "100");
+ bool ok = state.threads == 1;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_check() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "UCI_AnalyseMode", "true");
+ bool ok = state.uci_analysemode == true;
+
+ apply_option(&state, "UCI_AnalyseMode", "false");
+ ok &= state.uci_analysemode == false;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_button() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "Clear Hash", "");
+ bool ok = state.clear_hash == true;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_string() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ apply_option(&state, "UCI_Opponent", "Carlsen");
+ bool ok = true;
+ ok &= state.uci_opponent.length == 7;
+ ok &= memcmp(state.uci_opponent.data, "Carlsen", 7) == 0;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_apply_option_unknown_ignored() {
+ uci_state_t state;
+ uci_state_init(&state);
+ state.debug = false;
+
+ apply_option(&state, "Nonexistent", "42");
+ bool ok = true;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_option_settings_count() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ int count = sizeof(state.option_settings) / sizeof(option_setting_t);
+ bool ok = count == 11;
+
+ uci_state_deinit(&state);
+ return ok;
+}
+
+bool test_option_settings_types() {
+ uci_state_t state;
+ uci_state_init(&state);
+
+ bool ok = true;
+ ok &= state.option_settings[0].type == OPTION_SPIN; // Threads
+ ok &= state.option_settings[1].type == OPTION_SPIN; // Hash
+ ok &= state.option_settings[2].type == OPTION_BUTTON; // Clear Hash
+ ok &= state.option_settings[3].type == OPTION_CHECK; // UCI_ShowCurrLine
+ ok &= state.option_settings[4].type == OPTION_CHECK; // UCI_ShowRefutations
+ ok &= state.option_settings[5].type == OPTION_CHECK; // UCI_LimitStrength
+ ok &= state.option_settings[6].type == OPTION_SPIN; // UCI_Elo
+ ok &= state.option_settings[7].type == OPTION_CHECK; // UCI_AnalyseMode
+ ok &= state.option_settings[8].type == OPTION_STRING; // UCI_Opponent
+ ok &= state.option_settings[9].type == OPTION_STRING; // UCI_EngineAbout
+ ok &= state.option_settings[10].type == OPTION_STRING;// UCI_SetPositionValue
+
+ uci_state_deinit(&state);
+ return ok;
+}
+#endif
+