[gnome-games] chess: Run tests on make check, add tests for PGN files, remove obsolete manual test PGN files



commit f190a87b5725522c8900e963079f056370cb3e0a
Author: Robert Ancell <robert ancell canonical com>
Date:   Tue Feb 22 12:34:19 2011 +1100

    chess: Run tests on make check, add tests for PGN files, remove obsolete manual test PGN files

 glchess/src/Makefile.am           |   17 +++++--
 glchess/src/chess-pgn.vala        |  108 +++++++++++++++++++++++--------------
 glchess/src/test-chess-pgn.vala   |  100 ++++++++++++++++++++++++++++++++++
 glchess/tests/carriage_return.pgn |    9 ---
 glchess/tests/castle.pgn          |   10 ----
 glchess/tests/castleblock.pgn     |   10 ----
 glchess/tests/castleblock2.pgn    |   11 ----
 glchess/tests/castleblock3.pgn    |   10 ----
 glchess/tests/castleblock4.pgn    |   10 ----
 glchess/tests/castleblock5.pgn    |   10 ----
 glchess/tests/castleblock6.pgn    |   11 ----
 glchess/tests/checkmate.pgn       |   10 ----
 glchess/tests/comments.pgn        |   12 ----
 glchess/tests/complex.pgn         |   12 ----
 glchess/tests/complex2.pgn        |   10 ----
 glchess/tests/manual1.pgn         |    1 -
 glchess/tests/manual2.pgn         |    1 -
 glchess/tests/move0.pgn           |   10 ----
 glchess/tests/move1.pgn           |   10 ----
 glchess/tests/move2.pgn           |    9 ---
 glchess/tests/move3.pgn           |   10 ----
 glchess/tests/promotion.pgn       |   10 ----
 glchess/tests/stalemate.pgn       |   24 --------
 glchess/tests/stalemate2.pgn      |   31 -----------
 glchess/tests/threefoldrep.pgn    |   25 ---------
 glchess/tests/threefoldrep2.pgn   |   17 ------
 glchess/tests/threefoldrep3.pgn   |   17 ------
 glchess/tests/yahoo_chess.pgn     |   33 -----------
 28 files changed, 180 insertions(+), 368 deletions(-)
---
diff --git a/glchess/src/Makefile.am b/glchess/src/Makefile.am
index 065c455..8dd1bc4 100644
--- a/glchess/src/Makefile.am
+++ b/glchess/src/Makefile.am
@@ -1,6 +1,8 @@
 bin_PROGRAMS = glchess
 
-noinst_PROGRAMS = test-chess-game
+noinst_PROGRAMS = test-chess-game test-chess-pgn
+
+TESTS = test-chess-game test-chess-pgn
 
 glchess_SOURCES = \
 	config.vapi \
@@ -28,17 +30,24 @@ test_chess_game_SOURCES = \
 	chess-clock.vala \
 	chess-game.vala \
 	test-chess-game.vala
-
 test_chess_game_CFLAGS = \
 	$(GOBJECT_CFLAGS)
-
 test_chess_game_LDADD = \
 	$(GOBJECT_LIBS)
-
 test_chess_game_VALAFLAGS = \
     --pkg gobject-2.0 \
     --pkg posix
 
+test_chess_pgn_SOURCES = \
+	chess-pgn.vala \
+	test-chess-pgn.vala
+test_chess_pgn_CFLAGS = \
+	$(GIO_CFLAGS)
+test_chess_pgn_LDADD = \
+	$(GIO_LIBS)
+test_chess_pgn_VALAFLAGS = \
+    --pkg gio-2.0
+
 glchess_CFLAGS = \
 	-DPKGDATADIR=\"@datadir@/glchess\" \
 	$(GMODULE_CFLAGS) \
diff --git a/glchess/src/chess-pgn.vala b/glchess/src/chess-pgn.vala
index a4cf04b..ee02c65 100644
--- a/glchess/src/chess-pgn.vala
+++ b/glchess/src/chess-pgn.vala
@@ -161,7 +161,8 @@ public class PGNGame
 
 enum State
 {
-    IDLE,
+    TAGS,
+    MOVE_TEXT,
     LINE_COMMENT,
     BRACE_COMMENT,
     TAG_START,
@@ -170,6 +171,7 @@ enum State
     TAG_VALUE,
     POST_TAG_VALUE,
     SYMBOL,
+    PERIOD,
     NAG,
     ERROR
 }
@@ -182,27 +184,22 @@ public class PGN
     {
     }
 
-    public PGN.from_file (File file) throws Error
+    public PGN.from_string (string data) throws PGNError
     {
-        string contents;
-        size_t n_read;
-        file.load_contents (null, out contents, out n_read);
-        
         // FIXME: Feed through newline at end to make sure parsing complete
-       
-        State state = State.IDLE;
+
+        State state = State.TAGS, home_state = State.TAGS;
         PGNGame game = new PGNGame ();
         bool in_escape = false;
         size_t token_start = 0, line_offset = 0;
         string tag_name = "";
         StringBuilder tag_value = new StringBuilder ();
         int line = 1;
-        bool have_tags = false;
         int rav_level = 0;
-        for (size_t offset = 0; offset < contents.length; offset++)
+        for (size_t offset = 0; offset <= data.length; offset++)
         {
-            unichar c = contents[(long) offset];
-            
+            unichar c = data[(long) offset];
+
             if (c == '\n')
             {
                line++;
@@ -211,47 +208,63 @@ public class PGN
             
             switch (state)
             {
-            case State.IDLE:
+            case State.TAGS:
+                home_state = State.TAGS;
                 if (c.isspace ())
-                    ;//
+                    ; /* Ignore whitespace */
                 else if (c == ';')
                     state = State.LINE_COMMENT;
                 else if (c == '{')
                     state = State.BRACE_COMMENT;
                 else if (c == '[')
-                {
-                    have_tags = true;
                     state = State.TAG_START;
+                else
+                {
+                    offset--;
+                    state = State.MOVE_TEXT;
+                    continue;
                 }
-                else if (have_tags && c == '*')
+                break;
+
+            case State.MOVE_TEXT:
+                home_state = State.MOVE_TEXT;
+                if (c.isspace ())
+                    ; /* Ignore whitespace */
+                else if (c == ';')
+                    state = State.LINE_COMMENT;
+                else if (c == '{')
+                    state = State.BRACE_COMMENT;
+                else if (c == '*')
                 {
                     if (rav_level == 0)
                     {
                         game.result = PGNGame.RESULT_IN_PROGRESS;
                         games.append (game);
                         game = new PGNGame ();
-                        have_tags = false;
+                        state = State.TAGS;
                     }
-                    state = State.IDLE;
                 }
-                else if (have_tags && c == '.')
-                    continue;
-                else if (have_tags && c.isalnum ())
+                else if (c == '.')
+                {
+                    offset--;
+                    state = State.PERIOD;
+                }
+                else if (c.isalnum ())
                 {
                     token_start = offset;
                     state = State.SYMBOL;
                 }
-                else if (have_tags && c == '$')
+                else if (c == '$')
                 {
                     token_start = offset + 1;
                     state = State.NAG;
                 }
-                else if (have_tags && c == '(')
+                else if (c == '(')
                 {
                     rav_level++;
                     continue;
                 }
-                else if (have_tags && c == ')')
+                else if (c == ')')
                 {
                     if (rav_level == 0)
                         state = State.ERROR;
@@ -264,12 +277,12 @@ public class PGN
 
             case State.LINE_COMMENT:
                 if (c == '\n')
-                    state = State.IDLE;
+                    state = home_state;
                 break;
 
             case State.BRACE_COMMENT:
                 if (c == '}')
-                    state = State.IDLE;
+                    state = home_state;
                 break;
 
             case State.TAG_START:
@@ -287,7 +300,7 @@ public class PGN
             case State.TAG_NAME:
                 if (c.isspace ())
                 {
-                    tag_name = contents[(long)token_start:(long)offset];
+                    tag_name = data[(long)token_start:(long)offset];
                     state = State.PRE_TAG_VALUE;
                 }
                 else if (c.isalnum() || c == '_' || c == '+' || c == '#' || c == '=' || c == ':' || c == '-')
@@ -329,7 +342,7 @@ public class PGN
                 else if (c == ']')
                 {
                     game.tags.insert (tag_name, tag_value.str);
-                    state = State.IDLE;
+                    state = State.TAGS;
                 }
                 else
                     state = State.ERROR;
@@ -341,13 +354,16 @@ public class PGN
                     continue;
                 else
                 {
-                    string symbol = contents[(long)token_start:(long)offset];
+                    string symbol = data[(long)token_start:(long)offset];
 
                     bool is_number = true;
                     for (int i = 0; i < symbol.length; i++)
                        if (!symbol[i].isdigit ())
                            is_number = false;
 
+                    state = State.MOVE_TEXT;
+                    offset--;
+
                     /* Game termination markers */
                     if (symbol == PGNGame.RESULT_DRAW || symbol == PGNGame.RESULT_WHITE || symbol == PGNGame.RESULT_BLACK)
                     {
@@ -356,7 +372,7 @@ public class PGN
                             game.result = symbol;
                             games.append (game);
                             game = new PGNGame ();
-                            have_tags = false;
+                            state = State.TAGS;
                         }
                     }
                     else if (!is_number)
@@ -364,31 +380,30 @@ public class PGN
                         if (rav_level == 0)
                             game.moves.append (symbol);
                     }
-
-                    state = State.IDLE;
-                    offset--;
                 }
                 break;
 
+            case State.PERIOD:
+                /* FIXME: Should check these move carefully, e.g. "1. e2" */
+                state = State.MOVE_TEXT;
+                break;
+
             case State.NAG:
                 if (c.isdigit ())
                     continue;
                 else
                 {
-                    //string nag = contents[(long)token_start:(long)offset];
+                    //string nag = data[(long)token_start:(long)offset];
                     //stdout.printf ("nag = '%s'\n", nag);
-                    state = State.IDLE;
+                    state = State.MOVE_TEXT;
                     offset--;
                 }
                 break;
 
             case State.ERROR:
                 size_t char_offset = offset - line_offset - 1;
-                var filename = file.get_path ();
-                if (filename == null)
-                    filename = file.get_uri ();
-                stderr.printf ("%s:%d.%d: error: Unexpected character\n", filename, line, (int) (char_offset + 1));
-                stderr.printf ("%s\n", contents[(long)line_offset:(long)offset]);
+                stderr.printf ("%d.%d: error: Unexpected character\n", line, (int) (char_offset + 1));
+                stderr.printf ("%s\n", data[(long)line_offset:(long)offset]);
                 for (int i = 0; i < char_offset; i++)
                     stderr.printf (" ");
                 stderr.printf ("^\n");
@@ -396,8 +411,19 @@ public class PGN
             }
         }
 
+        if (game.moves.length () > 0 || game.tags.size () > 0)
+            games.append (game);
+
         /* Must have at least one game */
         if (games == null)
             throw new PGNError.LOAD_ERROR("No games in PGN file");
+     }
+
+    public PGN.from_file (File file) throws Error
+    {
+        string contents;
+        size_t n_read;
+        file.load_contents (null, out contents, out n_read);
+        this.from_string (contents);
     }
 }
\ No newline at end of file
diff --git a/glchess/src/test-chess-pgn.vala b/glchess/src/test-chess-pgn.vala
new file mode 100644
index 0000000..741d99f
--- /dev/null
+++ b/glchess/src/test-chess-pgn.vala
@@ -0,0 +1,100 @@
+class GlChess
+{
+    static int test_count = 0;
+    static int failure_count = 0;
+
+    private static void test_pgn_file (string data, string moves)
+    {
+        test_count++;
+
+        PGN file;
+        try
+        {
+            file = new PGN.from_string (data);
+        }
+        catch (PGNError e)
+        {
+            stderr.printf ("%d. FAIL %s\n", test_count, e.message);
+            failure_count++;
+            return;
+        }
+
+        var game = file.games.nth_data (0);
+        var move_string = "";
+        foreach (var move in game.moves)
+            move_string += "%s ".printf (move);
+        move_string = move_string.strip ();
+
+        if (move_string == moves)
+            stderr.printf ("%d. PASS\n", test_count);
+        else
+        {
+            failure_count++;
+            stderr.printf ("%d. FAIL got moves '%s', expected '%s'\n", test_count, move_string, moves);
+        }
+    }
+
+    public static int main (string[] args)
+    {
+        /* Simple file in export format */
+        test_pgn_file ("[Event \"?\"]\n" +
+                       "[Site \"?\"]\n" +
+                       "[Date \"????.??.??\"]\n" +
+                       "[Round \"?\"]\n" +
+                       "[White \"\"]\n" +
+                       "[Black \"\"]\n" +
+                       "[Result \"*\"]\n" +
+                       "\n" +
+                       "1. *\n",
+                       "");
+
+        /* No tags */
+        test_pgn_file ("1. e1 *\n", "e1");
+
+        /* No move numbers */
+        test_pgn_file ("e1 *\n", "e1");
+
+        /* No move result */
+        test_pgn_file ("e1\n", "e1");
+
+        /* No trailing newline */
+        test_pgn_file ("e1", "e1");
+
+        /* Carriage returns instead of newlines */
+        test_pgn_file ("[Event \"?\"]\r" +
+                       "\r" +
+                       "1. d4 *\r",
+                       "d4");
+
+        /* Comments */
+        test_pgn_file ("; Line comment 1\n" +
+                       "[Event \"?\"]\n" +
+                       "; Line comment 2\n" +
+                       "\n" +
+                       "1. e4 {First Move} e5 {Multi\n" +
+                       "line\n" +
+                       "comment} 2. Nc3 {More comments} * {Comment about game end}\n",
+                       "e4 e5 Nc3");
+
+        /* Format used by Yahoo Chess */
+        test_pgn_file (";Title: Yahoo! Chess Game\n" +
+                       ";White: roovis\n" +
+                       ";Black: ladyjones96\n" +
+                       ";Date: Fri Oct 19 12:51:54 GMT 2007\n" +
+                       "\n" +
+                       "1. e2-e4 e7-e5\n",
+                       "e2-e4 e7-e5");
+
+        /* Recursive Annotation Variation */
+        test_pgn_file ("1.Ra8+ (1.Bxd6+ Kb7 2.Rc7+ Kb8 (2...Kb6 3.Ra6#) 3.Rd7+ Kc8 4.Rc1# (4.Ra8#))",
+                       "Ra8+");
+
+        /* Numeric Annotation Glyph */
+        test_pgn_file ("e4 e5 $1 Nc3 $2",
+                       "e4 e5 Nc3");
+
+        stdout.printf ("%d/%d tests successful\n", test_count - failure_count, test_count);
+
+        return failure_count;
+    }
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]