@@ -26,7 +26,11 @@ import Testing
2626 ] )
2727func positionValidatorAcceptsPlayablePositions( fen: String ) throws {
2828 let position = try FENSerializer ( ) . position ( from: fen)
29+ let result = PositionValidator ( ) . validationResult ( for: position)
2930
31+ #expect( result. isValid)
32+ #expect( result. issues. isEmpty)
33+ #expect( try result. validatedPosition ( ) == position)
3034 #expect( PositionValidator ( ) . issues ( in: position) . isEmpty)
3135 #expect( try FENSerializer ( ) . validatedPosition ( from: fen) == position)
3236}
@@ -175,6 +179,79 @@ func positionValidatorAcceptsPlayablePositions(fen: String) throws {
175179 )
176180}
177181
182+ @Test func positionValidationResultReportsSemanticIssuesWithoutThrowing( ) throws {
183+ let position = try FENSerializer ( ) . position ( from: " P3k3/8/8/8/8/8/8/8 w K d6 1 1 " )
184+ let result = PositionValidator ( ) . validationResult ( for: position)
185+
186+ #expect( result. position == position)
187+ #expect( result. isValid == false )
188+ #expect( result. issues. contains ( . missingKing( . white) ) )
189+ #expect( result. issues. contains ( . pawnOnInvalidRank( Square ( coordinate: " a8 " ) ) ) )
190+ #expect( result. issues. contains ( . invalidCastlingRight( Piece ( kind: . king, color: . white) ) ) )
191+ #expect( result. issues. contains ( . invalidEnPassantTarget( Square ( coordinate: " d6 " ) ) ) )
192+
193+ do {
194+ _ = try result. validatedPosition ( )
195+ Issue . record ( " Expected semantic validation result to throw " )
196+ } catch let error as PositionValidationError {
197+ #expect( error == . invalidPosition( result. issues) )
198+ } catch {
199+ Issue . record ( " Expected PositionValidationError, got: \( error) " )
200+ }
201+ }
202+
203+ @Test func fenValidationResultReportsValidPositions( ) throws {
204+ let serializer = FENSerializer ( )
205+ let position = try serializer. position ( from: PGNSerializer . standardStartingFEN)
206+ let result = serializer. validationResult ( for: PGNSerializer . standardStartingFEN)
207+
208+ #expect( result == . valid( position) )
209+ #expect( result. isValid)
210+ #expect( result. position == position)
211+ #expect( result. syntaxError == nil )
212+ #expect( result. positionIssues. isEmpty)
213+ #expect( try result. validatedPosition ( ) == position)
214+ }
215+
216+ @Test func fenValidationResultReportsSyntaxErrorsWithoutThrowing( ) {
217+ let result = FENSerializer ( ) . validationResult ( for: " 8/8/8/8/8/8/8 w - - 0 1 " )
218+
219+ #expect( result. isValid == false )
220+ #expect( result. position == nil )
221+ #expect( result. syntaxError == . invalidPiecePlacement( " 8/8/8/8/8/8/8 " ) )
222+ #expect( result. positionIssues. isEmpty)
223+
224+ do {
225+ _ = try result. validatedPosition ( )
226+ Issue . record ( " Expected syntax-invalid FEN result to throw " )
227+ } catch let error as FENParsingError {
228+ #expect( error == . invalidPiecePlacement( " 8/8/8/8/8/8/8 " ) )
229+ } catch {
230+ Issue . record ( " Expected FENParsingError, got: \( error) " )
231+ }
232+ }
233+
234+ @Test func fenValidationResultReportsSemanticIssuesWithoutThrowing( ) throws {
235+ let fen = " 8/8/8/8/8/8/8/8 w - - 0 1 "
236+ let parsedPosition = try FENSerializer ( ) . position ( from: fen)
237+ let result = FENSerializer ( ) . validationResult ( for: fen)
238+
239+ #expect( result. isValid == false )
240+ #expect( result. position == parsedPosition)
241+ #expect( result. syntaxError == nil )
242+ #expect( result. positionIssues. contains ( . missingKing( . white) ) )
243+ #expect( result. positionIssues. contains ( . missingKing( . black) ) )
244+
245+ do {
246+ _ = try result. validatedPosition ( )
247+ Issue . record ( " Expected semantically invalid FEN result to throw " )
248+ } catch let error as PositionValidationError {
249+ #expect( error == . invalidPosition( result. positionIssues) )
250+ } catch {
251+ Issue . record ( " Expected PositionValidationError, got: \( error) " )
252+ }
253+ }
254+
178255@Test func fenValidatedPositionPreservesSyntaxErrorsAndThrowsSemanticErrors( ) throws {
179256 do {
180257 _ = try FENSerializer ( ) . validatedPosition ( from: " 8/8/8/8/8/8/8 w - - 0 1 " )
0 commit comments