2
2
3
3
#include < functional>
4
4
#include < iostream>
5
+ #include < sstream>
5
6
#include < string>
6
7
#include < vector>
7
8
8
9
#include < engine/uci_engine.hpp>
9
10
10
11
namespace fastchess ::engine {
11
12
13
+ bool isValidInfoLine (const std::string &infoLine) {
14
+ std::istringstream iss (infoLine);
15
+ std::string token;
16
+
17
+ if (!(iss >> token) || token != " info" ) {
18
+ std::cerr << " \r\n Invalid info line format: " << infoLine << std::endl;
19
+ return false ;
20
+ }
21
+
22
+ while (iss >> token) {
23
+ if (token == " time" || token == " nps" || token == " score" ) {
24
+ if (!(iss >> token)) {
25
+ std::cerr << " \r\n No value after token: " << token << std::endl;
26
+ return false ;
27
+ }
28
+
29
+ if (token.find (' .' ) != std::string::npos) {
30
+ std::cerr << " \r\n Time/NPS/Score value is not an integer: " << token << std::endl;
31
+ return false ;
32
+ }
33
+ }
34
+ }
35
+
36
+ return true ;
37
+ }
38
+
12
39
inline bool compliant (int argc, char const *argv[]) {
13
40
int step = 0 ;
14
41
@@ -52,6 +79,7 @@ inline bool compliant(int argc, char const *argv[]) {
52
79
{" Send go wtime 100" , [&uci_engine] { return uci_engine.writeEngine (" go wtime 100" ); }},
53
80
{" Read bestmove" , [&uci_engine] { return uci_engine.readEngine (" bestmove" ) == process::Status::OK; }},
54
81
{" Check if engine prints an info line" , [&uci_engine] { return !uci_engine.lastInfoLine ().empty (); }},
82
+ {" Verify info line format is valid" , [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }},
55
83
{" Verify info line contains score" ,
56
84
[&uci_engine] { return str_utils::contains (uci_engine.lastInfoLine (), " score" ); }},
57
85
{" Set position to black to move" ,
@@ -63,6 +91,8 @@ inline bool compliant(int argc, char const *argv[]) {
63
91
[&uci_engine] { return uci_engine.readEngine (" bestmove" ) == process::Status::OK; }},
64
92
{" Check if engine prints an info line after go btime 100" ,
65
93
[&uci_engine] { return !uci_engine.lastInfoLine ().empty (); }},
94
+ {" Verify info line format is valid after go btime 100" ,
95
+ [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }},
66
96
{" Check if engine prints an info line with the score after go btime 100" ,
67
97
[&uci_engine] { return str_utils::contains (uci_engine.lastInfoLine (), " score" ); }},
68
98
{" Send go wtime 100 winc 100 btime 100 binc 100" ,
@@ -71,6 +101,8 @@ inline bool compliant(int argc, char const *argv[]) {
71
101
[&uci_engine] { return uci_engine.readEngine (" bestmove" ) == process::Status::OK; }},
72
102
{" Check if engine prints an info line after go wtime 100 winc 100" ,
73
103
[&uci_engine] { return !uci_engine.lastInfoLine ().empty (); }},
104
+ {" Verify info line format is valid after go wtime 100 winc 100" ,
105
+ [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }},
74
106
{" Check if engine prints an info line with the score after go wtime 100 winc 100" ,
75
107
[&uci_engine] { return str_utils::contains (uci_engine.lastInfoLine (), " score" ); }},
76
108
{" Send go btime 100 binc 100 wtime 100 winc 100" ,
@@ -79,6 +111,8 @@ inline bool compliant(int argc, char const *argv[]) {
79
111
[&uci_engine] { return uci_engine.readEngine (" bestmove" ) == process::Status::OK; }},
80
112
{" Check if engine prints an info line after go btime 100 binc 100" ,
81
113
[&uci_engine] { return !uci_engine.lastInfoLine ().empty (); }},
114
+ {" Verify info line format is valid after go btime 100 binc 100" ,
115
+ [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }},
82
116
{" Check if engine prints an info line with the score after go btime 100 binc 100" ,
83
117
[&uci_engine] { return str_utils::contains (uci_engine.lastInfoLine (), " score" ); }},
84
118
{" Check if engine prints an info line after go btime 100 binc 100" ,
@@ -91,12 +125,17 @@ inline bool compliant(int argc, char const *argv[]) {
91
125
[&uci_engine] {
92
126
return uci_engine.readEngine (" bestmove" ) == process::Status::OK && uci_engine.bestmove () != std::nullopt;
93
127
}},
128
+ {" Verify info line format is valid after go wtime 100 btime 100" ,
129
+ [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }},
94
130
{" Set position to startpos moves e2e4 e7e5" ,
95
131
[&uci_engine] { return uci_engine.writeEngine (" position startpos moves e2e4 e7e5" ); }},
96
132
{" Send go wtime 100 btime 100" , [&uci_engine] { return uci_engine.writeEngine (" go wtime 100 btime 100" ); }},
97
- {" Read bestmove after position startpos moves e2e4 e7e5" , [&uci_engine] {
133
+ {" Read bestmove after position startpos moves e2e4 e7e5" ,
134
+ [&uci_engine] {
98
135
return uci_engine.readEngine (" bestmove" ) == process::Status::OK && uci_engine.bestmove () != std::nullopt;
99
- }}};
136
+ }},
137
+ {" Verify info line format is valid after position startpos moves e2e4 e7e5" ,
138
+ [&uci_engine] { return isValidInfoLine (uci_engine.lastInfoLine ()); }}};
100
139
101
140
for (const auto &[description, action] : steps) {
102
141
if (!executeStep (description, action)) {
@@ -109,4 +148,4 @@ inline bool compliant(int argc, char const *argv[]) {
109
148
return true ;
110
149
}
111
150
112
- } // namespace fastchess::engine
151
+ } // namespace fastchess::engine
0 commit comments