Convert tests from unittest to pytest

Signed-off-by: Dan Yeaw <dan@yeaw.me>
This commit is contained in:
Dan Yeaw 2018-12-15 23:19:42 -05:00
parent 82f64b8362
commit 9d9c48375e
No known key found for this signature in database
GPG Key ID: 77A923EF537B61A4
21 changed files with 2057 additions and 2487 deletions

View File

@ -6,6 +6,9 @@ from __future__ import print_function
import threading
from builtins import object
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
DEBUG_ASYNC = False

94
gaphas/tests/conftest.py Normal file
View File

@ -0,0 +1,94 @@
import pytest
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gaphas import state
from gaphas.canvas import Canvas
from gaphas.examples import Box
from gaphas.item import Line
from gaphas.tool import ConnectHandleTool
from gaphas.view import GtkView
class SimpleCanvas(object):
"""Creates a test canvas object.
Adds a view, canvas, and handle connection tool to a test
case. Two boxes and a line are added to the canvas as well.
"""
def __init__(self):
self.canvas = Canvas()
self.box1 = Box()
self.canvas.add(self.box1)
self.box1.matrix.translate(100, 50)
self.box1.width = 40
self.box1.height = 40
self.box1.request_update()
self.box2 = Box()
self.canvas.add(self.box2)
self.box2.matrix.translate(100, 150)
self.box2.width = 50
self.box2.height = 50
self.box2.request_update()
self.line = Line()
self.head = self.line.handles()[0]
self.tail = self.line.handles()[-1]
self.tail.pos = 100, 100
self.canvas.add(self.line)
self.canvas.update_now()
self.view = GtkView()
self.view.canvas = self.canvas
self.win = Gtk.Window()
self.win.add(self.view)
self.view.show()
self.view.update()
self.win.show()
self.tool = ConnectHandleTool(self.view)
@pytest.fixture()
def simple_canvas():
"""Creates a `SimpleCanvas`.
"""
return SimpleCanvas()
@pytest.fixture(scope="module")
def undo_fixture():
undo_list = []
redo_list = []
def undo():
apply_me = list(undo_list)
del undo_list[:]
apply_me.reverse()
for e in apply_me:
state.saveapply(*e)
redo_list[:] = undo_list[:]
del undo_list[:]
def undo_handler(event):
undo_list.append(event)
return undo, undo_handler, undo_list
@pytest.fixture()
def revert_undo(undo_fixture):
state.observers.clear()
state.subscribers.clear()
state.observers.add(state.revert_handler)
state.subscribers.add(undo_fixture[1])
yield
state.observers.remove(state.revert_handler)
state.subscribers.remove(undo_fixture[1])

View File

@ -1,51 +1,48 @@
"""
Generic gaphas item tests.
"""Test aspects for items.
"""
import unittest
import pytest
from gaphas.aspect import *
from gaphas.canvas import Canvas
from gaphas.view import View
class AspectTestCase(unittest.TestCase):
"""
Test aspects for items.
"""
def setUp(self):
class CanvasViewItem(object):
def __init__(self):
self.canvas = Canvas()
self.view = View(self.canvas)
def test_selection_select(self):
"""
Test the Selection role methods
"""
view = self.view
item = Item()
self.canvas.add(item)
selection = Selection(item, view)
assert item not in view.selected_items
selection.select()
assert item in view.selected_items
assert item is view.focused_item
selection.unselect()
assert item not in view.selected_items
assert None is view.focused_item
def test_selection_move(self):
"""
Test the Selection role methods
"""
view = self.view
item = Item()
self.canvas.add(item)
inmotion = InMotion(item, view)
self.assertEqual((1, 0, 0, 1, 0, 0), tuple(item.matrix))
inmotion.start_move((0, 0))
inmotion.move((12, 26))
self.assertEqual((1, 0, 0, 1, 12, 26), tuple(item.matrix))
self.item = Item()
# vim:sw=4:et:ai
@pytest.fixture()
def cvi():
return CanvasViewItem()
def test_selection_select(cvi):
"""Test the Selection role methods.
"""
cvi.canvas.add(cvi.item)
selection = Selection(cvi.item, cvi.view)
assert cvi.item not in cvi.view.selected_items
selection.select()
assert cvi.item in cvi.view.selected_items
assert cvi.item is cvi.view.focused_item
selection.unselect()
assert cvi.item not in cvi.view.selected_items
assert None is cvi.view.focused_item
def test_selection_move(cvi):
"""Test the Selection role methods.
"""
cvi.canvas.add(cvi.item)
in_motion = InMotion(cvi.item, cvi.view)
assert (1, 0, 0, 1, 0, 0) == tuple(cvi.item.matrix)
in_motion.start_move((0, 0))
in_motion.move((12, 26))
assert (1, 0, 0, 1, 12, 26) == tuple(cvi.item.matrix)

View File

@ -1,36 +1,35 @@
import unittest
import cairo
import pytest
from gaphas.canvas import Canvas, ConnectionError
from gaphas.examples import Box
from gaphas.item import Line
class MatricesTestCase(unittest.TestCase):
def test_update_matrices(self):
"""Test updating of matrices"""
c = Canvas()
i = Box()
ii = Box()
c.add(i)
c.add(ii, i)
def test_update_matrices():
"""Test updating of matrices"""
c = Canvas()
i = Box()
ii = Box()
c.add(i)
c.add(ii, i)
i.matrix = (1.0, 0.0, 0.0, 1.0, 5.0, 0.0)
ii.matrix = (1.0, 0.0, 0.0, 1.0, 0.0, 8.0)
i.matrix = (1.0, 0.0, 0.0, 1.0, 5.0, 0.0)
ii.matrix = (1.0, 0.0, 0.0, 1.0, 0.0, 8.0)
updated = c.update_matrices([i])
updated = c.update_matrices([i])
self.assertEqual(i._matrix_i2c, cairo.Matrix(1, 0, 0, 1, 5, 0))
self.assertEqual(ii._matrix_i2c, cairo.Matrix(1, 0, 0, 1, 5, 8))
assert i._matrix_i2c == cairo.Matrix(1, 0, 0, 1, 5, 0)
assert ii._matrix_i2c == cairo.Matrix(1, 0, 0, 1, 5, 8)
def test_reparent(self):
c = Canvas()
b1 = Box()
b2 = Box()
c.add(b1)
c.add(b2, b1)
c.reparent(b2, None)
def test_reparent():
c = Canvas()
b1 = Box()
b2 = Box()
c.add(b1)
c.add(b2, b1)
c.reparent(b2, None)
# fixme: what about multiple constraints for a handle?
@ -41,316 +40,177 @@ def count(i):
return len(list(i))
class CanvasTestCase(unittest.TestCase):
def test_connect_item(self):
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
def test_connect_item():
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 1
# Add the same
with pytest.raises(ConnectionError):
c.connect_item(line, line.handles()[0], b1, b1.ports()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 1
# Add the same
self.assertRaises(
ConnectionError, c.connect_item, line, line.handles()[0], b1, b1.ports()[0]
)
assert count(c.get_connections(handle=line.handles()[0])) == 1
# Same item, different port
# c.connect_item(l, l.handles()[0], b1, b1.ports()[-1])
# assert count(c.get_connections(handle=l.handles()[0])) == 1
# Different item
# c.connect_item(l, l.handles()[0], b2, b2.ports()[0])
# assert count(c.get_connections(handle=l.handles()[0])) == 1
def test_disconnect_item_with_callback(self):
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
events = []
def callback():
events.append("called")
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], callback=callback)
assert count(c.get_connections(handle=line.handles()[0])) == 1
c.disconnect_item(line, line.handles()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert events == ["called"]
def test_disconnect_item_with_constraint(self):
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
cons = b1.ports()[0].constraint(c, line, line.handles()[0], b1)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], constraint=cons)
assert count(c.get_connections(handle=line.handles()[0])) == 1
ncons = len(c.solver.constraints)
assert ncons == 5
c.disconnect_item(line, line.handles()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert len(c.solver.constraints) == 4
def test_disconnect_item_by_deleting_element(self):
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
events = []
def callback():
events.append("called")
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], callback=callback)
assert count(c.get_connections(handle=line.handles()[0])) == 1
c.remove(b1)
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert events == ["called"]
def test_disconnect_item_with_constraint_by_deleting_element(self):
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
cons = b1.ports()[0].constraint(c, line, line.handles()[0], b1)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], constraint=cons)
assert count(c.get_connections(handle=line.handles()[0])) == 1
ncons = len(c.solver.constraints)
assert ncons == 5
c.remove(b1)
assert count(c.get_connections(handle=line.handles()[0])) == 0
self.assertEqual(2, len(c.solver.constraints))
assert count(c.get_connections(handle=line.handles()[0])) == 1
class ConstraintProjectionTestCase(unittest.TestCase):
def test_line_projection(self):
"""Test projection with line's handle on element's side"""
line = Line()
line.matrix.translate(15, 50)
h1, h2 = line.handles()
h1.x, h1.y = 0, 0
h2.x, h2.y = 20, 20
def test_disconnect_item_with_callback():
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
box = Box()
box.matrix.translate(10, 10)
box.width = 40
box.height = 20
h_nw, h_ne, h_se, h_sw = box.handles()
events = []
canvas = Canvas()
canvas.add(line)
canvas.add(box)
def callback():
events.append("called")
# move line's second handle on box side
h2.x, h2.y = 5, -20
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], callback=callback)
assert count(c.get_connections(handle=line.handles()[0])) == 1
c.disconnect_item(line, line.handles()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert events == ["called"]
# bc = BalanceConstraint(band=(h_sw.x, h_se.x), v=h2.x, balance=0.25)
# canvas.projector(bc, x={h_sw.x: box, h_se.x: box, h2.x: line})
# canvas._solver.add_constraint(bc)
#
# eq = EqualsConstraint(a=h_se.y, b=h2.y)
# canvas.projector(eq, y={h_se.y: box, h2.y: line})
# canvas._solver.add_constraint(eq)
#
# box.request_update()
# line.request_update()
#
# canvas.update()
#
# box.width = 60
# box.height = 30
#
# canvas.update()
#
# # expect h2.x to be moved due to balance constraint
# self.assertEqual(10, h2.x)
# self.assertEqual(-10, h2.y)
def test_disconnect_item_with_constraint():
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
cons = b1.ports()[0].constraint(c, line, line.handles()[0], b1)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], constraint=cons)
assert count(c.get_connections(handle=line.handles()[0])) == 1
ncons = len(c.solver.constraints)
assert ncons == 5
c.disconnect_item(line, line.handles()[0])
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert len(c.solver.constraints) == 4
class CanvasConstraintTestCase(unittest.TestCase):
def test_remove_connected_item(self):
"""Test adding canvas constraint"""
canvas = Canvas()
def test_disconnect_item_by_deleting_element():
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
from gaphas.aspect import Connector, ConnectionSink
events = []
l1 = Line()
canvas.add(l1)
def callback():
events.append("called")
b1 = Box()
canvas.add(b1)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], callback=callback)
assert count(c.get_connections(handle=line.handles()[0])) == 1
number_cons1 = len(canvas.solver.constraints)
c.remove(b1)
b2 = Box()
canvas.add(b2)
number_cons2 = len(canvas.solver.constraints)
conn = Connector(l1, l1.handles()[0])
sink = ConnectionSink(b1, b1.ports()[0])
conn.connect(sink)
assert canvas.get_connection(l1.handles()[0])
conn = Connector(l1, l1.handles()[1])
sink = ConnectionSink(b2, b2.ports()[0])
conn.connect(sink)
assert canvas.get_connection(l1.handles()[1])
self.assertEqual(number_cons2 + 2, len(canvas.solver.constraints))
canvas.remove(b1)
# Expecting a class + line connected at one end only
self.assertEqual(number_cons1 + 1, len(canvas.solver.constraints))
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert events == ["called"]
# def test_adding_constraint(self):
# """Test adding canvas constraint"""
# canvas = Canvas()
#
# l1 = Line()
# canvas.add(l1)
#
# h1, h2 = l1.handles()
# h = Handle()
#
# eq1 = EqualsConstraint(h1.x, h.x)
# canvas.add_canvas_constraint(l1, h1, eq1)
# self.assertTrue(l1 in cons)
# self.assertTrue(h1 in cons[l1])
# self.assertTrue(eq1 in cons[l1][h1])
#
# l2 = Line()
# canvas.add(l2)
#
# h1, h2 = l2.handles()
# h = Handle()
#
# eq2 = EqualsConstraint(h1.x, h.x)
# canvas.add_canvas_constraint(l2, h1, eq2)
# self.assertTrue(l2 in cons)
# self.assertTrue(h1 in cons[l2])
# self.assertTrue(eq2 in cons[l2][h1])
#
#
# def test_adding_constraint_ex(self):
# """Test adding canvas constraint for non-existing item"""
# canvas = Canvas()
# l1 = Line()
# h1, h2 = l1.handles()
# h = Handle()
#
# eq = EqualsConstraint(h1.x, h.x)
# self.assertRaises(ValueError, canvas.add_canvas_constraint, l1, h1, eq)
#
#
# def test_removing_constraint(self):
# """Test removing canvas constraint"""
# canvas = Canvas()
# cons = canvas._canvas_constraints
#
# l1 = Line()
# canvas.add(l1)
#
# h1, h2 = l1.handles()
# h = Handle()
#
# eq1 = EqualsConstraint(h1.x, h.x)
# canvas.add_canvas_constraint(l1, h1, eq1)
#
# # test preconditions
# assert l1 in cons
# assert h1 in cons[l1]
# assert eq1 in cons[l1][h1]
#
# canvas.remove_canvas_constraint(l1, h1, eq1)
# self.assertTrue(l1 in cons)
# self.assertTrue(h1 in cons[l1])
# self.assertFalse(eq1 in cons[l1][h1])
#
# eq1 = EqualsConstraint(h1.x, h.x)
# eq2 = EqualsConstraint(h1.y, h.y)
# canvas.add_canvas_constraint(l1, h1, eq1)
# canvas.add_canvas_constraint(l1, h1, eq2)
#
# # test preconditions
# assert l1 in cons
# assert h1 in cons[l1]
# assert eq1 in cons[l1][h1]
# assert eq2 in cons[l1][h1]
#
# canvas.remove_canvas_constraint(l1, h1)
#
# self.assertTrue(l1 in cons)
# self.assertTrue(h1 in cons[l1])
# self.assertFalse(eq1 in cons[l1][h1])
# self.assertFalse(eq2 in cons[l1][h1])
#
#
# def test_fetching_constraints(self):
# """Test fetching canvas constraints"""
# canvas = Canvas()
# cons = canvas._canvas_constraints
#
# l1 = Line()
# canvas.add(l1)
#
# h1, h2 = l1.handles()
# h = Handle()
#
# eq1 = EqualsConstraint(h1.x, h.x)
# eq2 = EqualsConstraint(h1.y, h.y)
# canvas.add_canvas_constraint(l1, h1, eq1)
# canvas.add_canvas_constraint(l1, h1, eq2)
#
# # test preconditions
# assert l1 in cons
# assert h1 in cons[l1]
# assert eq1 in cons[l1][h1]
# assert eq2 in cons[l1][h1]
#
# self.assertTrue(eq1 in canvas.canvas_constraints(l1))
# self.assertTrue(eq2 in canvas.canvas_constraints(l1))
def test_disconnect_item_with_constraint_by_deleting_element():
b1 = Box()
b2 = Box()
line = Line()
c = Canvas()
c.add(b1)
c.add(b2)
c.add(line)
# vim:sw=4:et:ai
cons = b1.ports()[0].constraint(c, line, line.handles()[0], b1)
c.connect_item(line, line.handles()[0], b1, b1.ports()[0], constraint=cons)
assert count(c.get_connections(handle=line.handles()[0])) == 1
ncons = len(c.solver.constraints)
assert ncons == 5
c.remove(b1)
assert count(c.get_connections(handle=line.handles()[0])) == 0
assert 2 == len(c.solver.constraints)
def test_line_projection():
"""Test projection with line's handle on element's side.
"""
line = Line()
line.matrix.translate(15, 50)
h1, h2 = line.handles()
h1.x, h1.y = 0, 0
h2.x, h2.y = 20, 20
box = Box()
box.matrix.translate(10, 10)
box.width = 40
box.height = 20
canvas = Canvas()
canvas.add(line)
canvas.add(box)
# move line's second handle on box side
h2.x, h2.y = 5, -20
def test_remove_connected_item():
"""Test adding canvas constraint.
"""
canvas = Canvas()
from gaphas.aspect import Connector, ConnectionSink
l1 = Line()
canvas.add(l1)
b1 = Box()
canvas.add(b1)
number_cons1 = len(canvas.solver.constraints)
b2 = Box()
canvas.add(b2)
number_cons2 = len(canvas.solver.constraints)
conn = Connector(l1, l1.handles()[0])
sink = ConnectionSink(b1, b1.ports()[0])
conn.connect(sink)
assert canvas.get_connection(l1.handles()[0])
conn = Connector(l1, l1.handles()[1])
sink = ConnectionSink(b2, b2.ports()[0])
conn.connect(sink)
assert canvas.get_connection(l1.handles()[1])
assert number_cons2 + 2 == len(canvas.solver.constraints)
canvas.remove(b1)
# Expecting a class + line connected at one end only
assert number_cons1 + 1 == len(canvas.solver.constraints)

View File

@ -1,37 +1,30 @@
import unittest
import pytest
from gaphas.connector import Position, Handle
from gaphas.solver import Variable
class PositionTestCase(unittest.TestCase):
def test_position(self):
pos = Position((0, 0))
self.assertEqual(0, pos.x)
self.assertEqual(0, pos.y)
def test_position(self):
pos = Position((1, 2))
self.assertEqual(1, pos.x)
self.assertEqual(2, pos.y)
def test_set_xy(self):
pos = Position((1, 2))
x = Variable()
y = Variable()
assert x is not pos.x
assert y is not pos.y
pos.set_x(x)
pos.set_y(y)
assert x is pos.x
assert y is pos.y
@pytest.mark.parametrize("position", [(0, 0), (1, 2)])
def test_position(position):
pos = Position(position)
assert position[0] == pos.x
assert position[1] == pos.y
class HandleTestCase(unittest.TestCase):
def test_handle_x_y(self):
h = Handle()
self.assertEqual(0.0, h.x)
self.assertEqual(0.0, h.y)
def test_set_xy():
pos = Position((1, 2))
x = Variable()
y = Variable()
assert x is not pos.x
assert y is not pos.y
pos.set_x(x)
pos.set_y(y)
assert x is pos.x
assert y is pos.y
# vim: sw=4:et:ai
def test_handle_x_y():
h = Handle()
assert 0.0 == h.x
assert 0.0 == h.y

View File

@ -1,72 +1,62 @@
import unittest
from gaphas.solver import Variable
from gaphas.constraint import PositionConstraint, LineAlignConstraint
class PositionTestCase(unittest.TestCase):
def test_pos_constraint(self):
"""Test position constraint"""
x1, y1 = Variable(10), Variable(11)
x2, y2 = Variable(12), Variable(13)
pc = PositionConstraint(origin=(x1, y1), point=(x2, y2))
pc.solve_for()
def test_pos_constraint():
"""Test position constraint"""
x1, y1 = Variable(10), Variable(11)
x2, y2 = Variable(12), Variable(13)
pc = PositionConstraint(origin=(x1, y1), point=(x2, y2))
pc.solve_for()
# origin shall remain the same
self.assertEqual(10, x1)
self.assertEqual(11, y1)
# origin shall remain the same
assert 10 == x1
assert 11 == y1
# point shall be moved to origin
self.assertEqual(10, x2)
self.assertEqual(11, y2)
# point shall be moved to origin
assert 10 == x2
assert 11 == y2
# change just x of origin
x1.value = 15
pc.solve_for()
self.assertEqual(15, x2)
# change just x of origin
x1.value = 15
pc.solve_for()
assert 15 == x2
# change just y of origin
y1.value = 14
pc.solve_for()
self.assertEqual(14, y2)
# change just y of origin
y1.value = 14
pc.solve_for()
assert 14 == y2
class LineAlignConstraintTestCase(unittest.TestCase):
def test_delta():
"""Test line align constraint delta.
"""
Line align constraint test case.
line = (Variable(0), Variable(0)), (Variable(30), Variable(20))
point = (Variable(15), Variable(10))
lc = LineAlignConstraint(line=line, point=point, align=0.5, delta=5)
lc.solve_for()
assert round(abs(19.16 - point[0].value), 2) == 0
assert round(abs(12.77 - point[1].value), 2) == 0
line[1][0].value = 40
line[1][1].value = 30
lc.solve_for()
assert round(abs(24.00 - point[0].value), 2) == 0
assert round(abs(18.00 - point[1].value), 2) == 0
def test_delta_below_zero():
"""Test line align constraint with delta below zero.
"""
line = (Variable(0), Variable(0)), (Variable(30), Variable(20))
point = (Variable(15), Variable(10))
lc = LineAlignConstraint(line=line, point=point, align=0.5, delta=-5)
lc.solve_for()
assert round(abs(10.84 - point[0].value), 2) == 0
assert round(abs(7.23 - point[1].value), 2) == 0
def test_delta(self):
"""Test line align delta
"""
line = (Variable(0), Variable(0)), (Variable(30), Variable(20))
point = (Variable(15), Variable(10))
lc = LineAlignConstraint(line=line, point=point, align=0.5, delta=5)
lc.solve_for()
self.assertAlmostEqual(19.16, point[0].value, 2)
self.assertAlmostEqual(12.77, point[1].value, 2)
line[1][0].value = 40
line[1][1].value = 30
lc.solve_for()
self.assertAlmostEqual(24.00, point[0].value, 2)
self.assertAlmostEqual(18.00, point[1].value, 2)
def test_delta_below_zero(self):
"""Test line align with delta below zero
"""
line = (Variable(0), Variable(0)), (Variable(30), Variable(20))
point = (Variable(15), Variable(10))
lc = LineAlignConstraint(line=line, point=point, align=0.5, delta=-5)
lc.solve_for()
self.assertAlmostEqual(10.84, point[0].value, 2)
self.assertAlmostEqual(7.23, point[1].value, 2)
line[1][0].value = 40
line[1][1].value = 30
lc.solve_for()
self.assertAlmostEqual(16.0, point[0].value, 2)
self.assertAlmostEqual(12.00, point[1].value, 2)
# vim: sw=4:et:ai
line[1][0].value = 40
line[1][1].value = 30
lc.solve_for()
assert round(abs(16.0 - point[0].value), 2) == 0
assert round(abs(12.00 - point[1].value), 2) == 0

View File

@ -1,103 +1,96 @@
import pytest
from builtins import range
from os import getenv
import unittest
from gaphas.canvas import Canvas
from gaphas.examples import Box
from gaphas.item import NW, NE, SE, SW
class ElementTestCase(unittest.TestCase):
def test_creation_with_size(self):
"""
Test if initial size holds when added to a canvas.
"""
canvas = Canvas()
box = Box(150, 153)
assert box.width == 150, box.width
assert box.height == 153, box.height
assert box.handles()[SE].pos.x == 150, box.handles()[SE].pos.x
assert box.handles()[SE].pos.y == 153, box.handles()[SE].pos.y
canvas.add(box)
assert box.width == 150, box.width
assert box.height == 153, box.height
assert box.handles()[SE].pos.x == 150, box.handles()[SE].pos.x
assert box.handles()[SE].pos.y == 153, box.handles()[SE].pos.y
def test_resize_se(self):
"""
Test resizing of element by dragging it SE handle.
"""
canvas = Canvas()
box = Box()
handles = box.handles()
canvas.add(box)
h_nw, h_ne, h_se, h_sw = handles
assert h_nw is handles[NW]
assert h_ne is handles[NE]
assert h_sw is handles[SW]
assert h_se is handles[SE]
# to see how many solver was called:
# GAPHAS_TEST_COUNT=3 nosetests -s --with-prof
# --profile-restrict=gaphas gaphas/tests/test_element.py | grep -e
# '\<solve\>' -e dirty
count = getenv("GAPHAS_TEST_COUNT")
if count:
count = int(count)
else:
count = 1
for i in range(count):
h_se.pos.x += 100 # h.se.{x,y} = 10, now
h_se.pos.y += 100
box.request_update()
canvas.update()
self.assertEqual(
110 * count, h_se.pos.x
) # h_se changed above, should remain the same
self.assertEqual(110 * count, float(h_se.pos.y))
self.assertEqual(110 * count, float(h_ne.pos.x))
self.assertEqual(110 * count, float(h_sw.pos.y))
def test_minimal_se(self):
"""
Test resizing of element by dragging it SE handle.
"""
canvas = Canvas()
box = Box()
handles = box.handles()
canvas.add(box)
h_nw, h_ne, h_se, h_sw = handles
assert h_nw is handles[NW]
assert h_ne is handles[NE]
assert h_sw is handles[SW]
assert h_se is handles[SE]
h_se.pos.x -= 20 # h.se.{x,y} == -10
h_se.pos.y -= 20
assert h_se.pos.x == h_se.pos.y == -10
box.request_update()
canvas.update()
self.assertEqual(10, h_se.pos.x) # h_se changed above, should be 10
self.assertEqual(10, h_se.pos.y)
self.assertEqual(10, h_ne.pos.x)
self.assertEqual(10, h_sw.pos.y)
class CanvasBox(object):
def __init__(self):
self.canvas = Canvas()
self.box = Box()
self.handles = self.box.handles()
# vim:sw=4:et:ai
@pytest.fixture()
def cb():
return CanvasBox()
def test_creation_with_size(cb):
"""Test if initial size holds when added to a canvas.
"""
cb.box.width = 150
cb.box.height = 153
assert cb.box.width == 150, cb.box.width
assert cb.box.height == 153, cb.box.height
assert cb.box.handles()[SE].pos.x == 150, cb.box.handles()[SE].pos.x
assert cb.box.handles()[SE].pos.y == 153, cb.box.handles()[SE].pos.y
cb.canvas.add(cb.box)
assert cb.box.width == 150, cb.box.width
assert cb.box.height == 153, cb.box.height
assert cb.box.handles()[SE].pos.x == 150, cb.box.handles()[SE].pos.x
assert cb.box.handles()[SE].pos.y == 153, cb.box.handles()[SE].pos.y
def test_resize_se(cb):
"""Test resizing of element by dragging its SE handle.
"""
cb.canvas.add(cb.box)
h_nw, h_ne, h_se, h_sw = cb.handles
assert h_nw is cb.handles[NW]
assert h_ne is cb.handles[NE]
assert h_sw is cb.handles[SW]
assert h_se is cb.handles[SE]
count = getenv("GAPHAS_TEST_COUNT")
if count:
count = int(count)
else:
count = 1
for i in range(count):
h_se.pos.x += 100 # h.se.{x,y} = 10, now
h_se.pos.y += 100
cb.box.request_update()
cb.canvas.update()
assert 110 * count == h_se.pos.x # h_se changed above, should remain the same
assert 110 * count == float(h_se.pos.y)
assert 110 * count == float(h_ne.pos.x)
assert 110 * count == float(h_sw.pos.y)
def test_minimal_se(cb):
"""Test resizing of element by dragging its SE handle.
"""
cb.canvas.add(cb.box)
h_nw, h_ne, h_se, h_sw = cb.handles
assert h_nw is cb.handles[NW]
assert h_ne is cb.handles[NE]
assert h_sw is cb.handles[SW]
assert h_se is cb.handles[SE]
h_se.pos.x -= 20 # h.se.{x,y} == -10
h_se.pos.y -= 20
assert h_se.pos.x == h_se.pos.y == -10
cb.box.request_update()
cb.canvas.update()
assert 10 == h_se.pos.x # h_se changed above, should be 10
assert 10 == h_se.pos.y
assert 10 == h_ne.pos.x
assert 10 == h_sw.pos.y

View File

@ -1,43 +1,27 @@
from __future__ import print_function
from builtins import object
import unittest
from gaphas.freehand import FreeHandCairoContext
import cairo
class PseudoFile(object):
def __init__(self):
self.data = ""
def write(self, data):
self.data = self.data + data
from gaphas.freehand import FreeHandCairoContext
class FreeHandCairoContextTest(unittest.TestCase):
def setUp(self):
pass
def test_drawing_lines():
surface = cairo.SVGSurface("freehand-drawing-lines.svg", 100, 100)
cr = FreeHandCairoContext(cairo.Context(surface))
cr.set_line_width(2)
cr.move_to(20, 20)
cr.line_to(20, 80)
cr.line_to(80, 80)
cr.line_to(80, 20)
cr.stroke()
cr.show_page()
def test_drawing_lines(self):
f = PseudoFile()
surface = cairo.SVGSurface("freehand-drawing-lines.svg", 100, 100)
cr = FreeHandCairoContext(cairo.Context(surface))
cr.set_line_width(2)
cr.move_to(20, 20)
cr.line_to(20, 80)
cr.line_to(80, 80)
cr.line_to(80, 20)
cr.stroke()
cr.show_page()
def test_drawing_rectangle(self):
surface = cairo.SVGSurface("freehand-drawing-rectangle.svg", 100, 100)
cr = FreeHandCairoContext(cairo.Context(surface))
cr.set_line_width(2)
cr.rectangle(20, 20, 60, 60)
cr.stroke()
cr.show_page()
def test_drawing_rectangle():
surface = cairo.SVGSurface("freehand-drawing-rectangle.svg", 100, 100)
cr = FreeHandCairoContext(cairo.Context(surface))
cr.set_line_width(2)
cr.rectangle(20, 20, 60, 60)
cr.stroke()
cr.show_page()
DRAWING_LINES_OUTPUT = """<?xml version="1.0" encoding="UTF-8"?>
@ -46,5 +30,3 @@ DRAWING_LINES_OUTPUT = """<?xml version="1.0" encoding="UTF-8"?>
<path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 20 20 C 23.324219 50.054688 17.195312 33.457031 20.722656 80.585938 C 38.78125 83.566406 20.984375 77.625 80.652344 80.652344 C 83.65625 70.992188 77.578125 60.988281 80.507812 20.019531 "/>
</g>
</svg>"""
# vim:sw=4:et:ai

View File

@ -1,8 +1,8 @@
from __future__ import print_function
import unittest
from builtins import range
import pytest
from gi.repository import Gtk
from gaphas.canvas import Canvas
@ -11,161 +11,157 @@ from gaphas.item import Element, Line
from gaphas.view import GtkView
class GuideTestCase(unittest.TestCase):
def setUp(self):
class TestWindow(object):
def __init__(self):
self.canvas = Canvas()
self.view = GtkView(self.canvas)
self.window = Gtk.Window()
self.window.add(self.view)
self.window.show_all()
def tearDown(self):
self.window.destroy()
def test_find_closest(self):
"""
test find closest method.
"""
set1 = [0, 10, 20]
set2 = [2, 15, 30]
guider = GuidedItemInMotion(Element(), self.view)
d, closest = guider.find_closest(set1, set2)
self.assertEqual(2.0, d)
self.assertEqual([2.0], closest)
def test_element_guide(self):
e1 = Element()
self.assertEqual(10, e1.width)
self.assertEqual(10, e1.height)
guides = Guide(e1).horizontal()
self.assertEqual(0.0, guides[0])
self.assertEqual(5.0, guides[1])
self.assertEqual(10.0, guides[2])
guides = Guide(e1).vertical()
self.assertEqual(0.0, guides[0])
self.assertEqual(5.0, guides[1])
self.assertEqual(10.0, guides[2])
def test_line_guide(self):
c = Canvas()
line = Line()
c.add(line)
line.handles().append(line._create_handle((20, 20)))
line.handles().append(line._create_handle((30, 30)))
line.handles().append(line._create_handle((40, 40)))
line.orthogonal = True
c.update_now()
guides = list(Guide(line).horizontal())
self.assertEqual(2, len(guides))
self.assertEqual(10.0, guides[0])
self.assertEqual(40.0, guides[1])
guides = list(Guide(line).vertical())
self.assertEqual(2, len(guides))
self.assertEqual(00.0, guides[0])
self.assertEqual(20.0, guides[1])
def test_line_guide_horizontal(self):
c = Canvas()
line = Line()
c.add(line)
line.handles().append(line._create_handle((20, 20)))
line.handles().append(line._create_handle((30, 30)))
line.handles().append(line._create_handle((40, 40)))
line.horizontal = True
line.orthogonal = True
c.update_now()
guides = list(Guide(line).horizontal())
self.assertEqual(2, len(guides))
self.assertEqual(0.0, guides[0])
self.assertEqual(20.0, guides[1])
guides = list(Guide(line).horizontal())
self.assertEqual(2, len(guides))
self.assertEqual(0.0, guides[0])
self.assertEqual(20.0, guides[1])
def test_guide_item_in_motion(self):
e1 = Element()
e2 = Element()
e3 = Element()
canvas = self.canvas
canvas.add(e1)
canvas.add(e2)
canvas.add(e3)
self.assertEqual(0, e1.matrix[4])
self.assertEqual(0, e1.matrix[5])
e2.matrix.translate(40, 40)
e2.request_update()
self.assertEqual(40, e2.matrix[4])
self.assertEqual(40, e2.matrix[5])
guider = GuidedItemInMotion(e3, self.view)
guider.start_move((0, 0))
self.assertEqual(0, e3.matrix[4])
self.assertEqual(0, e3.matrix[5])
# Moved back to guided lines:
for d in range(0, 3):
guider.move((d, d))
self.assertEqual(0, e3.matrix[4])
self.assertEqual(0, e3.matrix[5])
for d in range(3, 5):
guider.move((d, d))
self.assertEqual(5, e3.matrix[4])
self.assertEqual(5, e3.matrix[5])
guider.move((20, 20))
self.assertEqual(20, e3.matrix[4])
self.assertEqual(20, e3.matrix[5])
def test_guide_item_in_motion_2(self):
e1 = Element()
e2 = Element()
e3 = Element()
canvas = self.canvas
canvas.add(e1)
canvas.add(e2)
canvas.add(e3)
self.assertEqual(0, e1.matrix[4])
self.assertEqual(0, e1.matrix[5])
e2.matrix.translate(40, 40)
e2.request_update()
self.assertEqual(40, e2.matrix[4])
self.assertEqual(40, e2.matrix[5])
guider = GuidedItemInMotion(e3, self.view)
guider.start_move((3, 3))
self.assertEqual(0, e3.matrix[4])
self.assertEqual(0, e3.matrix[5])
# Moved back to guided lines:
for y in range(4, 6):
guider.move((3, y))
self.assertEqual(0, e3.matrix[4])
self.assertEqual(0, e3.matrix[5])
for y in range(6, 9):
guider.move((3, y))
self.assertEqual(0, e3.matrix[4])
self.assertEqual(5, e3.matrix[5])
# Take into account initial cursor offset of (3, 3)
guider.move((20, 23))
self.assertEqual(17, e3.matrix[4])
self.assertEqual(20, e3.matrix[5])
self.line = Line()
self.canvas.add(self.line)
self.e1 = Element()
self.e2 = Element()
self.e3 = Element()
# vim:sw=4:et:ai
@pytest.fixture()
def win():
test_window = TestWindow()
yield test_window
test_window.window.destroy()
def test_find_closest(win):
"""Test find closest method.
"""
set1 = [0, 10, 20]
set2 = [2, 15, 30]
guider = GuidedItemInMotion(Element(), win.view)
d, closest = guider.find_closest(set1, set2)
assert 2.0 == d
assert [2.0] == closest
def test_element_guide():
e1 = Element()
assert 10 == e1.width
assert 10 == e1.height
guides = Guide(e1).horizontal()
assert 0.0 == guides[0]
assert 5.0 == guides[1]
assert 10.0 == guides[2]
guides = Guide(e1).vertical()
assert 0.0 == guides[0]
assert 5.0 == guides[1]
assert 10.0 == guides[2]
def test_line_guide(win):
win.line.handles().append(win.line._create_handle((20, 20)))
win.line.handles().append(win.line._create_handle((30, 30)))
win.line.handles().append(win.line._create_handle((40, 40)))
win.line.orthogonal = True
win.canvas.update_now()
guides = list(Guide(win.line).horizontal())
assert 2 == len(guides)
assert 10.0 == guides[0]
assert 40.0 == guides[1]
guides = list(Guide(win.line).vertical())
assert 2 == len(guides)
assert 00.0 == guides[0]
assert 20.0 == guides[1]
def test_line_guide_horizontal(win):
win.line.handles().append(win.line._create_handle((20, 20)))
win.line.handles().append(win.line._create_handle((30, 30)))
win.line.handles().append(win.line._create_handle((40, 40)))
win.line.horizontal = True
win.line.orthogonal = True
win.canvas.update_now()
guides = list(Guide(win.line).horizontal())
assert 2 == len(guides)
assert 0.0 == guides[0]
assert 20.0 == guides[1]
guides = list(Guide(win.line).horizontal())
assert 2 == len(guides)
assert 0.0 == guides[0]
assert 20.0 == guides[1]
def test_guide_item_in_motion(win):
win.canvas.add(win.e1)
win.canvas.add(win.e2)
win.canvas.add(win.e3)
assert 0 == win.e1.matrix[4]
assert 0 == win.e1.matrix[5]
win.e2.matrix.translate(40, 40)
win.e2.request_update()
assert 40 == win.e2.matrix[4]
assert 40 == win.e2.matrix[5]
guider = GuidedItemInMotion(win.e3, win.view)
guider.start_move((0, 0))
assert 0 == win.e3.matrix[4]
assert 0 == win.e3.matrix[5]
# Moved back to guided lines:
for d in range(0, 3):
guider.move((d, d))
assert 0 == win.e3.matrix[4]
assert 0 == win.e3.matrix[5]
for d in range(3, 5):
guider.move((d, d))
assert 5 == win.e3.matrix[4]
assert 5 == win.e3.matrix[5]
guider.move((20, 20))
assert 20 == win.e3.matrix[4]
assert 20 == win.e3.matrix[5]
def test_guide_item_in_motion_2(win):
win.canvas.add(win.e1)
win.canvas.add(win.e2)
win.canvas.add(win.e3)
assert 0 == win.e1.matrix[4]
assert 0 == win.e1.matrix[5]
win.e2.matrix.translate(40, 40)
win.e2.request_update()
assert 40 == win.e2.matrix[4]
assert 40 == win.e2.matrix[5]
guider = GuidedItemInMotion(win.e3, win.view)
guider.start_move((3, 3))
assert 0 == win.e3.matrix[4]
assert 0 == win.e3.matrix[5]
# Moved back to guided lines:
for y in range(4, 6):
guider.move((3, y))
assert 0 == win.e3.matrix[4]
assert 0 == win.e3.matrix[5]
for y in range(6, 9):
guider.move((3, y))
assert 0 == win.e3.matrix[4]
assert 5 == win.e3.matrix[5]
# Take into account initial cursor offset of (3, 3)
guider.move((20, 23))
assert 17 == win.e3.matrix[4]
assert 20 == win.e3.matrix[5]

View File

@ -1,93 +1,91 @@
"""
Generic gaphas item tests.
"""
"""Item constraint creation tests.
import unittest
The test check functionality of `Item.constraint` method, not constraints
themselves.
"""
import pytest
from gaphas.item import Item
from gaphas.constraint import LineConstraint, EqualsConstraint, LessThanConstraint
from gaphas.item import Item
from gaphas.solver import Variable
class ItemConstraintTestCase(unittest.TestCase):
class ItemPosition(object):
def __init__(self):
self.item = Item()
self.pos1 = Variable(1), Variable(2)
self.pos2 = Variable(3), Variable(4)
@pytest.fixture()
def item_pos():
return ItemPosition()
def test_line_constraint(item_pos):
"""Test line creation constraint.
"""
Item constraint creation tests. The test check functionality of
`Item.constraint` method, not constraints themselves.
line = (Variable(3), Variable(4)), (Variable(5), Variable(6))
item_pos.item.constraint(line=(item_pos.pos1, line))
assert 1 == len(item_pos.item._constraints)
c = item_pos.item._constraints[0]
assert isinstance(c, LineConstraint)
assert (1, 2) == c._point
assert ((3, 4), (5, 6)) == c._line
def test_horizontal_constraint(item_pos):
"""Test horizontal constraint creation.
"""
item_pos.item.constraint(horizontal=(item_pos.pos1, item_pos.pos2))
assert 1 == len(item_pos.item._constraints)
def test_line_constraint(self):
"""
Test line creation constraint.
"""
item = Item()
pos = Variable(1), Variable(2)
line = (Variable(3), Variable(4)), (Variable(5), Variable(6))
item.constraint(line=(pos, line))
self.assertEqual(1, len(item._constraints))
c = item_pos.item._constraints[0]
assert isinstance(c, EqualsConstraint)
# Expect constraint on y-axis
assert 2 == c.a
assert 4 == c.b
c = item._constraints[0]
self.assertTrue(isinstance(c, LineConstraint))
self.assertEqual((1, 2), c._point)
self.assertEqual(((3, 4), (5, 6)), c._line)
def test_horizontal_constraint(self):
"""
Test horizontal constraint creation.
"""
item = Item()
p1 = Variable(1), Variable(2)
p2 = Variable(3), Variable(4)
item.constraint(horizontal=(p1, p2))
self.assertEqual(1, len(item._constraints))
def test_vertical_constraint(item_pos):
"""Test vertical constraint creation.
c = item._constraints[0]
self.assertTrue(isinstance(c, EqualsConstraint))
# expect constraint on y-axis
self.assertEqual(2, c.a)
self.assertEqual(4, c.b)
"""
item_pos.item.constraint(vertical=(item_pos.pos1, item_pos.pos2))
assert 1 == len(item_pos.item._constraints)
def test_vertical_constraint(self):
"""
Test vertical constraint creation.
"""
item = Item()
p1 = Variable(1), Variable(2)
p2 = Variable(3), Variable(4)
item.constraint(vertical=(p1, p2))
self.assertEqual(1, len(item._constraints))
c = item_pos.item._constraints[0]
assert isinstance(c, EqualsConstraint)
# Expect constraint on x-axis
assert 1 == c.a
assert 3 == c.b
c = item._constraints[0]
self.assertTrue(isinstance(c, EqualsConstraint))
# expect constraint on x-axis
self.assertEqual(1, c.a)
self.assertEqual(3, c.b)
def test_left_of_constraint(self):
"""
Test "less than" constraint (horizontal) creation.
"""
item = Item()
p1 = Variable(1), Variable(2)
p2 = Variable(3), Variable(4)
item.constraint(left_of=(p1, p2))
self.assertEqual(1, len(item._constraints))
def test_left_of_constraint(item_pos):
"""Test "less than" constraint (horizontal) creation.
c = item._constraints[0]
self.assertTrue(isinstance(c, LessThanConstraint))
self.assertEqual(1, c.smaller)
self.assertEqual(3, c.bigger)
"""
item_pos.item.constraint(left_of=(item_pos.pos1, item_pos.pos2))
assert 1 == len(item_pos.item._constraints)
def test_above_constraint(self):
"""
Test "less than" constraint (vertical) creation.
"""
item = Item()
p1 = Variable(1), Variable(2)
p2 = Variable(3), Variable(4)
item.constraint(above=(p1, p2))
self.assertEqual(1, len(item._constraints))
c = item_pos.item._constraints[0]
assert isinstance(c, LessThanConstraint)
assert 1 == c.smaller
assert 3 == c.bigger
c = item._constraints[0]
self.assertTrue(isinstance(c, LessThanConstraint))
self.assertEqual(2, c.smaller)
self.assertEqual(4, c.bigger)
def test_above_constraint(item_pos):
"""
Test "less than" constraint (vertical) creation.
"""
item_pos.item.constraint(above=(item_pos.pos1, item_pos.pos2))
assert 1 == len(item_pos.item._constraints)
c = item_pos.item._constraints[0]
assert isinstance(c, LessThanConstraint)
assert 2 == c.smaller
assert 4 == c.bigger

View File

@ -1,109 +1,75 @@
import unittest
from gaphas.item import Line
"""Basic item tests for lines.
"""
from gaphas.canvas import Canvas
from gaphas import state
from gaphas.item import Line
from gaphas.segment import Segment
undo_list = []
redo_list = []
def test_initial_ports(revert_undo):
"""Test initial ports amount.
def undo_handler(event):
undo_list.append(event)
def undo():
apply_me = list(undo_list)
del undo_list[:]
apply_me.reverse()
for e in apply_me:
state.saveapply(*e)
redo_list[:] = undo_list[:]
del undo_list[:]
class TestCaseBase(unittest.TestCase):
"""
Abstract test case class with undo support.
line = Line()
assert 1 == len(line.ports())
def test_orthogonal_horizontal_undo(revert_undo, undo_fixture):
"""Test orthogonal line constraints bug (#107).
"""
canvas = Canvas()
line = Line()
canvas.add(line)
assert not line.horizontal
assert len(canvas.solver._constraints) == 0
def setUp(self):
state.observers.add(state.revert_handler)
state.subscribers.add(undo_handler)
segment = Segment(line, None)
segment.split_segment(0)
def tearDown(self):
state.observers.remove(state.revert_handler)
state.subscribers.remove(undo_handler)
line.orthogonal = True
assert 2 == len(canvas.solver._constraints)
del undo_fixture[2][:] # Clear undo_list
line.horizontal = True
assert 2 == len(canvas.solver._constraints)
undo_fixture[0]() # Call undo
assert not line.horizontal
assert 2 == len(canvas.solver._constraints)
line.horizontal = True
assert line.horizontal
assert 2 == len(canvas.solver._constraints)
class LineTestCase(TestCaseBase):
"""
Basic line item tests.
def test_orthogonal_line_undo(revert_undo, undo_fixture):
"""Test orthogonal line undo.
"""
canvas = Canvas()
line = Line()
canvas.add(line)
def test_initial_ports(self):
"""Test initial ports amount
"""
line = Line()
self.assertEqual(1, len(line.ports()))
segment = Segment(line, None)
segment.split_segment(0)
def test_orthogonal_horizontal_undo(self):
"""Test orthogonal line constraints bug (#107)
"""
canvas = Canvas()
line = Line()
canvas.add(line)
assert not line.horizontal
assert len(canvas.solver._constraints) == 0
# Start with no orthogonal constraints
assert len(canvas.solver._constraints) == 0
segment = Segment(line, None)
segment.split_segment(0)
line.orthogonal = True
line.orthogonal = True
# Check orthogonal constraints
assert 2 == len(canvas.solver._constraints)
assert 3 == len(line.handles())
self.assertEqual(2, len(canvas.solver._constraints))
after_ortho = set(canvas.solver._constraints)
undo_fixture[0]() # Call undo
del undo_list[:]
line.horizontal = True
self.assertEqual(2, len(canvas.solver._constraints))
undo()
self.assertFalse(line.horizontal)
self.assertEqual(2, len(canvas.solver._constraints))
line.horizontal = True
self.assertTrue(line.horizontal)
self.assertEqual(2, len(canvas.solver._constraints))
def test_orthogonal_line_undo(self):
"""Test orthogonal line undo
"""
canvas = Canvas()
line = Line()
canvas.add(line)
segment = Segment(line, None)
segment.split_segment(0)
# start with no orthogonal constraints
assert len(canvas.solver._constraints) == 0
line.orthogonal = True
# check orthogonal constraints
self.assertEqual(2, len(canvas.solver._constraints))
self.assertEqual(3, len(line.handles()))
undo()
self.assertFalse(line.orthogonal)
self.assertEqual(0, len(canvas.solver._constraints))
self.assertEqual(2, len(line.handles()))
# vim:sw=4:et
assert not line.orthogonal
assert 0 == len(canvas.solver._constraints)
assert 2 == len(line.handles())

View File

@ -1,26 +1,25 @@
from __future__ import print_function
import io
import pickle
import unittest
from builtins import object
import cairo
import pytest
from future import standard_library
from gi.repository import Gtk
import demo
from gaphas.canvas import Canvas
from gaphas.examples import Box
from gaphas.item import Element, Line
from gaphas.view import View, GtkView
# Ensure extra pickle reducers/reconstructors are loaded:
import gaphas.picklers
standard_library.install_aliases()
class MyPickler(pickle.Pickler):
def save(self, obj):
# print('saving obj', obj, type(obj))
def save(self, obj, save_persistent_id=True):
try:
return pickle.Pickler.save(self, obj)
except pickle.PicklingError as e:
@ -29,191 +28,167 @@ class MyPickler(pickle.Pickler):
class MyDisconnect(object):
"""
Disconnect object should be located at top-level, so the pickle code
"""Create a disconnect object.
The disconnect object should be located at top-level, so the pickle code
can find it.
"""
def __call__(self):
pass
def create_canvas():
canvas = Canvas()
box = Box()
canvas.add(box)
box.matrix.translate(100, 50)
box.matrix.rotate(50)
box2 = Box()
canvas.add(box2, parent=box)
line = Line()
line.handles()[0].visible = False
line.handles()[0].connected_to = box
line.handles()[0].disconnect = MyDisconnect()
line.handles()[0].connection_data = 1
canvas.add(line)
canvas.update()
return canvas
class CanvasFixture(object):
def __init__(self):
self.canvas = Canvas()
self.box = Box()
self.box2 = Box()
self.line = Line()
class PickleTestCase(unittest.TestCase):
def test_pickle_element(self):
item = Element()
@pytest.fixture()
def canvas_fixture():
cf = CanvasFixture()
cf.canvas.add(cf.box)
cf.box.matrix.translate(100, 50)
cf.box.matrix.rotate(50)
cf.canvas.add(cf.box2, parent=cf.box)
pickled = pickle.dumps(item)
i2 = pickle.loads(pickled)
cf.line.handles()[0].visible = False
cf.line.handles()[0].connected_to = cf.box
cf.line.handles()[0].disconnect = MyDisconnect()
cf.line.handles()[0].connection_data = 1
assert i2
assert len(i2.handles()) == 4
cf.canvas.add(cf.line)
def test_pickle_line(self):
item = Line()
cf.canvas.update()
pickled = pickle.dumps(item)
i2 = pickle.loads(pickled)
assert i2
assert len(i2.handles()) == 2
def test_pickle(self):
canvas = create_canvas()
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
assert type(canvas._tree.nodes[0]) is Box
assert type(canvas._tree.nodes[1]) is Box
assert type(canvas._tree.nodes[2]) is Line
def test_pickle_connect(self):
"""
Persist a connection.
"""
canvas = Canvas()
box = Box()
canvas.add(box)
box2 = Box()
canvas.add(box2, parent=box)
line = Line()
line.handles()[0].visible = False
line.handles()[0].connected_to = box
line.handles()[0].disconnect = MyDisconnect()
line.handles()[0].connection_data = 1
canvas.add(line)
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
assert type(canvas._tree.nodes[0]) is Box
assert type(canvas._tree.nodes[1]) is Box
assert type(canvas._tree.nodes[2]) is Line
assert c2.solver
line2 = c2._tree.nodes[2]
h = line2.handles()[0]
assert h.visible == False
assert h.connected_to is c2._tree.nodes[0]
# connection_data and disconnect have not been persisted
assert h.connection_data == 1, h.connection_data
assert h.disconnect, h.disconnect
assert callable(h.disconnect)
assert h.disconnect() is None, h.disconnect()
def test_pickle_with_view(self):
canvas = create_canvas()
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
view = View(canvas=c2)
import cairo
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
cr = cairo.Context(surface)
view.update_bounding_box(cr)
cr.show_page()
surface.flush()
surface.finish()
def test_pickle_with_gtk_view(self):
canvas = create_canvas()
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()
def test_pickle_with_gtk_view_with_connection(self):
canvas = create_canvas()
box = canvas._tree.nodes[0]
assert isinstance(box, Box)
line = canvas._tree.nodes[2]
assert isinstance(line, Line)
view = GtkView(canvas=canvas)
# from gaphas.tool import ConnectHandleTool
# handle_tool = ConnectHandleTool()
# handle_tool.connect(view, line, line.handles()[0], (40, 0))
# assert line.handles()[0].connected_to is box, line.handles()[0].connected_to
# assert line.handles()[0].connection_data
# assert line.handles()[0].disconnect
# assert isinstance(line.handles()[0].disconnect, object), line.handles()[0].disconnect
import io
f = io.BytesIO()
pickler = MyPickler(f)
pickler.dump(canvas)
pickled = f.getvalue()
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()
def test_pickle_demo(self):
import demo
canvas = demo.create_canvas()
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()
return cf
if __name__ == "__main__":
unittest.main()
def test_pickle_element():
item = Element()
# vim: sw=4:et:ai
pickled = pickle.dumps(item)
i2 = pickle.loads(pickled)
assert i2
assert len(i2.handles()) == 4
def test_pickle_line():
item = Line()
pickled = pickle.dumps(item)
i2 = pickle.loads(pickled)
assert i2
assert len(i2.handles()) == 2
def test_pickle(canvas_fixture):
pickled = pickle.dumps(canvas_fixture.canvas)
pickle.loads(pickled)
assert type(canvas_fixture.canvas._tree.nodes[0]) is Box
assert type(canvas_fixture.canvas._tree.nodes[1]) is Box
assert type(canvas_fixture.canvas._tree.nodes[2]) is Line
def test_pickle_connect(canvas_fixture):
"""Persist a connection.
"""
canvas_fixture.line.handles()[0].visible = False
canvas_fixture.line.handles()[0].connected_to = canvas_fixture.box
canvas_fixture.line.handles()[0].disconnect = MyDisconnect()
canvas_fixture.line.handles()[0].connection_data = 1
pickled = pickle.dumps(canvas_fixture.canvas)
c2 = pickle.loads(pickled)
assert type(canvas_fixture.canvas._tree.nodes[0]) is Box
assert type(canvas_fixture.canvas._tree.nodes[1]) is Box
assert type(canvas_fixture.canvas._tree.nodes[2]) is Line
assert c2.solver
line2 = c2._tree.nodes[2]
h = line2.handles()[0]
assert h.visible is False
assert h.connected_to is c2._tree.nodes[0]
# Connection_data and disconnect have not been persisted
assert h.connection_data == 1, h.connection_data
assert h.disconnect, h.disconnect
assert callable(h.disconnect)
assert h.disconnect() is None, h.disconnect()
def test_pickle_with_view(canvas_fixture):
pickled = pickle.dumps(canvas_fixture.canvas)
c2 = pickle.loads(pickled)
view = View(canvas=c2)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
cr = cairo.Context(surface)
view.update_bounding_box(cr)
cr.show_page()
surface.flush()
surface.finish()
def test_pickle_with_gtk_view(canvas_fixture):
pickled = pickle.dumps(canvas_fixture.canvas)
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()
def test_pickle_with_gtk_view_with_connection(canvas_fixture):
box = canvas_fixture.canvas._tree.nodes[0]
assert isinstance(box, Box)
line = canvas_fixture.canvas._tree.nodes[2]
assert isinstance(line, Line)
f = io.BytesIO()
pickler = MyPickler(f)
pickler.dump(canvas_fixture.canvas)
pickled = f.getvalue()
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()
def test_pickle_demo():
canvas = demo.create_canvas()
pickled = pickle.dumps(canvas)
c2 = pickle.loads(pickled)
win = Gtk.Window()
view = GtkView(canvas=c2)
win.add(view)
view.show()
win.show()
view.update()

View File

@ -1,103 +1,91 @@
from builtins import range
import unittest
import pytest
from gaphas.geometry import Rectangle
from gaphas.quadtree import Quadtree
class QuadtreeTestCase(unittest.TestCase):
def test_lookups(self):
qtree = Quadtree((0, 0, 100, 100))
for i in range(100, 10):
for j in range(100, 10):
qtree.add("%dx%d" % (i, j), (i, j, 10, 10))
for i in range(100, 10):
for j in range(100, 10):
assert qtree.find_intersect((i + 1, j + 1, 1, 1)) == [
"%dx%d" % (i, j)
], qtree.find_intersect((i + 1, j + 1, 1, 1))
def test_with_rectangles(self):
from gaphas.geometry import Rectangle
qtree = Quadtree((0, 0, 100, 100))
for i in range(0, 100, 10):
for j in range(0, 100, 10):
qtree.add("%dx%d" % (i, j), Rectangle(i, j, 10, 10))
assert len(qtree._ids) == 100, len(qtree._ids)
for i in range(100, 10):
for j in range(100, 10):
assert qtree.find_intersect((i + 1, j + 1, 1, 1)) == [
"%dx%d" % (i, j)
], qtree.find_intersect((i + 1, j + 1, 1, 1))
def test_moving_items(self):
qtree = Quadtree((0, 0, 100, 100), capacity=10)
for i in range(0, 100, 10):
for j in range(0, 100, 10):
qtree.add("%dx%d" % (i, j), (i, j, 10, 10))
assert len(qtree._ids) == 100, len(qtree._ids)
assert qtree._bucket._buckets, qtree._bucket._buckets
for i in range(4):
assert qtree._bucket._buckets[i]._buckets
for j in range(4):
assert not qtree._bucket._buckets[i]._buckets[j]._buckets
# Check contents:
# First sub-level contains 9 items. second level contains 4 items
# ==> 4 * (9 + (4 * 4)) = 100
assert len(qtree._bucket.items) == 0, qtree._bucket.items
for i in range(4):
assert len(qtree._bucket._buckets[i].items) == 9
for item, bounds in qtree._bucket._buckets[i].items.items():
assert qtree._bucket.find_bucket(bounds) is qtree._bucket._buckets[i]
for j in range(4):
assert len(qtree._bucket._buckets[i]._buckets[j].items) == 4
assert qtree.get_bounds("0x0")
# Now move item '0x0' to the center of the first quadrant (20, 20)
qtree.add("0x0", (20, 20, 10, 10))
assert len(qtree._bucket.items) == 0
assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, (
qtree._bucket._buckets[0]._buckets[0].items
)
assert len(qtree._bucket._buckets[0].items) == 10, qtree._bucket._buckets[
0
].items
# Now move item '0x0' to the second quadrant (70, 20)
qtree.add("0x0", (70, 20, 10, 10))
assert len(qtree._bucket.items) == 0
assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, (
qtree._bucket._buckets[0]._buckets[0].items
)
assert len(qtree._bucket._buckets[0].items) == 9, qtree._bucket._buckets[
0
].items
assert len(qtree._bucket._buckets[1].items) == 10, qtree._bucket._buckets[
1
].items
def test_get_data(self):
"""
Extra data may be added to a node:
"""
qtree = Quadtree((0, 0, 100, 100))
for i in range(0, 100, 10):
for j in range(0, 100, 10):
qtree.add("%dx%d" % (i, j), (i, j, 10, 10), i + j)
for i in range(0, 100, 10):
for j in range(0, 100, 10):
assert i + j == qtree.get_data("%dx%d" % (i, j))
def test_clipped_bounds(self):
qtree = Quadtree((0, 0, 100, 100), capacity=10)
qtree.add(1, (-100, -100, 120, 120))
self.assertEqual((0, 0, 20, 20), qtree.get_clipped_bounds(1))
@pytest.fixture()
def qtree():
qtree = Quadtree((0, 0, 100, 100))
for i in range(0, 100, 10):
for j in range(0, 100, 10):
qtree.add(item="%dx%d" % (i, j), bounds=Rectangle(i, j, 10, 10))
return qtree
if __name__ == "__main__":
unittest.main()
def test_lookups(qtree):
for i in range(100, 10):
for j in range(100, 10):
assert qtree.find_intersect(rect=(i + 1, j + 1, 1, 1)) == [
"%dx%d" % (i, j)
], qtree.find_intersect(rect=(i + 1, j + 1, 1, 1))
# vim:sw=4:et:ai
def test_with_rectangles(qtree):
assert len(qtree._ids) == 100, len(qtree._ids)
for i in range(100, 10):
for j in range(100, 10):
assert qtree.find_intersect(rect=(i + 1, j + 1, 1, 1)) == [
"%dx%d" % (i, j)
], qtree.find_intersect(rect=(i + 1, j + 1, 1, 1))
def test_moving_items(qtree):
qtree.capacity = 10
assert len(qtree._ids) == 100, len(qtree._ids)
assert qtree._bucket._buckets, qtree._bucket._buckets
for i in range(4):
assert qtree._bucket._buckets[i]._buckets
for j in range(4):
assert not qtree._bucket._buckets[i]._buckets[j]._buckets
# Check contents:
# First sub-level contains 9 items. second level contains 4 items
# ==> 4 * (9 + (4 * 4)) = 100
assert len(qtree._bucket.items) == 0, qtree._bucket.items
for i in range(4):
assert len(qtree._bucket._buckets[i].items) == 9
for item, bounds in qtree._bucket._buckets[i].items.items():
assert qtree._bucket.find_bucket(bounds) is qtree._bucket._buckets[i]
for j in range(4):
assert len(qtree._bucket._buckets[i]._buckets[j].items) == 4
assert qtree.get_bounds("0x0")
# Now move item '0x0' to the center of the first quadrant (20, 20)
qtree.add("0x0", (20, 20, 10, 10))
assert len(qtree._bucket.items) == 0
assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, (
qtree._bucket._buckets[0]._buckets[0].items
)
assert len(qtree._bucket._buckets[0].items) == 10, qtree._bucket._buckets[0].items
# Now move item '0x0' to the second quadrant (70, 20)
qtree.add("0x0", (70, 20, 10, 10))
assert len(qtree._bucket.items) == 0
assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, (
qtree._bucket._buckets[0]._buckets[0].items
)
assert len(qtree._bucket._buckets[0].items) == 9, qtree._bucket._buckets[0].items
assert len(qtree._bucket._buckets[1].items) == 10, qtree._bucket._buckets[1].items
def test_get_data(qtree):
"""Test extra data added to a node.
"""
for i in range(0, 100, 10):
for j in range(0, 100, 10):
qtree.add(item="%dx%d" % (i, j), bounds=(i, j, 10, 10), data=i + j)
for i in range(0, 100, 10):
for j in range(0, 100, 10):
assert i + j == qtree.get_data(item="%dx%d" % (i, j))
def test_clipped_bounds(qtree):
qtree.capacity = 10
qtree.add(item=1, bounds=(-100, -100, 120, 120))
assert (0, 0, 20, 20) == qtree.get_clipped_bounds(item=1)

View File

@ -1,479 +1,418 @@
"""
Generic gaphas item tests.
"""Test segment aspects for items.
"""
from __future__ import print_function
import unittest
import pytest
from gaphas.item import Item, Line
from gaphas.segment import *
from gaphas.canvas import Canvas
from gaphas.item import Item
from gaphas.segment import *
from gaphas.view import View
from gaphas import state
from gaphas.tests.test_tool import simple_canvas
class SegmentTestCase(unittest.TestCase):
"""
Test aspects for items.
"""
def setUp(self):
self.canvas = Canvas()
self.line = Line()
self.view = View(self.canvas)
def test_segment_fails_for_item(self):
"""
Test if Segment aspect can be applied to Item
"""
item = Item()
try:
s = Segment(item, self.view)
except TypeError as e:
pass
else:
assert False, "Should not be reached"
def test_segment(self):
"""
"""
view = self.view
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
self.assertEqual(2, len(line.handles()))
segment.split((5, 5))
self.assertEqual(3, len(line.handles()))
undo_list = []
redo_list = []
def undo_handler(event):
undo_list.append(event)
def undo():
apply_me = list(undo_list)
del undo_list[:]
apply_me.reverse()
for e in apply_me:
state.saveapply(*e)
redo_list[:] = undo_list[:]
del undo_list[:]
class TestCaseBase(unittest.TestCase):
"""
Abstract test case class with undo support.
"""
def setUp(self):
state.observers.add(state.revert_handler)
state.subscribers.add(undo_handler)
simple_canvas(self)
def tearDown(self):
state.observers.remove(state.revert_handler)
state.subscribers.remove(undo_handler)
class LineSplitTestCase(TestCaseBase):
"""
Tests for line splitting.
"""
def test_split_single(self):
"""Test single line splitting
"""
# we start with two handles and one port, after split 3 handles are
# expected and 2 ports
assert len(self.line.handles()) == 2
assert len(self.line.ports()) == 1
old_port = self.line.ports()[0]
h1, h2 = self.line.handles()
self.assertEqual(h1.pos, old_port.start)
self.assertEqual(h2.pos, old_port.end)
segment = Segment(self.line, self.view)
handles, ports = segment.split_segment(0)
handle = handles[0]
self.assertEqual(1, len(handles))
self.assertEqual((50, 50), handle.pos.pos)
self.assertEqual(3, len(self.line.handles()))
self.assertEqual(2, len(self.line.ports()))
# new handle is between old handles
self.assertEqual(handle, self.line.handles()[1])
# and old port is deleted
self.assertTrue(old_port not in self.line.ports())
# check ports order
p1, p2 = self.line.ports()
h1, h2, h3 = self.line.handles()
self.assertEqual(h1.pos, p1.start)
self.assertEqual(h2.pos, p1.end)
self.assertEqual(h2.pos, p2.start)
self.assertEqual(h3.pos, p2.end)
def test_split_multiple(self):
"""Test multiple line splitting
"""
self.line.handles()[1].pos = (20, 16)
handles = self.line.handles()
old_ports = self.line.ports()[:]
# start with two handles, split into 4 segments - 3 new handles to
# be expected
assert len(handles) == 2
assert len(old_ports) == 1
segment = Segment(self.line, self.view)
handles, ports = segment.split_segment(0, count=4)
self.assertEqual(3, len(handles))
h1, h2, h3 = handles
self.assertEqual((5, 4), h1.pos.pos)
self.assertEqual((10, 8), h2.pos.pos)
self.assertEqual((15, 12), h3.pos.pos)
# new handles between old handles
self.assertEqual(5, len(self.line.handles()))
self.assertEqual(h1, self.line.handles()[1])
self.assertEqual(h2, self.line.handles()[2])
self.assertEqual(h3, self.line.handles()[3])
self.assertEqual(4, len(self.line.ports()))
# and old port is deleted
self.assertTrue(old_ports[0] not in self.line.ports())
# check ports order
p1, p2, p3, p4 = self.line.ports()
h1, h2, h3, h4, h5 = self.line.handles()
self.assertEqual(h1.pos, p1.start)
self.assertEqual(h2.pos, p1.end)
self.assertEqual(h2.pos, p2.start)
self.assertEqual(h3.pos, p2.end)
self.assertEqual(h3.pos, p3.start)
self.assertEqual(h4.pos, p3.end)
self.assertEqual(h4.pos, p4.start)
self.assertEqual(h5.pos, p4.end)
def test_ports_after_split(self):
"""Test ports removal after split
"""
self.line.handles()[1].pos = (20, 16)
segment = Segment(self.line, self.view)
segment.split_segment(0)
handles = self.line.handles()
old_ports = self.line.ports()[:]
# start with 3 handles and two ports
assert len(handles) == 3
assert len(old_ports) == 2
# do split of first segment again
# first port should be deleted, but 2nd one should remain untouched
segment.split_segment(0)
self.assertFalse(old_ports[0] in self.line.ports())
self.assertEqual(old_ports[1], self.line.ports()[2])
def test_constraints_after_split(self):
"""Test if constraints are recreated after line split
"""
# connect line2 to self.line
line2 = Line()
self.canvas.add(line2)
head = line2.handles()[0]
self.tool.connect(line2, head, (25, 25))
cinfo = self.canvas.get_connection(head)
self.assertEqual(self.line, cinfo.connected)
Segment(self.line, self.view).split_segment(0)
assert len(self.line.handles()) == 3
h1, h2, h3 = self.line.handles()
cinfo = self.canvas.get_connection(head)
# connection shall be reconstrained between 1st and 2nd handle
self.assertEqual(h1.pos, cinfo.constraint._line[0]._point)
self.assertEqual(h2.pos, cinfo.constraint._line[1]._point)
def test_split_undo(self):
"""Test line splitting undo
"""
self.line.handles()[1].pos = (20, 0)
# we start with two handles and one port, after split 3 handles and
# 2 ports are expected
assert len(self.line.handles()) == 2
assert len(self.line.ports()) == 1
segment = Segment(self.line, self.view)
segment.split_segment(0)
assert len(self.line.handles()) == 3
assert len(self.line.ports()) == 2
# after undo, 2 handles and 1 port are expected again
undo()
self.assertEqual(2, len(self.line.handles()))
self.assertEqual(1, len(self.line.ports()))
def test_orthogonal_line_split(self):
"""Test orthogonal line splitting
"""
# start with no orthogonal constraints
assert len(self.line._orthogonal_constraints) == 0
segment = Segment(self.line, None)
segment.split_segment(0)
self.line.orthogonal = True
# check orthogonal constraints
self.assertEqual(2, len(self.line._orthogonal_constraints))
self.assertEqual(3, len(self.line.handles()))
Segment(self.line, self.view).split_segment(0)
# 3 handles and 2 ports are expected
# 2 constraints keep the self.line orthogonal
self.assertEqual(3, len(self.line._orthogonal_constraints))
self.assertEqual(4, len(self.line.handles()))
self.assertEqual(3, len(self.line.ports()))
def test_params_errors(self):
"""Test parameter error exceptions
"""
line = Line()
segment = Segment(line, self.view)
# there is only 1 segment
self.assertRaises(ValueError, segment.split_segment, -1)
line = Line()
segment = Segment(line, self.view)
self.assertRaises(ValueError, segment.split_segment, 1)
line = Line()
# can't split into one or less segment :)
segment = Segment(line, self.view)
self.assertRaises(ValueError, segment.split_segment, 0, 1)
class LineMergeTestCase(TestCaseBase):
"""
Tests for line merging.
"""
def test_merge_first_single(self):
"""Test single line merging starting from 1st segment
"""
self.line.handles()[1].pos = (20, 0)
segment = Segment(self.line, self.view)
segment.split_segment(0)
# we start with 3 handles and 2 ports, after merging 2 handles and
# 1 port are expected
assert len(self.line.handles()) == 3
assert len(self.line.ports()) == 2
old_ports = self.line.ports()[:]
segment = Segment(self.line, self.view)
handles, ports = segment.merge_segment(0)
# deleted handles and ports
self.assertEqual(1, len(handles))
self.assertEqual(2, len(ports))
# handles and ports left after segment merging
self.assertEqual(2, len(self.line.handles()))
self.assertEqual(1, len(self.line.ports()))
self.assertTrue(handles[0] not in self.line.handles())
self.assertTrue(ports[0] not in self.line.ports())
self.assertTrue(ports[1] not in self.line.ports())
# old ports are completely removed as they are replaced by new one
# port
self.assertEqual(old_ports, ports)
# finally, created port shall span between first and last handle
port = self.line.ports()[0]
self.assertEqual((0, 0), port.start.pos)
self.assertEqual((20, 0), port.end.pos)
def test_constraints_after_merge(self):
"""Test if constraints are recreated after line merge
"""
# connect line2 to self.line
line2 = Line()
self.canvas.add(line2)
head = line2.handles()[0]
# conn = Connector(line2, head)
# sink = conn.glue((25, 25))
# assert sink is not None
# conn.connect(sink)
self.tool.connect(line2, head, (25, 25))
cinfo = self.canvas.get_connection(head)
self.assertEqual(self.line, cinfo.connected)
segment = Segment(self.line, self.view)
segment.split_segment(0)
assert len(self.line.handles()) == 3
c1 = cinfo.constraint
segment.merge_segment(0)
assert len(self.line.handles()) == 2
h1, h2 = self.line.handles()
# connection shall be reconstrained between 1st and 2nd handle
cinfo = self.canvas.get_connection(head)
self.assertEqual(cinfo.constraint._line[0]._point, h1.pos)
self.assertEqual(cinfo.constraint._line[1]._point, h2.pos)
self.assertFalse(c1 == cinfo.constraint)
def test_merge_multiple(self):
"""Test multiple line merge
"""
self.line.handles()[1].pos = (20, 16)
segment = Segment(self.line, self.view)
segment.split_segment(0, count=3)
# start with 4 handles and 3 ports, merge 3 segments
assert len(self.line.handles()) == 4
assert len(self.line.ports()) == 3
handles, ports = segment.merge_segment(0, count=3)
self.assertEqual(2, len(handles))
self.assertEqual(3, len(ports))
self.assertEqual(2, len(self.line.handles()))
self.assertEqual(1, len(self.line.ports()))
self.assertTrue(not set(handles).intersection(set(self.line.handles())))
self.assertTrue(not set(ports).intersection(set(self.line.ports())))
# finally, created port shall span between first and last handle
port = self.line.ports()[0]
self.assertEqual((0, 0), port.start.pos)
self.assertEqual((20, 16), port.end.pos)
def test_merge_undo(self):
"""Test line merging undo
"""
self.line.handles()[1].pos = (20, 0)
segment = Segment(self.line, self.view)
# split for merging
segment.split_segment(0)
assert len(self.line.handles()) == 3
assert len(self.line.ports()) == 2
# clear undo stack before merging
del undo_list[:]
# merge with empty undo stack
segment.merge_segment(0)
assert len(self.line.handles()) == 2
assert len(self.line.ports()) == 1
# after merge undo, 3 handles and 2 ports are expected again
undo()
self.assertEqual(3, len(self.line.handles()))
self.assertEqual(2, len(self.line.ports()))
def test_orthogonal_line_merge(self):
"""Test orthogonal line merging
"""
self.assertEqual(4, len(self.canvas.solver._constraints))
self.line.handles()[-1].pos = 100, 100
segment = Segment(self.line, self.view)
# prepare the self.line for merging
segment.split_segment(0)
segment.split_segment(0)
self.line.orthogonal = True
self.assertEqual(4 + 3, len(self.canvas.solver._constraints))
self.assertEqual(4, len(self.line.handles()))
self.assertEqual(3, len(self.line.ports()))
# test the merging
segment.merge_segment(0)
self.assertEqual(4 + 2, len(self.canvas.solver._constraints))
self.assertEqual(3, len(self.line.handles()))
self.assertEqual(2, len(self.line.ports()))
def test_params_errors(self):
"""Test parameter error exceptions
"""
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
segment.split_segment(0)
# no segment -1
self.assertRaises(ValueError, segment.merge_segment, -1)
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
segment.split_segment(0)
# no segment no 2
self.assertRaises(ValueError, segment.merge_segment, 2)
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
segment.split_segment(0)
# can't merge one or less segments :)
self.assertRaises(ValueError, segment.merge_segment, 0, 1)
line = Line()
self.canvas.add(line)
self.assertEqual(2, len(line.handles()))
segment = Segment(line, self.view)
# can't merge line with one segment
self.assertRaises(ValueError, segment.merge_segment, 0)
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
segment.split_segment(0)
# 2 segments: no 0 and 1. cannot merge as there are no segments
# after segment no 1
self.assertRaises(ValueError, segment.merge_segment, 1)
line = Line()
self.canvas.add(line)
segment = Segment(line, self.view)
segment.split_segment(0)
# 2 segments: no 0 and 1. cannot merge 3 segments as there are no 3
# segments
self.assertRaises(ValueError, segment.merge_segment, 0, 3)
class SegmentHandlesTest(unittest.TestCase):
def setUp(self):
class SegmentFixture(object):
def __init__(self):
self.canvas = Canvas()
self.line = Line()
self.canvas.add(self.line)
self.view = View(self.canvas)
def testHandleFinder(self):
finder = HandleFinder(self.line, self.view)
assert type(finder) is SegmentHandleFinder, type(finder)
self.item = Item()
# vim:sw=4:et:ai
@pytest.fixture(name="seg")
def segment_fixture():
return SegmentFixture()
def test_segment_fails_for_item(seg):
"""Test if Segment aspect can be applied to Item.
"""
try:
s = Segment(seg.item, seg.view)
except TypeError as e:
pass
else:
assert False, "Should not be reached"
def test_segment(seg):
"""Test add a new segment to a line.
"""
line = Line()
seg.canvas.add(line)
segment = Segment(line, seg.view)
assert 2 == len(line.handles())
segment.split((5, 5))
assert 3 == len(line.handles())
# Test Line Splitting
def test_split_single(simple_canvas):
"""Test single line splitting
"""
# Start with 2 handles & 1 port, after split: expect 3 handles & 2 ports
assert len(simple_canvas.line.handles()) == 2
assert len(simple_canvas.line.ports()) == 1
old_port = simple_canvas.line.ports()[0]
h1, h2 = simple_canvas.line.handles()
assert h1.pos == old_port.start
assert h2.pos == old_port.end
segment = Segment(simple_canvas.line, simple_canvas.view)
handles, ports = segment.split_segment(0)
handle = handles[0]
assert 1 == len(handles)
assert (50, 50) == handle.pos.pos
assert 3 == len(simple_canvas.line.handles())
assert 2 == len(simple_canvas.line.ports())
# New handle is between old handles
assert handle == simple_canvas.line.handles()[1]
# The old port is deleted
assert old_port not in simple_canvas.line.ports()
# check ports order
p1, p2 = simple_canvas.line.ports()
h1, h2, h3 = simple_canvas.line.handles()
assert h1.pos == p1.start
assert h2.pos == p1.end
assert h2.pos == p2.start
assert h3.pos == p2.end
def test_split_multiple(simple_canvas):
"""Test multiple line splitting.
"""
simple_canvas.line.handles()[1].pos = (20, 16)
handles = simple_canvas.line.handles()
old_ports = simple_canvas.line.ports()[:]
# Start with two handles, split into 4 segments: expect 3 new handles
assert len(handles) == 2
assert len(old_ports) == 1
segment = Segment(simple_canvas.line, simple_canvas.view)
handles, ports = segment.split_segment(0, count=4)
assert 3 == len(handles)
h1, h2, h3 = handles
assert (5, 4) == h1.pos.pos
assert (10, 8) == h2.pos.pos
assert (15, 12) == h3.pos.pos
# New handles between old handles
assert 5 == len(simple_canvas.line.handles())
assert h1 == simple_canvas.line.handles()[1]
assert h2 == simple_canvas.line.handles()[2]
assert h3 == simple_canvas.line.handles()[3]
assert 4 == len(simple_canvas.line.ports())
# The old port is deleted
assert old_ports[0] not in simple_canvas.line.ports()
# Check ports order
p1, p2, p3, p4 = simple_canvas.line.ports()
h1, h2, h3, h4, h5 = simple_canvas.line.handles()
assert h1.pos == p1.start
assert h2.pos == p1.end
assert h2.pos == p2.start
assert h3.pos == p2.end
assert h3.pos == p3.start
assert h4.pos == p3.end
assert h4.pos == p4.start
assert h5.pos == p4.end
def test_ports_after_split(simple_canvas):
"""Test ports removal after split
"""
simple_canvas.line.handles()[1].pos = (20, 16)
segment = Segment(simple_canvas.line, simple_canvas.view)
segment.split_segment(0)
handles = simple_canvas.line.handles()
old_ports = simple_canvas.line.ports()[:]
# Start with 3 handles and 2 ports
assert len(handles) == 3
assert len(old_ports) == 2
# Split 1st segment again: 1st port should be deleted, but 2nd one should
# remain untouched
segment.split_segment(0)
assert not (old_ports[0] in simple_canvas.line.ports())
assert old_ports[1] == simple_canvas.line.ports()[2]
def test_constraints_after_split(simple_canvas):
"""Test if constraints are recreated after line split.
"""
# Connect line2 to self.line
line2 = Line()
simple_canvas.canvas.add(line2)
head = line2.handles()[0]
simple_canvas.tool.connect(line2, head, (25, 25))
cinfo = simple_canvas.canvas.get_connection(head)
assert simple_canvas.line == cinfo.connected
Segment(simple_canvas.line, simple_canvas.view).split_segment(0)
assert len(simple_canvas.line.handles()) == 3
h1, h2, h3 = simple_canvas.line.handles()
cinfo = simple_canvas.canvas.get_connection(head)
# Connection shall be reconstrained between 1st and 2nd handle
assert h1.pos == cinfo.constraint._line[0]._point
assert h2.pos == cinfo.constraint._line[1]._point
def test_split_undo(simple_canvas, revert_undo, undo_fixture):
"""Test line splitting undo.
"""
simple_canvas.line.handles()[1].pos = (20, 0)
# We start with two handles and one port, after split 3 handles and
# 2 ports are expected
assert len(simple_canvas.line.handles()) == 2
assert len(simple_canvas.line.ports()) == 1
segment = Segment(simple_canvas.line, simple_canvas.view)
segment.split_segment(0)
assert len(simple_canvas.line.handles()) == 3
assert len(simple_canvas.line.ports()) == 2
# After undo, 2 handles and 1 port are expected again
undo_fixture[0]() # Call Undo
assert 2 == len(simple_canvas.line.handles())
assert 1 == len(simple_canvas.line.ports())
def test_orthogonal_line_split(simple_canvas):
"""Test orthogonal line splitting.
"""
# Start with no orthogonal constraints
assert len(simple_canvas.line._orthogonal_constraints) == 0
segment = Segment(simple_canvas.line, None)
segment.split_segment(0)
simple_canvas.line.orthogonal = True
# Check orthogonal constraints
assert 2 == len(simple_canvas.line._orthogonal_constraints)
assert 3 == len(simple_canvas.line.handles())
Segment(simple_canvas.line, simple_canvas.view).split_segment(0)
# 3 handles and 2 ports are expected
# 2 constraints keep the self.line orthogonal
assert 3 == len(simple_canvas.line._orthogonal_constraints)
assert 4 == len(simple_canvas.line.handles())
assert 3 == len(simple_canvas.line.ports())
def test_params_error_exc(simple_canvas):
"""Test parameter error exceptions.
"""
line = Line()
segment = Segment(line, simple_canvas.view)
# There is only 1 segment
with pytest.raises(ValueError):
segment.split_segment(-1)
line = Line()
segment = Segment(line, simple_canvas.view)
with pytest.raises(ValueError):
segment.split_segment(1)
line = Line()
# Can't split into one or less segment :)
segment = Segment(line, simple_canvas.view)
with pytest.raises(ValueError):
segment.split_segment(0, 1)
# Test Line Merging
def test_merge_first_single(simple_canvas):
"""Test single line merging starting from 1st segment.
"""
simple_canvas.line.handles()[1].pos = (20, 0)
segment = Segment(simple_canvas.line, simple_canvas.view)
segment.split_segment(0)
# We start with 3 handles and 2 ports, after merging 2 handles and 1 port
# are expected
assert len(simple_canvas.line.handles()) == 3
assert len(simple_canvas.line.ports()) == 2
old_ports = simple_canvas.line.ports()[:]
segment = Segment(simple_canvas.line, simple_canvas.view)
handles, ports = segment.merge_segment(0)
# Deleted handles and ports
assert 1 == len(handles)
assert 2 == len(ports)
# Handles and ports left after segment merging
assert 2 == len(simple_canvas.line.handles())
assert 1 == len(simple_canvas.line.ports())
assert handles[0] not in simple_canvas.line.handles()
assert ports[0] not in simple_canvas.line.ports()
assert ports[1] not in simple_canvas.line.ports()
# Old ports are completely removed as they are replaced by new one port
assert old_ports == ports
# Finally, created port shall span between first and last handle
port = simple_canvas.line.ports()[0]
assert (0, 0) == port.start.pos
assert (20, 0) == port.end.pos
def test_constraints_after_merge(simple_canvas):
"""Test if constraints are recreated after line merge.
"""
line2 = Line()
simple_canvas.canvas.add(line2)
head = line2.handles()[0]
simple_canvas.tool.connect(line2, head, (25, 25))
cinfo = simple_canvas.canvas.get_connection(head)
assert simple_canvas.line == cinfo.connected
segment = Segment(simple_canvas.line, simple_canvas.view)
segment.split_segment(0)
assert len(simple_canvas.line.handles()) == 3
c1 = cinfo.constraint
segment.merge_segment(0)
assert len(simple_canvas.line.handles()) == 2
h1, h2 = simple_canvas.line.handles()
# Connection shall be reconstrained between 1st and 2nd handle
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo.constraint._line[0]._point == h1.pos
assert cinfo.constraint._line[1]._point == h2.pos
assert not (c1 == cinfo.constraint)
def test_merge_multiple(simple_canvas):
"""Test multiple line merge.
"""
simple_canvas.line.handles()[1].pos = (20, 16)
segment = Segment(simple_canvas.line, simple_canvas.view)
segment.split_segment(0, count=3)
# Start with 4 handles and 3 ports, merge 3 segments
assert len(simple_canvas.line.handles()) == 4
assert len(simple_canvas.line.ports()) == 3
handles, ports = segment.merge_segment(0, count=3)
assert 2 == len(handles)
assert 3 == len(ports)
assert 2 == len(simple_canvas.line.handles())
assert 1 == len(simple_canvas.line.ports())
assert not set(handles).intersection(set(simple_canvas.line.handles()))
assert not set(ports).intersection(set(simple_canvas.line.ports()))
# Finally, the created port shall span between first and last handle
port = simple_canvas.line.ports()[0]
assert (0, 0) == port.start.pos
assert (20, 16) == port.end.pos
def test_merge_undo(simple_canvas, revert_undo, undo_fixture):
"""Test line merging undo.
"""
simple_canvas.line.handles()[1].pos = (20, 0)
segment = Segment(simple_canvas.line, simple_canvas.view)
# Split for merging
segment.split_segment(0)
assert len(simple_canvas.line.handles()) == 3
assert len(simple_canvas.line.ports()) == 2
# Clear undo stack before merging
del undo_fixture[2][:]
# Merge with empty undo stack
segment.merge_segment(0)
assert len(simple_canvas.line.handles()) == 2
assert len(simple_canvas.line.ports()) == 1
# After merge undo, 3 handles and 2 ports are expected again
undo_fixture[0]() # Undo
assert 3 == len(simple_canvas.line.handles())
assert 2 == len(simple_canvas.line.ports())
def test_orthogonal_line_merge(simple_canvas):
"""Test orthogonal line merging.
"""
assert 4 == len(simple_canvas.canvas.solver._constraints)
simple_canvas.line.handles()[-1].pos = 100, 100
segment = Segment(simple_canvas.line, simple_canvas.view)
# Prepare the self.line for merging
segment.split_segment(0)
segment.split_segment(0)
simple_canvas.line.orthogonal = True
assert 4 + 3 == len(simple_canvas.canvas.solver._constraints)
assert 4 == len(simple_canvas.line.handles())
assert 3 == len(simple_canvas.line.ports())
# Test the merging
segment.merge_segment(0)
assert 4 + 2 == len(simple_canvas.canvas.solver._constraints)
assert 3 == len(simple_canvas.line.handles())
assert 2 == len(simple_canvas.line.ports())
@pytest.mark.parametrize("num_segments", [-1, 2, (0, 1), 0, 1, (0, 3)])
def test_params_errors(simple_canvas, num_segments):
"""Test parameter error exceptions.
"""
line = Line()
simple_canvas.canvas.add(line)
segment = Segment(line, simple_canvas.view)
with pytest.raises(ValueError):
if isinstance(num_segments, tuple):
segment.split_segment(0)
segment.merge_segment(num_segments[0], num_segments[1])
elif num_segments == 0:
assert 2 == len(line.handles())
segment.merge_segment(0)
else:
segment.split_segment(0)
segment.merge_segment(num_segments)
def test_handle_finder(seg):
finder = HandleFinder(seg.line, seg.view)
assert type(finder) is SegmentHandleFinder, type(finder)

View File

@ -1,15 +1,15 @@
"""
Unit tests for Gaphas' solver.
"""
from __future__ import print_function
from __future__ import division
"""Test constraint solver.
"""
from __future__ import division
from __future__ import print_function
import unittest
from timeit import Timer
from gaphas.solver import Solver, Variable
from gaphas.constraint import EquationConstraint, EqualsConstraint, LessThanConstraint
import pytest
from gaphas.constraint import EquationConstraint, EqualsConstraint, LessThanConstraint
from gaphas.solver import Solver, Variable
SETUP = """
from gaphas.solver import Solver, Variable
@ -25,143 +25,118 @@ REPEAT = 30
NUMBER = 1000
class WeakestVariableTestCase(unittest.TestCase):
class SolverFixture(object):
def __init__(self):
self.solver = Solver()
self.a = Variable(1, 30)
self.b = Variable(2, 10)
self.c = Variable(3, 10)
self.c_eq = EquationConstraint(
lambda a, b, c: a + b + c, a=self.a, b=self.b, c=self.c
)
self.solver.add_constraint(self.c_eq)
@pytest.fixture(name="solv")
def solver_fixture():
return SolverFixture()
def test_weakest_list(solv):
"""Test weakest list.
"""
Test weakest variable calculation.
assert solv.b in solv.c_eq._weakest
assert solv.c in solv.c_eq._weakest
def test_weakest_list_order(solv):
"""Test weakest list order.
"""
weakest = [el for el in solv.c_eq._weakest]
solv.a.value = 4
def test_weakest_list(self):
"""Test weakest list"""
solver = Solver()
a = Variable(1, 30)
b = Variable(2, 10)
c = Variable(3, 10)
assert solv.c_eq._weakest == weakest # Does not change if non-weak variable changed
c_eq = EquationConstraint(lambda a, b, c: a + b + c, a=a, b=b, c=c)
solver.add_constraint(c_eq)
solv.b.value = 5
assert solv.c_eq.weakest() == solv.c
# because of kwargs above we cannot test by the order of arguments
self.assertTrue(b in c_eq._weakest)
self.assertTrue(c in c_eq._weakest)
solv.b.value = 6
assert solv.c_eq.weakest() == solv.c
def test_weakest_list_order(self):
"""Test weakest list order"""
solver = Solver()
a = Variable(1, 30)
b = Variable(2, 10)
c = Variable(3, 10)
# b changed above, now change a - all weakest variables changed return the
# oldest changed variable
solv.c.value = 6
assert solv.c_eq.weakest() == solv.b
c_eq = EquationConstraint(lambda a, b, c: a + b + c, a=a, b=b, c=c)
solver.add_constraint(c_eq)
weakest = [el for el in c_eq._weakest]
a.value = 4
self.assertEqual(
c_eq._weakest, weakest
) # does not change if non-weak variable changed
b.value = 5
self.assertEqual(c_eq.weakest(), c)
b.value = 6
self.assertEqual(c_eq.weakest(), c)
# b changed above, now change a - all weakest variables changed
# return the oldest changed variable then
c.value = 6
self.assertEqual(c_eq.weakest(), b)
b.value = 6
self.assertEqual(c_eq.weakest(), c)
def test_strength_change(self):
"""Test strength change"""
solver = Solver()
a = Variable(1, 30)
b = Variable(2, 10)
c = Variable(3, 10)
c_eq = EquationConstraint(lambda a, b, c: a + b + c, a=a, b=b, c=c)
solver.add_constraint(c_eq)
b.strength = 9
self.assertEqual(c_eq._weakest, [b])
solv.b.value = 6
assert solv.c_eq.weakest() == solv.c
class SizeTestCase(unittest.TestCase):
def test_strength_change(solv):
"""Test strength change.
"""
Test size related constraints, i.e. minimal size.
solv.b.strength = 9
assert solv.c_eq._weakest == [solv.b]
def test_min_size(solv):
"""Test minimal size constraint.
"""
v1 = Variable(0)
v2 = Variable(10)
v3 = Variable(10)
c1 = EqualsConstraint(a=v2, b=v3)
c2 = LessThanConstraint(smaller=v1, bigger=v3, delta=10)
solv.solver.add_constraint(c1)
solv.solver.add_constraint(c2)
def test_min_size(self):
"""Test minimal size constraint"""
solver = Solver()
v1 = Variable(0)
v2 = Variable(10)
v3 = Variable(10)
c1 = EqualsConstraint(a=v2, b=v3)
c2 = LessThanConstraint(smaller=v1, bigger=v3, delta=10)
solver.add_constraint(c1)
solver.add_constraint(c2)
# Check everything is ok on start
solv.solver.solve()
assert 0 == v1
assert 10 == v2
assert 10 == v3
# check everyting is ok on start
solver.solve()
self.assertEqual(0, v1)
self.assertEqual(10, v2)
self.assertEqual(10, v3)
# Change v1 to 2, after solve it should be 0 again due to LT constraint
v1.value = 2
solv.solver.solve()
# change v1 to 2, after solve it should be 0 again due to LT
# constraint
v1.value = 2
solver.solve()
assert 0 == v1
assert 10 == v2
assert 10 == v3
self.assertEqual(0, v1)
self.assertEqual(10, v2)
self.assertEqual(10, v3)
# Change v3 to 20, after solve v2 will follow thanks to EQ constraint
v3.value = 20
solv.solver.solve()
# change v3 to 20, after solve v2 will follow thanks to EQ
# constraint
v3.value = 20
solver.solve()
assert 0 == v1
assert 20 == v2
assert 20 == v3
self.assertEqual(0, v1)
self.assertEqual(20, v2)
self.assertEqual(20, v3)
# Change v3 to 0, after solve it should be 10 due to LT.delta = 10, v2
# should also be 10 due to EQ constraint
v3.value = 0
solv.solver.solve()
# change v3 to 0, after solve it shoul be 10 due to LT.delta = 10,
# v2 should also be 10 due to EQ constraint
v3.value = 0
solver.solve()
self.assertEqual(0, v1)
self.assertEqual(10, v2)
self.assertEqual(10, v3)
assert 0 == v1
assert 10 == v2
assert 10 == v3
class SolverSpeedTestCase(unittest.TestCase):
def test_speed_run_weakest():
"""Speed test for weakest variable.
"""
Solver speed tests.
"""
def _test_speed_run_weakest(self):
"""
Speed test for weakest variable.
"""
results = Timer(
setup=SETUP,
stmt="""
results = Timer(
setup=SETUP,
stmt="""
v1.value = 5.0
c_eq.weakest()""",
).repeat(repeat=REPEAT, number=NUMBER)
).repeat(repeat=REPEAT, number=NUMBER)
# Print the average of the best 10 runs:
results.sort()
print("[Avg: %gms]" % ((sum(results[:10]) / 10)) * 1000)
if __name__ == "__main__":
unittest.main()
# vim:sw=4:et:ai
# Print the average of the best 10 runs:
results.sort()
print("[Avg: %gms]" % (sum(results[:10]) / 10) * 1000)

View File

@ -1,5 +1,4 @@
import sys
import unittest
from builtins import object
from gaphas.state import reversible_pair, observed, _reverse
@ -22,19 +21,19 @@ class SList(object):
self.list.remove(self.list.index(node))
class StateTestCase(unittest.TestCase):
def test_adding_pair(self):
"""Test adding reversible pair
"""
reversible_pair(
SList.add,
SList.remove,
bind1={"before": lambda self, node: self.list[self.list.index(node) + 1]},
)
def test_adding_pair():
"""Test adding reversible pair.
if sys.version_info.major >= 3: # Modern Python
self.assertTrue(SList.add in _reverse)
self.assertTrue(SList.remove in _reverse)
else: # Legacy Python
self.assertTrue(SList.add.__func__ in _reverse)
self.assertTrue(SList.remove.__func__ in _reverse)
"""
reversible_pair(
SList.add,
SList.remove,
bind1={"before": lambda self, node: self.list[self.list.index(node) + 1]},
)
if sys.version_info.major >= 3: # Modern Python
assert SList.add in _reverse
assert SList.remove in _reverse
else: # Legacy Python
assert SList.add.__func__ in _reverse
assert SList.remove.__func__ in _reverse

View File

@ -1,251 +1,167 @@
"""Test all the tools.
"""
Test all the tools provided by gaphas.
"""
import unittest
from gi.repository import Gtk
from gaphas.canvas import Canvas
from gaphas.canvas import Context
from gaphas.constraint import LineConstraint
from gaphas.examples import Box
from gaphas.item import Line
from gaphas.tool import ConnectHandleTool
from gaphas.view import GtkView
Event = Context
def simple_canvas(self):
# Test handle connection tool glue method
def test_item_and_port_glue(simple_canvas):
"""Test glue operation to an item and its ports.
"""
This decorator adds view, canvas and handle connection tool to a test
case. Two boxes and a line are added to the canvas as well.
ports = simple_canvas.box1.ports()
# Glue to port nw-ne
sink = simple_canvas.tool.glue(simple_canvas.line, simple_canvas.head, (120, 50))
assert sink.item == simple_canvas.box1
assert ports[0] == sink.port
# Glue to port ne-se
sink = simple_canvas.tool.glue(simple_canvas.line, simple_canvas.head, (140, 70))
assert sink.item == simple_canvas.box1
assert ports[1] == sink.port
# Glue to port se-sw
sink = simple_canvas.tool.glue(simple_canvas.line, simple_canvas.head, (120, 90))
assert sink.item == simple_canvas.box1
assert ports[2] == sink.port
# Glue to port sw-nw
sink = simple_canvas.tool.glue(simple_canvas.line, simple_canvas.head, (100, 70))
assert sink.item == simple_canvas.box1
assert ports[3] == sink.port
def test_failed_glue(simple_canvas):
"""Test glue from too far distance.
"""
self.canvas = Canvas()
self.box1 = Box()
self.canvas.add(self.box1)
self.box1.matrix.translate(100, 50)
self.box1.width = 40
self.box1.height = 40
self.box1.request_update()
self.box2 = Box()
self.canvas.add(self.box2)
self.box2.matrix.translate(100, 150)
self.box2.width = 50
self.box2.height = 50
self.box2.request_update()
self.line = Line()
self.head = self.line.handles()[0]
self.tail = self.line.handles()[-1]
self.tail.pos = 100, 100
self.canvas.add(self.line)
self.canvas.update_now()
self.view = GtkView()
self.view.canvas = self.canvas
win = Gtk.Window()
win.add(self.view)
self.view.show()
self.view.update()
win.show()
self.tool = ConnectHandleTool(self.view)
sink = simple_canvas.tool.glue(simple_canvas.line, simple_canvas.head, (90, 50))
assert sink is None
class ConnectHandleToolGlueTestCase(unittest.TestCase):
"""
Test handle connection tool glue method.
def test_glue_no_port_no_can_glue(simple_canvas):
"""Test no glue with no port.
Test if glue method does not call ConnectHandleTool.can_glue method when
port is not found.
"""
def setUp(self):
simple_canvas(self)
class Tool(ConnectHandleTool):
def __init__(self, *args):
super(Tool, self).__init__(*args)
self._calls = 0
def test_item_and_port_glue(self):
"""Test glue operation to an item and its ports"""
def can_glue(self, *args):
self._calls += 1
ports = self.box1.ports()
# glue to port nw-ne
sink = self.tool.glue(self.line, self.head, (120, 50))
self.assertEqual(sink.item, self.box1)
self.assertEqual(ports[0], sink.port)
# glue to port ne-se
sink = self.tool.glue(self.line, self.head, (140, 70))
self.assertEqual(sink.item, self.box1)
self.assertEqual(ports[1], sink.port)
# glue to port se-sw
sink = self.tool.glue(self.line, self.head, (120, 90))
self.assertEqual(sink.item, self.box1)
self.assertEqual(ports[2], sink.port)
# glue to port sw-nw
sink = self.tool.glue(self.line, self.head, (100, 70))
self.assertEqual(sink.item, self.box1)
self.assertEqual(ports[3], sink.port)
def test_failed_glue(self):
"""Test glue from too far distance"""
sink = self.tool.glue(self.line, self.head, (90, 50))
self.assertTrue(sink is None)
# def test_glue_call_can_glue_once(self):
# """Test if glue method calls can glue once only
#
# Box has 4 ports. Every port is examined once per
# ConnectHandleTool.glue method call. The purpose of this test is to
# assure that ConnectHandleTool.can_glue is called once (for the
# found port), it cannot be called four times (once for every port).
# """
#
# # count ConnectHandleTool.can_glue calls
# class Tool(ConnectHandleTool):
# def __init__(self, *args):
# super(Tool, self).__init__(*args)
# self._calls = 0
#
# def can_glue(self, *args):
# self._calls += 1
# return True
#
# tool = Tool(self.view)
# item, port = tool.glue(self.line, self.head, (120, 50))
# assert item and port
# self.assertEqual(1, tool._calls)
# def test_glue_cannot_glue(self):
# """Test if glue method respects ConnectHandleTool.can_glue method"""
#
# class Tool(ConnectHandleTool):
# def can_glue(self, *args):
# return False
#
# tool = Tool(self.view)
# item, port = tool.glue(self.line, self.head, (120, 50))
# self.assertTrue(item is None, item)
# self.assertTrue(port is None, port)
def test_glue_no_port_no_can_glue(self):
"""Test if glue method does not call ConnectHandleTool.can_glue method when port is not found"""
class Tool(ConnectHandleTool):
def __init__(self, *args):
super(Tool, self).__init__(*args)
self._calls = 0
def can_glue(self, *args):
self._calls += 1
tool = Tool(self.view)
# at 300, 50 there should be no item
sink = tool.glue(self.line, self.head, (300, 50))
assert sink is None
self.assertEqual(0, tool._calls)
tool = Tool(simple_canvas.view)
# At 300, 50 there should be no item
sink = tool.glue(simple_canvas.line, simple_canvas.head, (300, 50))
assert sink is None
assert 0 == tool._calls
class ConnectHandleToolConnectTestCase(unittest.TestCase):
def setUp(self):
simple_canvas(self)
def test_connect(simple_canvas):
"""Test connection to an item.
def _get_line(self):
line = Line()
head = line.handles()[0]
self.canvas.add(line)
return line, head
"""
line, head = simple_canvas.line, simple_canvas.head
simple_canvas.tool.connect(line, head, (120, 50))
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo is not None
assert simple_canvas.box1 == cinfo.connected
assert cinfo.port is simple_canvas.box1.ports()[0], "port %s" % cinfo.port
assert isinstance(cinfo.constraint, LineConstraint)
# No default callback defined:
assert cinfo.callback is None
def test_connect(self):
"""Test connection to an item"""
line, head = self._get_line()
self.tool.connect(line, head, (120, 50))
cinfo = self.canvas.get_connection(head)
self.assertTrue(cinfo is not None)
self.assertEqual(self.box1, cinfo.connected)
self.assertTrue(cinfo.port is self.box1.ports()[0], "port %s" % cinfo.port)
self.assertTrue(isinstance(cinfo.constraint, LineConstraint))
# No default callback defined:
self.assertTrue(cinfo.callback is None)
line, head = self._get_line()
self.tool.connect(line, head, (90, 50))
cinfo2 = self.canvas.get_connection(head)
self.assertTrue(cinfo is not cinfo2, cinfo2)
self.assertTrue(cinfo2 is None, cinfo2)
def test_reconnect_another(self):
"""Test reconnection to another item"""
line, head = self._get_line()
self.tool.connect(line, head, (120, 50))
cinfo = self.canvas.get_connection(head)
assert cinfo is not None
item = cinfo.connected
port = cinfo.port
constraint = cinfo.constraint
assert item == self.box1
assert port == self.box1.ports()[0]
assert item != self.box2
# connect to box2, handle's connected item and connection data
# should differ
self.tool.connect(line, head, (120, 150))
cinfo = self.canvas.get_connection(head)
assert cinfo is not None
self.assertEqual(self.box2, cinfo.connected)
self.assertEqual(self.box2.ports()[0], cinfo.port)
# old connection does not exist
self.assertNotEqual(item, cinfo.connected)
self.assertNotEqual(constraint, cinfo.constraint)
def test_reconnect_same(self):
"""Test reconnection to same item"""
line, head = self._get_line()
self.tool.connect(line, head, (120, 50))
cinfo = self.canvas.get_connection(head)
assert cinfo is not None
item = cinfo.connected
port = cinfo.port
constraint = cinfo.constraint
assert item == self.box1
assert item != self.box2
# connect to box1 again, handle's connected item and port should be
# the same but connection constraint will differ
connected = self.tool.connect(line, head, (120, 50))
cinfo = self.canvas.get_connection(head)
assert cinfo is not None
self.assertEqual(self.box1, cinfo.connected)
self.assertEqual(self.box1.ports()[0], cinfo.port)
self.assertNotEqual(constraint, cinfo.constraint)
def xtest_find_port(self):
"""Test finding a port
"""
line, head = self._get_line()
p1, p2, p3, p4 = self.box1.ports()
head.pos = 110, 50
port = self.tool.find_port(line, head, self.box1)
self.assertEqual(p1, port)
head.pos = 140, 60
port = self.tool.find_port(line, head, self.box1)
self.assertEqual(p2, port)
head.pos = 110, 95
port = self.tool.find_port(line, head, self.box1)
self.assertEqual(p3, port)
head.pos = 100, 55
port = self.tool.find_port(line, head, self.box1)
self.assertEqual(p4, port)
line, head = simple_canvas.line, simple_canvas.head
simple_canvas.tool.connect(line, head, (90, 50))
cinfo2 = simple_canvas.canvas.get_connection(head)
assert cinfo is not cinfo2, cinfo2
assert cinfo2 is None, cinfo2
# vim: sw=4:et:ai
def test_reconnect_another(simple_canvas):
"""Test reconnection to another item.
"""
line, head = simple_canvas.line, simple_canvas.head
simple_canvas.tool.connect(line, head, (120, 50))
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo is not None
item = cinfo.connected
port = cinfo.port
constraint = cinfo.constraint
assert item == simple_canvas.box1
assert port == simple_canvas.box1.ports()[0]
assert item != simple_canvas.box2
# Connect to box2, handle's connected item and connection data should
# differ
simple_canvas.tool.connect(line, head, (120, 150))
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo is not None
assert simple_canvas.box2 == cinfo.connected
assert simple_canvas.box2.ports()[0] == cinfo.port
# Old connection does not exist
assert item != cinfo.connected
assert constraint != cinfo.constraint
def test_reconnect_same(simple_canvas):
"""Test reconnection to same item.
"""
line, head = simple_canvas.line, simple_canvas.head
simple_canvas.tool.connect(line, head, (120, 50))
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo is not None
item = cinfo.connected
constraint = cinfo.constraint
assert item == simple_canvas.box1
assert item != simple_canvas.box2
# Connect to box1 again, handle's connected item and port should be the
# same but connection constraint will differ
simple_canvas.tool.connect(line, head, (120, 50))
cinfo = simple_canvas.canvas.get_connection(head)
assert cinfo is not None
assert simple_canvas.box1 == cinfo.connected
assert simple_canvas.box1.ports()[0] == cinfo.port
assert constraint != cinfo.constraint
def xtest_find_port(simple_canvas):
"""Test finding a port.
"""
line, head = simple_canvas.line, simple_canvas.head
p1, p2, p3, p4 = simple_canvas.box1.ports()
head.pos = 110, 50
port = simple_canvas.tool.find_port(line, head, simple_canvas.box1)
assert p1 == port
head.pos = 140, 60
port = simple_canvas.tool.find_port(line, head, simple_canvas.box1)
assert p2 == port
head.pos = 110, 95
port = simple_canvas.tool.find_port(line, head, simple_canvas.box1)
assert p3 == port
head.pos = 100, 55
port = simple_canvas.tool.find_port(line, head, simple_canvas.box1)
assert p4 == port

View File

@ -1,164 +1,145 @@
import unittest
import pytest
from gaphas.tree import Tree
class TreeTestCase(unittest.TestCase):
def test_add(self):
"""
Test creating node trees.
"""
tree = Tree()
n1 = "n1"
n2 = "n2"
n3 = "n3"
tree.add(n1)
assert len(tree._nodes) == 1
assert len(tree._children) == 2
assert len(tree._children[None]) == 1
assert len(tree._children[n1]) == 0
tree.add(n2)
tree.add(n3, parent=n1)
assert len(tree._nodes) == 3
assert len(tree._children) == 4
assert len(tree._children[None]) == 2
assert len(tree._children[n1]) == 1
assert len(tree._children[n2]) == 0
assert len(tree._children[n2]) == 0
assert tree._nodes == [n1, n3, n2]
n4 = "n4"
tree.add(n4, parent=n3)
assert tree._nodes == [n1, n3, n4, n2]
n5 = "n5"
tree.add(n5, parent=n3)
assert tree._nodes == [n1, n3, n4, n5, n2]
n6 = "n6"
tree.add(n6, parent=n2)
assert tree._nodes == [n1, n3, n4, n5, n2, n6]
n7 = "n7"
tree.add(n7, parent=n1)
assert len(tree._children) == 8
assert tree._nodes == [n1, n3, n4, n5, n7, n2, n6]
assert tree.get_parent(n7) is n1
assert tree.get_parent(n6) is n2
assert tree.get_parent(n5) is n3
assert tree.get_parent(n4) is n3
assert tree.get_parent(n3) is n1
assert tree.get_parent(n2) is None
assert tree.get_parent(n1) is None
def test_add_on_index(self):
tree = Tree()
n1 = "n1"
n2 = "n2"
n3 = "n3"
n4 = "n4"
n5 = "n5"
tree.add(n1)
tree.add(n2)
tree.add(n3, index=1)
assert tree.get_children(None) == [n1, n3, n2], tree.get_children(None)
assert tree.nodes == [n1, n3, n2], tree.nodes
tree.add(n4, parent=n3)
tree.add(n5, parent=n3, index=0)
assert tree.get_children(None) == [n1, n3, n2], tree.get_children(None)
assert tree.nodes == [n1, n3, n5, n4, n2], tree.nodes
assert tree.get_children(n3) == [n5, n4], tree.get_children(n3)
def test_remove(self):
"""
Test removal of nodes.
"""
tree = Tree()
n1 = "n1"
n2 = "n2"
n3 = "n3"
n4 = "n4"
n5 = "n5"
tree.add(n1)
tree.add(n2)
tree.add(n3, parent=n1)
tree.add(n4, parent=n3)
tree.add(n5, parent=n4)
assert tree._nodes == [n1, n3, n4, n5, n2]
all_ch = list(tree.get_all_children(n1))
assert all_ch == [n3, n4, n5], all_ch
tree.remove(n4)
assert tree._nodes == [n1, n3, n2]
tree.remove(n1)
assert len(tree._children) == 2
assert tree._children[None] == [n2]
assert tree._children[n2] == []
assert tree._nodes == [n2]
def test_siblings(self):
tree = Tree()
n1 = "n1"
n2 = "n2"
n3 = "n3"
tree.add(n1)
tree.add(n2)
tree.add(n3)
assert tree.get_next_sibling(n1) is n2
assert tree.get_next_sibling(n2) is n3
try:
tree.get_next_sibling(n3)
except IndexError:
pass # okay
else:
raise AssertionError(
"Index should be out of range, not %s" % tree.get_next_sibling(n3)
)
assert tree.get_previous_sibling(n3) is n2
assert tree.get_previous_sibling(n2) is n1
try:
tree.get_previous_sibling(n1)
except IndexError:
pass # okay
else:
raise AssertionError(
"Index should be out of range, not %s" % tree.get_previous_sibling(n1)
)
def test_reparent(self):
tree = Tree()
n1 = "n1"
n2 = "n2"
n3 = "n3"
n4 = "n4"
n5 = "n5"
tree.add(n1)
tree.add(n2)
tree.add(n3)
tree.add(n4, parent=n2)
tree.add(n5, parent=n4)
assert tree.nodes == [n1, n2, n4, n5, n3], tree.nodes
tree.reparent(n4, parent=n1, index=0)
assert tree.nodes == [n1, n4, n5, n2, n3], tree.nodes
assert tree.get_children(n2) == [], tree.get_children(n2)
assert tree.get_children(n1) == [n4], tree.get_children(n1)
assert tree.get_children(n4) == [n5], tree.get_children(n4)
tree.reparent(n4, parent=None, index=0)
assert tree.nodes == [n4, n5, n1, n2, n3], tree.nodes
@pytest.fixture()
def tree_fixture():
node = ["n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7"]
return Tree(), node
# vi:sw=4:et:ai
def test_add(tree_fixture):
""" Test creating node trees.
"""
tree = tree_fixture[0]
n = tree_fixture[1]
tree.add(n[1])
assert len(tree._nodes) == 1
assert len(tree._children) == 2
assert len(tree._children[None]) == 1
assert len(tree._children[n[1]]) == 0
tree.add(n[2])
tree.add(n[3], parent=n[1])
assert len(tree._nodes) == 3
assert len(tree._children) == 4
assert len(tree._children[None]) == 2
assert len(tree._children[n[1]]) == 1
assert len(tree._children[n[2]]) == 0
assert len(tree._children[n[2]]) == 0
assert tree._nodes == [n[1], n[3], n[2]]
tree.add(n[4], parent=n[3])
assert tree._nodes == [n[1], n[3], n[4], n[2]]
tree.add(n[5], parent=n[3])
assert tree._nodes == [n[1], n[3], n[4], n[5], n[2]]
tree.add(n[6], parent=n[2])
assert tree._nodes == [n[1], n[3], n[4], n[5], n[2], n[6]]
tree.add(n[7], parent=n[1])
assert len(tree._children) == 8
assert tree._nodes == [n[1], n[3], n[4], n[5], n[7], n[2], n[6]]
assert tree.get_parent(n[7]) is n[1]
assert tree.get_parent(n[6]) is n[2]
assert tree.get_parent(n[5]) is n[3]
assert tree.get_parent(n[4]) is n[3]
assert tree.get_parent(n[3]) is n[1]
assert tree.get_parent(n[2]) is None
assert tree.get_parent(n[1]) is None
def test_add_on_index(tree_fixture):
tree = tree_fixture[0]
n = tree_fixture[1]
tree.add(n[1])
tree.add(n[2])
tree.add(n[3], index=1)
assert tree.get_children(None) == [n[1], n[3], n[2]], tree.get_children(None)
assert tree.nodes == [n[1], n[3], n[2]], tree.nodes
tree.add(n[4], parent=n[3])
tree.add(n[5], parent=n[3], index=0)
assert tree.get_children(None) == [n[1], n[3], n[2]], tree.get_children(None)
assert tree.nodes == [n[1], n[3], n[5], n[4], n[2]], tree.nodes
assert tree.get_children(n[3]) == [n[5], n[4]], tree.get_children(n[3])
def test_remove(tree_fixture):
"""Test removal of nodes.
"""
tree = tree_fixture[0]
n = tree_fixture[1]
tree.add(n[1])
tree.add(n[2])
tree.add(n[3], parent=n[1])
tree.add(n[4], parent=n[3])
tree.add(n[5], parent=n[4])
assert tree._nodes == [n[1], n[3], n[4], n[5], n[2]]
all_ch = list(tree.get_all_children(n[1]))
assert all_ch == [n[3], n[4], n[5]], all_ch
tree.remove(n[4])
assert tree._nodes == [n[1], n[3], n[2]]
tree.remove(n[1])
assert len(tree._children) == 2
assert tree._children[None] == [n[2]]
assert tree._children[n[2]] == []
assert tree._nodes == [n[2]]
def test_siblings(tree_fixture):
tree = tree_fixture[0]
n = tree_fixture[1]
tree.add(n[1])
tree.add(n[2])
tree.add(n[3])
assert tree.get_next_sibling(n[1]) is n[2]
assert tree.get_next_sibling(n[2]) is n[3]
try:
tree.get_next_sibling(n[3])
except IndexError:
pass # Okay
else:
raise AssertionError(
"Index should be out of range, not %s" % tree.get_next_sibling(n[3])
)
assert tree.get_previous_sibling(n[3]) is n[2]
assert tree.get_previous_sibling(n[2]) is n[1]
try:
tree.get_previous_sibling(n[1])
except IndexError:
pass # Okay
else:
raise AssertionError(
"Index should be out of range, not %s" % tree.get_previous_sibling(n[1])
)
def test_reparent(tree_fixture):
tree = tree_fixture[0]
n = tree_fixture[1]
tree.add(n[1])
tree.add(n[2])
tree.add(n[3])
tree.add(n[4], parent=n[2])
tree.add(n[5], parent=n[4])
assert tree.nodes == [n[1], n[2], n[4], n[5], n[3]], tree.nodes
tree.reparent(n[4], parent=n[1], index=0)
assert tree.nodes == [n[1], n[4], n[5], n[2], n[3]], tree.nodes
assert tree.get_children(n[2]) == [], tree.get_children(n[2])
assert tree.get_children(n[1]) == [n[4]], tree.get_children(n[1])
assert tree.get_children(n[4]) == [n[5]], tree.get_children(n[4])
tree.reparent(n[4], parent=None, index=0)
assert tree.nodes == [n[4], n[5], n[1], n[2], n[3]], tree.nodes

View File

@ -1,103 +1,58 @@
import unittest
from gaphas import state
from gaphas.aspect import Connector, ConnectionSink
from gaphas.canvas import Canvas
from gaphas.examples import Box
from gaphas.item import Line
state.observers.clear()
state.subscribers.clear()
undo_list = []
redo_list = []
def test_undo_on_delete_element(revert_undo, undo_fixture):
b1 = Box()
b2 = Box()
line = Line()
canvas = Canvas()
canvas.add(b1)
assert 2 == len(canvas.solver.constraints)
def undo_handler(event):
undo_list.append(event)
canvas.add(b2)
assert 4 == len(canvas.solver.constraints)
canvas.add(line)
def undo():
apply_me = list(undo_list)
del undo_list[:]
apply_me.reverse()
for e in apply_me:
state.saveapply(*e)
redo_list[:] = undo_list[:]
del undo_list[:]
sink = ConnectionSink(b1, b1.ports()[0])
connector = Connector(line, line.handles()[0])
connector.connect(sink)
sink = ConnectionSink(b2, b2.ports()[0])
connector = Connector(line, line.handles()[-1])
connector.connect(sink)
class UndoTestCase(unittest.TestCase):
def setUp(self):
state.observers.add(state.revert_handler)
state.subscribers.add(undo_handler)
assert 6 == len(canvas.solver.constraints)
assert 2 == len(list(canvas.get_connections(item=line)))
def shutDown(self):
state.observers.remove(state.revert_handler)
state.subscribers.remove(undo_handler)
del undo_fixture[2][:] # Clear undo_list
def testUndoOnDeletedElement(self):
b1 = Box()
# Here disconnect is not invoked!
canvas.remove(b2)
b2 = Box()
line = Line()
assert 3 == len(canvas.solver.constraints)
assert 1 == len(list(canvas.get_connections(item=line)))
canvas = Canvas()
canvas.add(b1)
self.assertEqual(2, len(canvas.solver.constraints))
cinfo = canvas.get_connection(line.handles()[0])
assert b1 == cinfo.connected
canvas.add(b2)
self.assertEqual(4, len(canvas.solver.constraints))
cinfo = canvas.get_connection(line.handles()[-1])
assert cinfo is None
canvas.add(line)
assert [] == list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.x))
assert [] == list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.y))
sink = ConnectionSink(b1, b1.ports()[0])
connector = Connector(line, line.handles()[0])
connector.connect(sink)
undo_fixture[0]() # Call undo
sink = ConnectionSink(b2, b2.ports()[0])
connector = Connector(line, line.handles()[-1])
connector.connect(sink)
assert 6 == len(canvas.solver.constraints)
assert 2 == len(list(canvas.get_connections(item=line)))
self.assertEqual(6, len(canvas.solver.constraints))
self.assertEqual(2, len(list(canvas.get_connections(item=line))))
cinfo = canvas.get_connection(line.handles()[0])
assert b1 == cinfo.connected
del undo_list[:]
# Here disconnect is not invoked!
canvas.remove(b2)
self.assertEqual(3, len(canvas.solver.constraints))
self.assertEqual(1, len(list(canvas.get_connections(item=line))))
cinfo = canvas.get_connection(line.handles()[0])
self.assertEqual(b1, cinfo.connected)
cinfo = canvas.get_connection(line.handles()[-1])
self.assertEqual(None, cinfo)
self.assertEqual(
[], list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.x))
)
self.assertEqual(
[], list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.y))
)
undo()
self.assertEqual(6, len(canvas.solver.constraints))
self.assertEqual(2, len(list(canvas.get_connections(item=line))))
cinfo = canvas.get_connection(line.handles()[0])
self.assertEqual(b1, cinfo.connected)
cinfo = canvas.get_connection(line.handles()[-1])
self.assertEqual(b2, cinfo.connected)
# self.assertEqual(list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.x)))
# self.assertTrue(list(canvas.solver.constraints_with_variable(line.handles()[-1].pos.y)))
if __name__ == "__main__":
unittest.main()
# vim:sw=4:et:ai
cinfo = canvas.get_connection(line.handles()[-1])
assert b2 == cinfo.connected

View File

@ -1,11 +1,11 @@
"""
Test cases for the View class.
"""Test cases for the View class.
"""
from __future__ import division
import math
import unittest
import pytest
from gi.repository import Gtk
from gaphas.canvas import Canvas
@ -14,259 +14,229 @@ from gaphas.item import Line
from gaphas.view import View, GtkView
class ViewTestCase(unittest.TestCase):
def test_bounding_box_calculations(self):
"""
A view created before and after the canvas is populated should contain
the same data.
"""
canvas = Canvas()
class ViewFixture(object):
def __init__(self):
self.canvas = Canvas()
self.view = GtkView(self.canvas)
self.window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
self.window.add(self.view)
self.window.show_all()
window1 = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
view1 = GtkView(canvas=canvas)
window1.add(view1)
view1.realize()
window1.show_all()
box = Box()
box.matrix = (1.0, 0.0, 0.0, 1, 10, 10)
canvas.add(box)
line = Line()
line.fyzzyness = 1
line.handles()[1].pos = (30, 30)
# line.split_segment(0, 3)
line.matrix.translate(30, 60)
canvas.add(line)
window2 = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
view2 = GtkView(canvas=canvas)
window2.add(view2)
window2.show_all()
# Process pending (expose) events, which cause the canvas to be drawn.
while Gtk.events_pending():
Gtk.main_iteration()
try:
assert view2.get_item_bounding_box(box)
assert view1.get_item_bounding_box(box)
assert view1.get_item_bounding_box(box) == view2.get_item_bounding_box(
box
), (
"%s != %s"
% (view1.get_item_bounding_box(box), view2.get_item_bounding_box(box))
)
assert view1.get_item_bounding_box(line) == view2.get_item_bounding_box(
line
), (
"%s != %s"
% (view1.get_item_bounding_box(line), view2.get_item_bounding_box(line))
)
finally:
window1.destroy()
window2.destroy()
def test_get_item_at_point(self):
"""
Hover tool only reacts on motion-notify events
"""
canvas = Canvas()
view = GtkView(canvas)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
box = Box()
canvas.add(box)
self.box = Box()
self.canvas.add(self.box)
# No gtk main loop, so updates occur instantly
assert not canvas.require_update()
box.width = 50
box.height = 50
assert not self.canvas.require_update()
# Process pending (expose) events, which cause the canvas to be drawn.
while Gtk.events_pending():
Gtk.main_iteration()
assert len(view._qtree._ids) == 1
assert not view._qtree._bucket.bounds == (
0,
0,
0,
0,
), view._qtree._bucket.bounds
assert view.get_item_at_point((10, 10)) is box
assert view.get_item_at_point((60, 10)) is None
window.destroy()
def test_get_handle_at_point(self):
canvas = Canvas()
view = GtkView(canvas)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
box = Box()
box.min_width = 20
box.min_height = 30
box.matrix.translate(20, 20)
box.matrix.rotate(math.pi / 1.5)
canvas.add(box)
i, h = view.get_handle_at_point((20, 20))
assert i is box
assert h is box.handles()[0]
def test_get_handle_at_point_at_pi_div_2(self):
canvas = Canvas()
view = GtkView(canvas)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
box = Box()
box.min_width = 20
box.min_height = 30
box.matrix.translate(20, 20)
box.matrix.rotate(math.pi / 2)
canvas.add(box)
p = canvas.get_matrix_i2c(box).transform_point(0, 20)
p = canvas.get_matrix_c2i(box).transform_point(20, 20)
i, h = view.get_handle_at_point((20, 20))
assert i is box
assert h is box.handles()[0]
def test_item_removal(self):
canvas = Canvas()
view = GtkView(canvas)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
box = Box()
canvas.add(box)
# No gtk main loop, so updates occur instantly
assert not canvas.require_update()
# Process pending (expose) events, which cause the canvas to be drawn.
while Gtk.events_pending():
Gtk.main_iteration()
assert len(canvas.get_all_items()) == len(view._qtree)
view.focused_item = box
canvas.remove(box)
assert len(canvas.get_all_items()) == 0
assert len(view._qtree) == 0
window.destroy()
def test_view_registration(self):
canvas = Canvas()
# Simple views do not register on the canvas
view = View(canvas)
assert len(canvas._registered_views) == 0
box = Box()
canvas.add(box)
# By default no complex updating/calculations are done:
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
# GTK view does register for updates though
view = GtkView(canvas)
assert len(canvas._registered_views) == 1
# No entry, since GtkView is not realized and has no window
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
# Now everything is realized and updated
assert view in box._matrix_i2v
assert view in box._matrix_v2i
view.canvas = None
assert len(canvas._registered_views) == 0
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
view.canvas = canvas
assert len(canvas._registered_views) == 1
assert view in box._matrix_i2v
assert view in box._matrix_v2i
def test_view_registration_2(self):
"""
Test view registration and destroy when view is destroyed.
"""
canvas = Canvas()
view = GtkView(canvas)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
box = Box()
canvas.add(box)
assert hasattr(box, "_matrix_i2v")
assert hasattr(box, "_matrix_v2i")
assert box._matrix_i2v[view]
assert box._matrix_v2i[view]
assert len(canvas._registered_views) == 1
assert view in canvas._registered_views
window.destroy()
assert len(canvas._registered_views) == 0
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
def test_scroll_adjustments_signal(self):
sc = Gtk.ScrolledWindow()
view = GtkView(Canvas())
sc.add(view)
assert view.hadjustment
assert view.vadjustment
assert view.hadjustment.get_value() == 0.0
assert view.hadjustment.get_lower() == 0.0
assert view.hadjustment.get_upper() == 1.0
assert view.hadjustment.get_step_increment() == 0.0
assert view.hadjustment.get_page_increment() == 1.0
assert view.hadjustment.get_page_size() == 1.0
assert view.vadjustment.get_value() == 0.0
assert view.vadjustment.get_lower() == 0.0
assert view.vadjustment.get_upper() == 1.0
assert view.vadjustment.get_step_increment() == 0.0
assert view.vadjustment.get_page_increment() == 1.0
assert view.vadjustment.get_page_size() == 1.0
def test_scroll_adjustments(self):
sc = Gtk.ScrolledWindow()
view = GtkView(Canvas())
sc.add(view)
assert sc.get_hadjustment() is view.hadjustment
assert sc.get_vadjustment() is view.vadjustment
@pytest.fixture()
def view_fixture():
return ViewFixture()
if __name__ == "__main__":
unittest.main()
def test_bounding_box_calculations(view_fixture):
"""A view created before and after the canvas is populated should contain
the same data.
# vim:sw=4:et:ai
"""
view_fixture.view.realize()
view_fixture.box.matrix = (1.0, 0.0, 0.0, 1, 10, 10)
line = Line()
line.fuzziness = 1
line.handles()[1].pos = (30, 30)
line.matrix.translate(30, 60)
view_fixture.canvas.add(line)
window2 = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
view2 = GtkView(canvas=view_fixture.canvas)
window2.add(view2)
window2.show_all()
# Process pending (expose) events, which cause the canvas to be drawn.
while Gtk.events_pending():
Gtk.main_iteration()
try:
assert view2.get_item_bounding_box(view_fixture.box)
assert view_fixture.view.get_item_bounding_box(view_fixture.box)
assert view_fixture.view.get_item_bounding_box(
view_fixture.box
) == view2.get_item_bounding_box(view_fixture.box), (
"%s != %s"
% (
view_fixture.view.get_item_bounding_box(view_fixture.box),
view2.get_item_bounding_box(view_fixture.box),
)
)
assert view_fixture.view.get_item_bounding_box(
line
) == view2.get_item_bounding_box(line), (
"%s != %s"
% (
view_fixture.view.get_item_bounding_box(line),
view2.get_item_bounding_box(line),
)
)
finally:
view_fixture.window.destroy()
window2.destroy()
def test_get_item_at_point(view_fixture):
"""Hover tool only reacts on motion-notify events.
"""
view_fixture.box.width = 50
view_fixture.box.height = 50
assert len(view_fixture.view._qtree._ids) == 1
assert not view_fixture.view._qtree._bucket.bounds == (
0,
0,
0,
0,
), view_fixture.view._qtree._bucket.bounds
assert view_fixture.view.get_item_at_point((10, 10)) is view_fixture.box
assert view_fixture.view.get_item_at_point((60, 10)) is None
view_fixture.window.destroy()
def test_get_handle_at_point(view_fixture):
box = Box()
box.min_width = 20
box.min_height = 30
box.matrix.translate(20, 20)
box.matrix.rotate(math.pi / 1.5)
view_fixture.canvas.add(box)
i, h = view_fixture.view.get_handle_at_point((20, 20))
assert i is box
assert h is box.handles()[0]
def test_get_handle_at_point_at_pi_div_2(view_fixture):
box = Box()
box.min_width = 20
box.min_height = 30
box.matrix.translate(20, 20)
box.matrix.rotate(math.pi / 2)
view_fixture.canvas.add(box)
box.matrix.translate(20, 20)
box.matrix.rotate(math.pi / 2)
i, h = view_fixture.view.get_handle_at_point((20, 20))
assert i is box
assert h is box.handles()[0]
def test_item_removal(view_fixture):
assert len(view_fixture.canvas.get_all_items()) == len(view_fixture.view._qtree)
view_fixture.view.focused_item = view_fixture.box
view_fixture.canvas.remove(view_fixture.box)
assert len(view_fixture.canvas.get_all_items()) == 0
assert len(view_fixture.view._qtree) == 0
view_fixture.window.destroy()
def test_view_registration(view_fixture):
canvas = Canvas()
# Simple views do not register on the canvas
view = View(canvas)
assert len(canvas._registered_views) == 0
box = Box()
canvas.add(box)
# By default no complex updating/calculations are done:
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
# GTK view does register for updates though
view = GtkView(canvas)
assert len(canvas._registered_views) == 1
# No entry, since GtkView is not realized and has no window
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
window.add(view)
window.show_all()
# Now everything is realized and updated
assert view in box._matrix_i2v
assert view in box._matrix_v2i
view.canvas = None
assert len(canvas._registered_views) == 0
assert view not in box._matrix_i2v
assert view not in box._matrix_v2i
view.canvas = canvas
assert len(canvas._registered_views) == 1
assert view in box._matrix_i2v
assert view in box._matrix_v2i
def test_view_registration_2(view_fixture):
"""Test view registration and destroy when view is destroyed.
"""
assert hasattr(view_fixture.box, "_matrix_i2v")
assert hasattr(view_fixture.box, "_matrix_v2i")
assert view_fixture.box._matrix_i2v[view_fixture.view]
assert view_fixture.box._matrix_v2i[view_fixture.view]
assert len(view_fixture.canvas._registered_views) == 1
assert view_fixture.view in view_fixture.canvas._registered_views
view_fixture.window.destroy()
assert len(view_fixture.canvas._registered_views) == 0
assert view_fixture.view not in view_fixture.box._matrix_i2v
assert view_fixture.view not in view_fixture.box._matrix_v2i
@pytest.fixture()
def sc_view():
sc = Gtk.ScrolledWindow()
view = GtkView(Canvas())
sc.add(view)
return view, sc
def test_scroll_adjustments_signal(sc_view):
assert sc_view[0].hadjustment
assert sc_view[0].vadjustment
assert sc_view[0].hadjustment.get_value() == 0.0
assert sc_view[0].hadjustment.get_lower() == 0.0
assert sc_view[0].hadjustment.get_upper() == 1.0
assert sc_view[0].hadjustment.get_step_increment() == 0.0
assert sc_view[0].hadjustment.get_page_increment() == 1.0
assert sc_view[0].hadjustment.get_page_size() == 1.0
assert sc_view[0].vadjustment.get_value() == 0.0
assert sc_view[0].vadjustment.get_lower() == 0.0
assert sc_view[0].vadjustment.get_upper() == 1.0
assert sc_view[0].vadjustment.get_step_increment() == 0.0
assert sc_view[0].vadjustment.get_page_increment() == 1.0
assert sc_view[0].vadjustment.get_page_size() == 1.0
def test_scroll_adjustments(sc_view):
assert sc_view[1].get_hadjustment() is sc_view[0].hadjustment
assert sc_view[1].get_vadjustment() is sc_view[0].vadjustment

View File

@ -252,7 +252,7 @@ class View(object):
if -d < (hx - x) < d and -d < (hy - y) < d:
return h
# The focused item is the prefered item for handle grabbing
# The focused item is the preferred item for handle grabbing
if self.focused_item:
h = find(self.focused_item)
if h: