pygo/gomill/gomill_tests/sgf_tests.py

787 lines
29 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
"""Tests for sgf.py."""
from __future__ import with_statement
from textwrap import dedent
from gomill_tests import gomill_test_support
from gomill import sgf
def make_tests(suite):
suite.addTests(gomill_test_support.make_simple_tests(globals()))
def test_new_sgf_game(tc):
g1 = sgf.Sgf_game(9)
tc.assertEqual(g1.get_size(), 9)
root = g1.get_root()
tc.assertEqual(root.get_raw('FF'), '4')
tc.assertEqual(root.get_raw('GM'), '1')
tc.assertEqual(root.get_raw('SZ'), '9')
tc.assertEqual(root.get_raw_property_map(), {
'FF': ['4'],
'GM': ['1'],
'SZ': ['9'],
'CA': ['UTF-8'],
});
tc.assertEqual(list(root), [])
tc.assertEqual(root.parent, None)
tc.assertIs(root.owner, g1)
def test_sgf_game_from_coarse_game_tree(tc):
class Namespace(object):
pass
coarse_game = Namespace()
coarse_game.sequence = [{'SZ' : ["9"]}, {'B' : ["aa"]}]
coarse_game.children = []
g1 = sgf.Sgf_game.from_coarse_game_tree(coarse_game)
tc.assertEqual(g1.get_size(), 9)
root = g1.get_root()
tc.assertIs(root.get_raw_property_map(), coarse_game.sequence[0])
tc.assertEqual(root.parent, None)
tc.assertIs(root.owner, g1)
tc.assertEqual(len(root), 1)
coarse_game2 = Namespace()
coarse_game2.sequence = [{'SZ' : ["0"]}, {'B' : ["aa"]}]
coarse_game2.children = []
tc.assertRaisesRegexp(ValueError, "size out of range: 0",
sgf.Sgf_game.from_coarse_game_tree, coarse_game2)
def test_sgf_game_from_string(tc):
g1 = sgf.Sgf_game.from_string("(;)")
tc.assertEqual(g1.get_size(), 19)
tc.assertRaisesRegexp(ValueError, "unexpected end of SGF data",
sgf.Sgf_game.from_string, "(;SZ[9]")
g2 = sgf.Sgf_game.from_string("(;SZ[9])")
tc.assertEqual(g2.get_size(), 9)
tc.assertRaisesRegexp(ValueError, "bad SZ property: a",
sgf.Sgf_game.from_string, "(;SZ[a])")
tc.assertRaisesRegexp(ValueError, "size out of range: 27",
sgf.Sgf_game.from_string, "(;SZ[27])")
tc.assertRaisesRegexp(ValueError, "unknown encoding: $",
sgf.Sgf_game.from_string, "(;CA[])")
def test_node(tc):
sgf_game = sgf.Sgf_game.from_string(
r"(;KM[6.5]C[sample\: comment]AB[ai][bh][ee]AE[];B[dg])")
node0 = sgf_game.get_root()
node1 = list(sgf_game.main_sequence_iter())[1]
tc.assertEqual(node0.get_size(), 19)
tc.assertEqual(node0.get_encoding(), "ISO-8859-1")
tc.assertIs(node0.has_property('KM'), True)
tc.assertIs(node0.has_property('XX'), False)
tc.assertIs(node1.has_property('KM'), False)
tc.assertEqual(set(node0.properties()), set(["KM", "C", "AB", "AE"]))
tc.assertEqual(set(node1.properties()), set(["B"]))
tc.assertEqual(node0.get_raw('C'), r"sample\: comment")
tc.assertEqual(node0.get_raw('AB'), "ai")
tc.assertEqual(node0.get_raw('AE'), "")
tc.assertRaises(KeyError, node0.get_raw, 'XX')
tc.assertEqual(node0.get_raw_list('KM'), ['6.5'])
tc.assertEqual(node0.get_raw_list('AB'), ['ai', 'bh', 'ee'])
tc.assertEqual(node0.get_raw_list('AE'), [''])
tc.assertRaises(KeyError, node0.get_raw_list, 'XX')
tc.assertRaises(KeyError, node0.get_raw, 'XX')
def test_property_combination(tc):
sgf_game = sgf.Sgf_game.from_string("(;XX[1]YY[2]XX[3]YY[4])")
node0 = sgf_game.get_root()
tc.assertEqual(node0.get_raw_list("XX"), ["1", "3"])
tc.assertEqual(node0.get_raw_list("YY"), ["2", "4"])
def test_node_get(tc):
sgf_game = sgf.Sgf_game.from_string(dedent(r"""
(;AP[testsuite:0]CA[utf-8]DT[2009-06-06]FF[4]GM[1]KM[7.5]PB[Black engine]
PL[B]PW[White engine][xs]RE[W+R]SZ[9]AB[ai][bh][ee]AW[fd][gc]AE[]BM[2]VW[]
EV[Test
event]
C[123:\)
abc]
YY[none
sense]
;B[dg]KO[]AR[ab:cd][de:fg]FG[515:first move]
LB[ac:lbl][bc:lbl2])
"""))
root = sgf_game.get_root()
node1 = list(sgf_game.main_sequence_iter())[1]
tc.assertRaises(KeyError, root.get, 'XX')
tc.assertEqual(root.get('C'), "123:)\nabc") # Text
tc.assertEqual(root.get('EV'), "Test event") # Simpletext
tc.assertEqual(root.get('BM'), 2) # Double
tc.assertEqual(root.get('YY'), "none\nsense") # unknown (Text)
tc.assertIs(node1.get('KO'), True) # None
tc.assertEqual(root.get('KM'), 7.5) # Real
tc.assertEqual(root.get('GM'), 1) # Number
tc.assertEqual(root.get('PL'), 'b') # Color
tc.assertEqual(node1.get('B'), (2, 3)) # Point
tc.assertEqual(root.get('AB'),
set([(0, 0), (1, 1), (4, 4)])) # List of Point
tc.assertEqual(root.get('VW'), set()) # Empty elist
tc.assertEqual(root.get('AP'), ("testsuite", "0")) # Application
tc.assertEqual(node1.get('AR'),
[((7, 0), (5, 2)), ((4, 3), (2, 5))]) # Arrow
tc.assertEqual(node1.get('FG'), (515, "first move")) # Figure
tc.assertEqual(node1.get('LB'),
[((6, 0), "lbl"), ((6, 1), "lbl2")]) # Label
# Check we (leniently) treat lists like elists on read
tc.assertEqual(root.get('AE'), set())
tc.assertRaisesRegexp(ValueError, "multiple values", root.get, 'PW')
def test_text_values(tc):
def check(s):
sgf_game = sgf.Sgf_game.from_string(s)
return sgf_game.get_root().get("C")
# Round-trip check of Text values through tokeniser, parser, and
# text_value().
tc.assertEqual(check(r"(;C[abc]KO[])"), r"abc")
tc.assertEqual(check(r"(;C[a\\bc]KO[])"), r"a\bc")
tc.assertEqual(check(r"(;C[a\\bc\]KO[])"), r"a\bc]KO[")
tc.assertEqual(check(r"(;C[abc\\]KO[])"), r"abc" + "\\")
tc.assertEqual(check(r"(;C[abc\\\]KO[])"), r"abc\]KO[")
tc.assertEqual(check(r"(;C[abc\\\\]KO[])"), r"abc" + "\\\\")
tc.assertEqual(check(r"(;C[abc\\\\\]KO[])"), r"abc\\]KO[")
tc.assertEqual(check(r"(;C[xxx :\) yyy]KO[])"), r"xxx :) yyy")
tc.assertEqual(check("(;C[ab\\\nc])"), "abc")
tc.assertEqual(check("(;C[ab\nc])"), "ab\nc")
SAMPLE_SGF = """\
(;AP[testsuite:0]CA[utf-8]DT[2009-06-06]FF[4]GM[1]KM[7.5]PB[Black engine]
PL[B]PW[White engine]RE[W+R]SZ[9]AB[ai][bh][ee]AW[fc][gc];B[dg];W[ef]C[comment
on two lines];B[];W[tt]C[Final comment])
"""
SAMPLE_SGF_VAR = """\
(;AP[testsuite:0]CA[utf-8]DT[2009-06-06]FF[4]GM[1]KM[7.5]PB[Black engine]
PL[B]RE[W+R]SZ[9]AB[ai][bh][ee]AW[fd][gc]VW[]
;B[dg]
;W[ef]C[comment
on two lines]
;B[]
;C[Nonfinal comment]VW[aa:bb]
(;B[ia];W[ib];B[ic])
(;B[ib];W[ic]
(;B[id])
(;B[ie])
))
"""
def test_node_string(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF)
node = sgf_game.get_root()
tc.assertMultiLineEqual(str(node), dedent("""\
AB[ai][bh][ee]
AP[testsuite:0]
AW[fc][gc]
CA[utf-8]
DT[2009-06-06]
FF[4]
GM[1]
KM[7.5]
PB[Black engine]
PL[B]
PW[White engine]
RE[W+R]
SZ[9]
"""))
def test_node_get_move(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF)
nodes = list(sgf_game.main_sequence_iter())
tc.assertEqual(nodes[0].get_move(), (None, None))
tc.assertEqual(nodes[1].get_move(), ('b', (2, 3)))
tc.assertEqual(nodes[2].get_move(), ('w', (3, 4)))
tc.assertEqual(nodes[3].get_move(), ('b', None))
tc.assertEqual(nodes[4].get_move(), ('w', None))
def test_node_get_setup_stones(tc):
sgf_game = sgf.Sgf_game.from_string(
r"(;KM[6.5]SZ[9]C[sample\: comment]AB[ai][bh][ee]AE[bb];B[dg])")
node0 = sgf_game.get_root()
node1 = list(sgf_game.main_sequence_iter())[1]
tc.assertIs(node0.has_setup_stones(), True)
tc.assertIs(node1.has_setup_stones(), False)
tc.assertEqual(node0.get_setup_stones(),
(set([(0, 0), (1, 1), (4, 4)]), set(), set([(7, 1)])))
tc.assertEqual(node1.get_setup_stones(),
(set(), set(), set()))
def test_sgf_game(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
nodes = list(sgf_game.main_sequence_iter())
tc.assertEqual(sgf_game.get_size(), 9)
tc.assertEqual(sgf_game.get_komi(), 7.5)
tc.assertIs(sgf_game.get_handicap(), None)
tc.assertEqual(sgf_game.get_player_name('b'), "Black engine")
tc.assertIs(sgf_game.get_player_name('w'), None)
tc.assertEqual(sgf_game.get_winner(), 'w')
tc.assertEqual(nodes[2].get('C'), "comment\non two lines")
tc.assertEqual(nodes[4].get('C'), "Nonfinal comment")
g2 = sgf.Sgf_game.from_string("(;)")
tc.assertEqual(g2.get_size(), 19)
tc.assertEqual(g2.get_komi(), 0.0)
tc.assertIs(g2.get_handicap(), None)
tc.assertIs(g2.get_player_name('b'), None)
tc.assertIs(g2.get_player_name('w'), None)
tc.assertEqual(g2.get_winner(), None)
def test_tree_view(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
root = sgf_game.get_root()
tc.assertIsInstance(root, sgf.Tree_node)
tc.assertIs(root.parent, None)
tc.assertIs(root.owner, sgf_game)
tc.assertEqual(len(root), 1)
tc.assertEqual(root[0].get_raw('B'), "dg")
tc.assertTrue(root)
tc.assertEqual(root.index(root[0]), 0)
branchnode = root[0][0][0][0]
tc.assertIsInstance(branchnode, sgf.Tree_node)
tc.assertIs(branchnode.parent, root[0][0][0])
tc.assertIs(branchnode.owner, sgf_game)
tc.assertEqual(len(branchnode), 2)
tc.assertIs(branchnode[1], branchnode[-1])
tc.assertEqual(branchnode[:1], [branchnode[0]])
tc.assertEqual([node for node in branchnode],
[branchnode[0], branchnode[1]])
with tc.assertRaises(IndexError):
branchnode[2]
tc.assertEqual(branchnode[0].get_raw('B'), "ia")
tc.assertEqual(branchnode[1].get_raw('B'), "ib")
tc.assertEqual(branchnode.index(branchnode[0]), 0)
tc.assertEqual(branchnode.index(branchnode[1]), 1)
tc.assertEqual(len(branchnode[1][0]), 2)
leaf = branchnode[1][0][1]
tc.assertIs(leaf.parent, branchnode[1][0])
tc.assertEqual(len(leaf), 0)
tc.assertFalse(leaf)
tc.assertIs(sgf_game.get_last_node(), root[0][0][0][0][0][0][0])
# check nothing breaks when first retrieval is by index
game2 = sgf.Sgf_game.from_string(SAMPLE_SGF)
root2 = game2.get_root()
tc.assertEqual(root2[0].get_raw('B'), "dg")
def test_serialise(tc):
# Doesn't cover transcoding
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
serialised = sgf_game.serialise()
tc.assertEqual(serialised, dedent("""\
(;FF[4]AB[ai][bh][ee]AP[testsuite:0]AW[fd][gc]CA[utf-8]DT[2009-06-06]GM[1]
KM[7.5]PB[Black engine]PL[B]RE[W+R]SZ[9]VW[];B[dg];C[comment
on two lines]W[ef]
;B[];C[Nonfinal comment]VW[aa:bb](;B[ia];W[ib];B[ic])(;B[ib];W[ic](;B[id])(;
B[ie])))
"""))
sgf_game2 = sgf.Sgf_game.from_string(serialised)
tc.assertEqual(map(str, sgf_game.get_main_sequence()),
map(str, sgf_game2.get_main_sequence()))
def test_serialise_wrap(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
serialised = sgf_game.serialise(wrap=None)
tc.assertEqual(serialised, dedent("""\
(;FF[4]AB[ai][bh][ee]AP[testsuite:0]AW[fd][gc]CA[utf-8]DT[2009-06-06]GM[1]KM[7.5]PB[Black engine]PL[B]RE[W+R]SZ[9]VW[];B[dg];C[comment
on two lines]W[ef];B[];C[Nonfinal comment]VW[aa:bb](;B[ia];W[ib];B[ic])(;B[ib];W[ic](;B[id])(;B[ie])))
"""))
sgf_game2 = sgf.Sgf_game.from_string(serialised)
tc.assertEqual(map(str, sgf_game.get_main_sequence()),
map(str, sgf_game2.get_main_sequence()))
def test_encoding(tc):
g1 = sgf.Sgf_game(19)
tc.assertEqual(g1.get_charset(), "UTF-8")
root = g1.get_root()
tc.assertEqual(root.get_encoding(), "UTF-8")
root.set("C", "£")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "£")
tc.assertEqual(g1.serialise(), dedent("""\
(;FF[4]C[£]CA[UTF-8]GM[1]SZ[19])
"""))
g2 = sgf.Sgf_game(19, encoding="iso-8859-1")
tc.assertEqual(g2.get_charset(), "ISO-8859-1")
root = g2.get_root()
tc.assertEqual(root.get_encoding(), "ISO-8859-1")
root.set("C", "£")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "\xa3")
tc.assertEqual(g2.serialise(), dedent("""\
(;FF[4]C[\xa3]CA[ISO-8859-1]GM[1]SZ[19])
"""))
tc.assertRaisesRegexp(ValueError, "unknown encoding: unknownencoding",
sgf.Sgf_game, 19, "unknownencoding")
def test_loaded_sgf_game_encoding(tc):
g1 = sgf.Sgf_game.from_string("""
(;FF[4]C[£]CA[utf-8]GM[1]SZ[19])
""")
tc.assertEqual(g1.get_charset(), "UTF-8")
root = g1.get_root()
tc.assertEqual(root.get_encoding(), "UTF-8")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "£")
tc.assertEqual(g1.serialise(), dedent("""\
(;FF[4]C[£]CA[utf-8]GM[1]SZ[19])
"""))
g2 = sgf.Sgf_game.from_string("""
(;FF[4]C[\xa3]CA[iso-8859-1]GM[1]SZ[19])
""")
tc.assertEqual(g2.get_charset(), "ISO-8859-1")
root = g2.get_root()
tc.assertEqual(root.get_encoding(), "ISO-8859-1")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "\xa3")
tc.assertEqual(g2.serialise(), dedent("""\
(;FF[4]C[\xa3]CA[iso-8859-1]GM[1]SZ[19])
"""))
g3 = sgf.Sgf_game.from_string("""
(;FF[4]C[\xa3]GM[1]SZ[19])
""")
tc.assertEqual(g3.get_charset(), "ISO-8859-1")
root = g3.get_root()
tc.assertEqual(root.get_encoding(), "ISO-8859-1")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "\xa3")
tc.assertEqual(g3.serialise(), dedent("""\
(;FF[4]C[\xa3]GM[1]SZ[19])
"""))
# This is invalidly encoded. get() notices, but serialise() doesn't care.
g4 = sgf.Sgf_game.from_string("""
(;FF[4]C[\xa3]CA[utf-8]GM[1]SZ[19])
""")
tc.assertEqual(g4.get_charset(), "UTF-8")
root = g4.get_root()
tc.assertEqual(root.get_encoding(), "UTF-8")
tc.assertRaises(UnicodeDecodeError, root.get, "C")
tc.assertEqual(root.get_raw("C"), "\xa3")
tc.assertEqual(g4.serialise(), dedent("""\
(;FF[4]C[\xa3]CA[utf-8]GM[1]SZ[19])
"""))
tc.assertRaisesRegexp(
ValueError, "unknown encoding: unknownencoding",
sgf.Sgf_game.from_string, """
(;FF[4]CA[unknownencoding]GM[1]SZ[19])
""")
def test_override_encoding(tc):
g1 = sgf.Sgf_game.from_string("""
(;FF[4]C[£]CA[iso-8859-1]GM[1]SZ[19])
""", override_encoding="utf-8")
root = g1.get_root()
tc.assertEqual(root.get_encoding(), "UTF-8")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "£")
tc.assertEqual(g1.serialise(), dedent("""\
(;FF[4]C[£]CA[UTF-8]GM[1]SZ[19])
"""))
g2 = sgf.Sgf_game.from_string("""
(;FF[4]C[\xa3]CA[utf-8]GM[1]SZ[19])
""", override_encoding="iso-8859-1")
root = g2.get_root()
tc.assertEqual(root.get_encoding(), "ISO-8859-1")
tc.assertEqual(root.get("C"), "£")
tc.assertEqual(root.get_raw("C"), "\xa3")
tc.assertEqual(g2.serialise(), dedent("""\
(;FF[4]C[\xa3]CA[ISO-8859-1]GM[1]SZ[19])
"""))
def test_serialise_transcoding(tc):
g1 = sgf.Sgf_game.from_string("""
(;FF[4]C[£]CA[utf-8]GM[1]SZ[19])
""")
tc.assertEqual(g1.serialise(), dedent("""\
(;FF[4]C[£]CA[utf-8]GM[1]SZ[19])
"""))
g1.get_root().set("CA", "latin-1")
tc.assertEqual(g1.serialise(), dedent("""\
(;FF[4]C[\xa3]CA[latin-1]GM[1]SZ[19])
"""))
g1.get_root().set("CA", "unknown")
tc.assertRaisesRegexp(ValueError, "unsupported charset: \['unknown']",
g1.serialise)
# improperly-encoded from the start
g2 = sgf.Sgf_game.from_string("""
(;FF[4]C[£]CA[ascii]GM[1]SZ[19])
""")
tc.assertEqual(g2.serialise(), dedent("""\
(;FF[4]C[£]CA[ascii]GM[1]SZ[19])
"""))
g2.get_root().set("CA", "utf-8")
tc.assertRaises(UnicodeDecodeError, g2.serialise)
g3 = sgf.Sgf_game.from_string("""
(;FF[4]C[Δ]CA[utf-8]GM[1]SZ[19])
""")
g3.get_root().unset("CA")
tc.assertRaises(UnicodeEncodeError, g3.serialise)
def test_tree_mutation(tc):
sgf_game = sgf.Sgf_game(9)
root = sgf_game.get_root()
n1 = root.new_child()
n1.set("N", "n1")
n2 = root.new_child()
n2.set("N", "n2")
n3 = n1.new_child()
n3.set("N", "n3")
n4 = root.new_child(1)
n4.set("N", "n4")
tc.assertEqual(
sgf_game.serialise(),
"(;FF[4]CA[UTF-8]GM[1]SZ[9](;N[n1];N[n3])(;N[n4])(;N[n2]))\n")
tc.assertEqual(
[node.get_raw_property_map() for node in sgf_game.main_sequence_iter()],
[node.get_raw_property_map() for node in root, root[0], n3])
tc.assertIs(sgf_game.get_last_node(), n3)
n1.delete()
tc.assertEqual(
sgf_game.serialise(),
"(;FF[4]CA[UTF-8]GM[1]SZ[9](;N[n4])(;N[n2]))\n")
tc.assertRaises(ValueError, root.delete)
def test_tree_mutation_from_coarse_game(tc):
sgf_game = sgf.Sgf_game.from_string("(;SZ[9](;N[n1];N[n3])(;N[n2]))")
root = sgf_game.get_root()
n4 = root.new_child()
n4.set("N", "n4")
n3 = root[0][0]
tc.assertEqual(n3.get("N"), "n3")
n5 = n3.new_child()
n5.set("N", "n5")
tc.assertEqual(sgf_game.serialise(),
"(;SZ[9](;N[n1];N[n3];N[n5])(;N[n2])(;N[n4]))\n")
tc.assertEqual(
[node.get_raw_property_map() for node in sgf_game.main_sequence_iter()],
[node.get_raw_property_map() for node in root, root[0], n3, n5])
tc.assertIs(sgf_game.get_last_node(), n5)
n3.delete()
tc.assertEqual(sgf_game.serialise(),
"(;SZ[9](;N[n1])(;N[n2])(;N[n4]))\n")
tc.assertRaises(ValueError, root.delete)
def test_reparent(tc):
g1 = sgf.Sgf_game.from_string("(;SZ[9](;N[n1];N[n3])(;N[n2]))")
root = g1.get_root()
# Test with unexpanded root
tc.assertRaisesRegexp(ValueError, "would create a loop",
root.reparent, root)
n1 = root[0]
n2 = root[1]
n3 = root[0][0]
tc.assertEqual(n1.get("N"), "n1")
tc.assertEqual(n2.get("N"), "n2")
tc.assertEqual(n3.get("N"), "n3")
n3.reparent(n2)
tc.assertEqual(g1.serialise(), "(;SZ[9](;N[n1])(;N[n2];N[n3]))\n")
n3.reparent(n2)
tc.assertEqual(g1.serialise(), "(;SZ[9](;N[n1])(;N[n2];N[n3]))\n")
tc.assertRaisesRegexp(ValueError, "would create a loop",
root.reparent, n3)
tc.assertRaisesRegexp(ValueError, "would create a loop",
n3.reparent, n3)
g2 = sgf.Sgf_game(9)
tc.assertRaisesRegexp(
ValueError, "new parent doesn't belong to the same game",
n3.reparent, g2.get_root())
def test_reparent_index(tc):
g1 = sgf.Sgf_game.from_string("(;SZ[9](;N[n1];N[n3])(;N[n2]))")
root = g1.get_root()
n1 = root[0]
n2 = root[1]
n3 = root[0][0]
tc.assertEqual(n1.get("N"), "n1")
tc.assertEqual(n2.get("N"), "n2")
tc.assertEqual(n3.get("N"), "n3")
n3.reparent(root, index=1)
tc.assertEqual(g1.serialise(), "(;SZ[9](;N[n1])(;N[n3])(;N[n2]))\n")
n3.reparent(root, index=1)
tc.assertEqual(g1.serialise(), "(;SZ[9](;N[n1])(;N[n3])(;N[n2]))\n")
n3.reparent(root, index=2)
tc.assertEqual(g1.serialise(), "(;SZ[9](;N[n1])(;N[n2])(;N[n3]))\n")
def test_extend_main_sequence(tc):
g1 = sgf.Sgf_game(9)
for i in xrange(6):
g1.extend_main_sequence().set("N", "e%d" % i)
tc.assertEqual(
g1.serialise(),
"(;FF[4]CA[UTF-8]GM[1]SZ[9];N[e0];N[e1];N[e2];N[e3];N[e4];N[e5])\n")
g2 = sgf.Sgf_game.from_string("(;SZ[9](;N[n1];N[n3])(;N[n2]))")
for i in xrange(6):
g2.extend_main_sequence().set("N", "e%d" % i)
tc.assertEqual(
g2.serialise(),
"(;SZ[9](;N[n1];N[n3];N[e0];N[e1];N[e2];N[e3];N[e4];N[e5])(;N[n2]))\n")
def test_get_sequence_above(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
root = sgf_game.get_root()
branchnode = root[0][0][0][0]
leaf = branchnode[1][0][1]
tc.assertEqual(sgf_game.get_sequence_above(root), [])
tc.assertEqual(sgf_game.get_sequence_above(branchnode),
[root, root[0], root[0][0], root[0][0][0]])
tc.assertEqual(sgf_game.get_sequence_above(leaf),
[root, root[0], root[0][0], root[0][0][0],
branchnode, branchnode[1], branchnode[1][0]])
sgf_game2 = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
tc.assertRaisesRegexp(ValueError, "node doesn't belong to this game",
sgf_game2.get_sequence_above, leaf)
def test_get_main_sequence_below(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
root = sgf_game.get_root()
branchnode = root[0][0][0][0]
leaf = branchnode[1][0][1]
tc.assertEqual(sgf_game.get_main_sequence_below(leaf), [])
tc.assertEqual(sgf_game.get_main_sequence_below(branchnode),
[branchnode[0], branchnode[0][0], branchnode[0][0][0]])
tc.assertEqual(sgf_game.get_main_sequence_below(root),
[root[0], root[0][0], root[0][0][0], branchnode,
branchnode[0], branchnode[0][0], branchnode[0][0][0]])
sgf_game2 = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
tc.assertRaisesRegexp(ValueError, "node doesn't belong to this game",
sgf_game2.get_main_sequence_below, branchnode)
def test_main_sequence(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
root = sgf_game.get_root()
nodes = list(sgf_game.main_sequence_iter())
tc.assertEqual(len(nodes), 8)
tc.assertIs(root.get_raw_property_map(),
nodes[0].get_raw_property_map())
# Check that main_sequence_iter() optimisation has been used.
# (Have to call this before making the tree expand.)
with tc.assertRaises(AttributeError):
nodes[1].parent
tree_nodes = sgf_game.get_main_sequence()
tc.assertEqual(len(tree_nodes), 8)
tc.assertIs(root.get_raw_property_map(),
tree_nodes[0].get_raw_property_map())
tc.assertIs(tree_nodes[0], root)
tc.assertIs(tree_nodes[2].parent, tree_nodes[1])
tc.assertIs(sgf_game.get_last_node(), tree_nodes[-1])
tree_node = root
for node in nodes:
tc.assertIs(tree_node.get_raw_property_map(),
node.get_raw_property_map())
if tree_node:
tree_node = tree_node[0]
def test_find(tc):
sgf_game = sgf.Sgf_game.from_string(SAMPLE_SGF_VAR)
root = sgf_game.get_root()
branchnode = root[0][0][0][0]
leaf = branchnode[1][0][1]
tc.assertEqual(root.get("VW"), set())
tc.assertIs(root.find("VW"), root)
tc.assertRaises(KeyError, root[0].get, "VW")
tc.assertEqual(root[0].find_property("VW"), set())
tc.assertIs(root[0].find("VW"), root)
tc.assertEqual(branchnode.get("VW"),
set([(7, 0), (7, 1), (8, 0), (8, 1)]))
tc.assertIs(branchnode.find("VW"), branchnode)
tc.assertEqual(branchnode.find_property("VW"),
set([(7, 0), (7, 1), (8, 0), (8, 1)]))
tc.assertRaises(KeyError, leaf.get, "VW")
tc.assertIs(leaf.find("VW"), branchnode)
tc.assertEqual(leaf.find_property("VW"),
set([(7, 0), (7, 1), (8, 0), (8, 1)]))
tc.assertIs(leaf.find("XX"), None)
tc.assertRaises(KeyError, leaf.find_property, "XX")
def test_node_set_raw(tc):
sgf_game = sgf.Sgf_game.from_string(dedent(r"""
(;AP[testsuite:0]CA[utf-8]DT[2009-06-06]FF[4]GM[1]KM[7.5]
PB[Black engine]PW[White engine]RE[W+R]SZ[9]
AB[ai][bh][ee]AW[fd][gc]BM[2]VW[]
PL[B]
C[123abc]
;B[dg]C[first move])
"""))
root = sgf_game.get_root()
tc.assertEqual(root.get_raw('RE'), "W+R")
root.set_raw('RE', "W+2.5")
tc.assertEqual(root.get_raw('RE'), "W+2.5")
tc.assertRaises(KeyError, root.get_raw, 'XX')
root.set_raw('XX', "xyz")
tc.assertEqual(root.get_raw('XX'), "xyz")
root.set_raw_list('XX', ("abc", "def"))
tc.assertEqual(root.get_raw('XX'), "abc")
tc.assertEqual(root.get_raw_list('XX'), ["abc", "def"])
tc.assertRaisesRegexp(ValueError, "empty property list",
root.set_raw_list, 'B', [])
values = ["123", "456"]
root.set_raw_list('YY', values)
tc.assertEqual(root.get_raw_list('YY'), ["123", "456"])
values.append("789")
tc.assertEqual(root.get_raw_list('YY'), ["123", "456"])
tc.assertRaisesRegexp(ValueError, "ill-formed property identifier",
root.set_raw, 'Black', "aa")
tc.assertRaisesRegexp(ValueError, "ill-formed property identifier",
root.set_raw_list, 'Black', ["aa"])
root.set_raw('C', "foo\\]bar")
tc.assertEqual(root.get_raw('C'), "foo\\]bar")
root.set_raw('C', "abc\\\\")
tc.assertEqual(root.get_raw('C'), "abc\\\\")
tc.assertRaisesRegexp(ValueError, "ill-formed raw property value",
root.set_raw, 'C', "foo]bar")
tc.assertRaisesRegexp(ValueError, "ill-formed raw property value",
root.set_raw, 'C', "abc\\")
tc.assertRaisesRegexp(ValueError, "ill-formed raw property value",
root.set_raw_list, 'C', ["abc", "de]f"])
root.set_raw('C', "foo\\]bar\\\nbaz")
tc.assertEqual(root.get('C'), "foo]barbaz")
def test_node_aliasing(tc):
# Check that node objects retrieved by different means use the same
# property map.
sgf_game = sgf.Sgf_game.from_string(dedent(r"""
(;C[root];C[node 1])
"""))
root = sgf_game.get_root()
plain_node = list(sgf_game.main_sequence_iter())[1]
tree_node = root[0]
# Check the main_sequence_iter() optimisation was used, otherwise this test
# isn't checking what it's supposed to.
tc.assertIsNot(tree_node, plain_node)
tc.assertIs(tree_node.__class__, sgf.Tree_node)
tc.assertIs(plain_node.__class__, sgf.Node)
tc.assertEqual(tree_node.get_raw('C'), "node 1")
tree_node.set_raw('C', r"test\value")
tc.assertEqual(tree_node.get_raw('C'), r"test\value")
tc.assertEqual(plain_node.get_raw('C'), r"test\value")
plain_node.set_raw_list('XX', ["1", "2", "3"])
tc.assertEqual(tree_node.get_raw_list('XX'), ["1", "2", "3"])
def test_node_set(tc):
sgf_game = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9])")
root = sgf_game.get_root()
root.set("KO", True)
root.set("KM", 0.5)
root.set('DD', [(3, 4), (5, 6)])
root.set('AB', set([(0, 0), (1, 1), (4, 4)]))
root.set('TW', set())
root.set('XX', "nonsense [none]sense more n\\onsens\\e")
tc.assertEqual(sgf_game.serialise(), dedent("""\
(;FF[4]AB[ai][bh][ee]DD[ef][gd]GM[1]KM[0.5]KO[]SZ[9]TW[]
XX[nonsense [none\\]sense more n\\\\onsens\\\\e])
"""))
def test_node_unset(tc):
sgf_game = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9]HA[3])")
root = sgf_game.get_root()
tc.assertEqual(root.get('HA'), 3)
root.unset('HA')
tc.assertRaises(KeyError, root.unset, 'PL')
tc.assertEqual(sgf_game.serialise(),
"(;FF[4]GM[1]SZ[9])\n")
def test_set_and_unset_size(tc):
g1 = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9]HA[3])")
root1 = g1.get_root()
tc.assertRaisesRegexp(ValueError, "changing size is not permitted",
root1.set, "SZ", 19)
root1.set("SZ", 9)
tc.assertRaisesRegexp(ValueError, "changing size is not permitted",
root1.unset, "SZ")
g2 = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[19]HA[3])")
root2 = g2.get_root()
root2.unset("SZ")
root2.set("SZ", 19)
def test_set_and_unset_charset(tc):
g1 = sgf.Sgf_game.from_string("(;FF[4]CA[utf-8]GM[1]SZ[9]HA[3])")
tc.assertEqual(g1.get_charset(), "UTF-8")
root1 = g1.get_root()
root1.unset("CA")
tc.assertEqual(g1.get_charset(), "ISO-8859-1")
root1.set("CA", "iso-8859-1")
tc.assertEqual(g1.get_charset(), "ISO-8859-1")
root1.set("CA", "ascii")
tc.assertEqual(g1.get_charset(), "ASCII")
root1.set("CA", "unknownencoding")
tc.assertRaisesRegexp(ValueError,
"no codec available for CA unknownencoding",
g1.get_charset)
def test_node_set_move(tc):
sgf_game = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9];B[aa];B[bb])")
root, n1, n2 = sgf_game.get_main_sequence()
tc.assertEqual(root.get_move(), (None, None))
root.set_move('b', (1, 1))
n1.set_move('w', (1, 2))
n2.set_move('b', None)
tc.assertEqual(root.get('B'), (1, 1))
tc.assertRaises(KeyError, root.get, 'W')
tc.assertEqual(n1.get('W'), (1, 2))
tc.assertRaises(KeyError, n1.get, 'B')
tc.assertEqual(n2.get('B'), None)
tc.assertRaises(KeyError, n2.get, 'W')
def test_node_setup_stones(tc):
sgf_game = sgf.Sgf_game.from_string("(;FF[4]GM[1]SZ[9]AW[aa:bb])")
root = sgf_game.get_root()
root.set_setup_stones(
[(1, 2), (3, 4)],
set(),
[(1, 3), (4, 5)],
)
tc.assertEqual(root.get('AB'), set([(1, 2), (3, 4)]))
tc.assertRaises(KeyError, root.get, 'AW')
tc.assertEqual(root.get('AE'), set([(1, 3), (4, 5)]))
def test_add_comment_text(tc):
sgf_game = sgf.Sgf_game(9)
root = sgf_game.get_root()
root.add_comment_text("hello\nworld")
tc.assertEqual(root.get('C'), "hello\nworld")
root.add_comment_text("hello\naga]in")
tc.assertEqual(root.get('C'), "hello\nworld\n\nhello\naga]in")