test_graph6.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from io import BytesIO
  2. import pytest
  3. import networkx as nx
  4. import networkx.readwrite.graph6 as g6
  5. from networkx.utils import edges_equal, nodes_equal
  6. def test_from_graph6_invariant_to_trailing_newline():
  7. """See gh-7557"""
  8. G = nx.from_graph6_bytes(b">>graph6<<P~~~~~~~~~~~~~~~~~~~~~~{\n")
  9. H = nx.from_graph6_bytes(b">>graph6<<P~~~~~~~~~~~~~~~~~~~~~~{")
  10. assert nx.utils.graphs_equal(G, H)
  11. def test_from_graph6_raises_header_newline():
  12. """graph6 headers must not be followed by a newline. See gh-7557."""
  13. with pytest.raises(nx.NetworkXError):
  14. G = nx.from_graph6_bytes(b">>graph6<<\nP~~~~~~~~~~~~~~~~~~~~~~{")
  15. class TestGraph6Utils:
  16. def test_n_data_n_conversion(self):
  17. for i in [0, 1, 42, 62, 63, 64, 258047, 258048, 7744773, 68719476735]:
  18. assert g6.data_to_n(g6.n_to_data(i))[0] == i
  19. assert g6.data_to_n(g6.n_to_data(i))[1] == []
  20. assert g6.data_to_n(g6.n_to_data(i) + [42, 43])[1] == [42, 43]
  21. class TestFromGraph6Bytes:
  22. def test_from_graph6_bytes(self):
  23. data = b"DF{"
  24. G = nx.from_graph6_bytes(data)
  25. assert nodes_equal(G.nodes(), [0, 1, 2, 3, 4])
  26. assert edges_equal(
  27. G.edges(), [(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
  28. )
  29. def test_read_equals_from_bytes(self):
  30. data = b"DF{"
  31. G = nx.from_graph6_bytes(data)
  32. fh = BytesIO(data)
  33. Gin = nx.read_graph6(fh)
  34. assert nodes_equal(G.nodes(), Gin.nodes())
  35. assert edges_equal(G.edges(), Gin.edges())
  36. class TestReadGraph6:
  37. def test_read_many_graph6(self):
  38. """Test for reading many graphs from a file into a list."""
  39. data = b"DF{\nD`{\nDqK\nD~{\n"
  40. fh = BytesIO(data)
  41. glist = nx.read_graph6(fh)
  42. assert len(glist) == 4
  43. for G in glist:
  44. assert sorted(G) == list(range(5))
  45. class TestWriteGraph6:
  46. """Unit tests for writing a graph to a file in graph6 format."""
  47. def test_null_graph(self):
  48. result = BytesIO()
  49. nx.write_graph6(nx.null_graph(), result)
  50. assert result.getvalue() == b">>graph6<<?\n"
  51. def test_trivial_graph(self):
  52. result = BytesIO()
  53. nx.write_graph6(nx.trivial_graph(), result)
  54. assert result.getvalue() == b">>graph6<<@\n"
  55. def test_complete_graph(self):
  56. result = BytesIO()
  57. nx.write_graph6(nx.complete_graph(4), result)
  58. assert result.getvalue() == b">>graph6<<C~\n"
  59. def test_large_complete_graph(self):
  60. result = BytesIO()
  61. nx.write_graph6(nx.complete_graph(67), result, header=False)
  62. assert result.getvalue() == b"~?@B" + b"~" * 368 + b"w\n"
  63. def test_no_header(self):
  64. result = BytesIO()
  65. nx.write_graph6(nx.complete_graph(4), result, header=False)
  66. assert result.getvalue() == b"C~\n"
  67. def test_complete_bipartite_graph(self):
  68. result = BytesIO()
  69. G = nx.complete_bipartite_graph(6, 9)
  70. nx.write_graph6(G, result, header=False)
  71. # The expected encoding here was verified by Sage.
  72. assert result.getvalue() == b"N??F~z{~Fw^_~?~?^_?\n"
  73. @pytest.mark.parametrize("G", (nx.MultiGraph(), nx.DiGraph()))
  74. def test_no_directed_or_multi_graphs(self, G):
  75. with pytest.raises(nx.NetworkXNotImplemented):
  76. nx.write_graph6(G, BytesIO())
  77. def test_length(self):
  78. for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
  79. g = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
  80. gstr = BytesIO()
  81. nx.write_graph6(g, gstr, header=False)
  82. # Strip the trailing newline.
  83. gstr = gstr.getvalue().rstrip()
  84. assert len(gstr) == ((i - 1) * i // 2 + 5) // 6 + (1 if i < 63 else 4)
  85. def test_roundtrip(self):
  86. for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
  87. G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
  88. f = BytesIO()
  89. nx.write_graph6(G, f)
  90. f.seek(0)
  91. H = nx.read_graph6(f)
  92. assert nodes_equal(G.nodes(), H.nodes())
  93. assert edges_equal(G.edges(), H.edges())
  94. def test_write_path(self, tmp_path):
  95. with open(tmp_path / "test.g6", "w+b") as f:
  96. g6.write_graph6_file(nx.null_graph(), f)
  97. f.seek(0)
  98. assert f.read() == b">>graph6<<?\n"
  99. @pytest.mark.parametrize("edge", ((0, 1), (1, 2), (1, 42)))
  100. def test_relabeling(self, edge):
  101. G = nx.Graph([edge])
  102. f = BytesIO()
  103. nx.write_graph6(G, f)
  104. f.seek(0)
  105. assert f.read() == b">>graph6<<A_\n"
  106. class TestToGraph6Bytes:
  107. def test_null_graph(self):
  108. G = nx.null_graph()
  109. assert g6.to_graph6_bytes(G) == b">>graph6<<?\n"
  110. def test_trivial_graph(self):
  111. G = nx.trivial_graph()
  112. assert g6.to_graph6_bytes(G) == b">>graph6<<@\n"
  113. def test_complete_graph(self):
  114. assert g6.to_graph6_bytes(nx.complete_graph(4)) == b">>graph6<<C~\n"
  115. def test_large_complete_graph(self):
  116. G = nx.complete_graph(67)
  117. assert g6.to_graph6_bytes(G, header=False) == b"~?@B" + b"~" * 368 + b"w\n"
  118. def test_no_header(self):
  119. G = nx.complete_graph(4)
  120. assert g6.to_graph6_bytes(G, header=False) == b"C~\n"
  121. def test_complete_bipartite_graph(self):
  122. G = nx.complete_bipartite_graph(6, 9)
  123. assert g6.to_graph6_bytes(G, header=False) == b"N??F~z{~Fw^_~?~?^_?\n"
  124. @pytest.mark.parametrize("G", (nx.MultiGraph(), nx.DiGraph()))
  125. def test_no_directed_or_multi_graphs(self, G):
  126. with pytest.raises(nx.NetworkXNotImplemented):
  127. g6.to_graph6_bytes(G)
  128. def test_length(self):
  129. for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
  130. G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
  131. # Strip the trailing newline.
  132. gstr = g6.to_graph6_bytes(G, header=False).rstrip()
  133. assert len(gstr) == ((i - 1) * i // 2 + 5) // 6 + (1 if i < 63 else 4)
  134. def test_roundtrip(self):
  135. for i in list(range(13)) + [31, 47, 62, 63, 64, 72]:
  136. G = nx.random_graphs.gnm_random_graph(i, i * i // 4, seed=i)
  137. data = g6.to_graph6_bytes(G)
  138. H = nx.from_graph6_bytes(data.rstrip())
  139. assert nodes_equal(G.nodes(), H.nodes())
  140. assert edges_equal(G.edges(), H.edges())
  141. @pytest.mark.parametrize("edge", ((0, 1), (1, 2), (1, 42)))
  142. def test_relabeling(self, edge):
  143. G = nx.Graph([edge])
  144. assert g6.to_graph6_bytes(G) == b">>graph6<<A_\n"