Qobjectの比較

djangoのQobjectの比較する関数を書いた。Qobjectは順序不同になるので、比較がめんどうだった。
(他に楽に比較する方法があるのかもしれないけれど)

  1. 別にnoseの関数を使う必要はないけれど。
from django.conf import settings
settings.configure()

from django.db.models import Q
from nose.tools import eq_,  ok_
from itertools import izip

def q_equal(q1, q2):
    if hasattr(q1, "connector") and hasattr(q2, "connector"):
        if q1.connector == q2.connector:
            for x, y in izip(sorted(q1.children, key=str), sorted(q2.children, key=str)):
                if not q_equal(x, y):
                    return False
            return True
    else:
        return q1 == q2

def q_eq(q1, q2):
    try:
        ok_(q_equal(q1, q2))
    except AssertionError, e:
        print("a:%s" % q1)
        print("b:%s" % q2)
        raise e


def test_success_simple():
    q_eq(Q(x="foo"),  Q(x="foo"))

def test_fail_simple():
    q_eq(Q(x="foo"), Q(x="bar"))

def test_success_2elements():
    q_eq(Q(x="foo")& Q(y="bar"), Q(y="bar") & Q(x="foo"))

def test_success_3elements():
    qobj0 = Q(x="foo") & Q(y="bar") & Q(z="boo")
    qobj1 = Q(y="bar") & Q(z="boo") & Q(x="foo")
    q_eq(qobj0, qobj1)

def test_fail_3elements():
    qobj0 = Q(x="foo") & Q(y="bar") & Q(z="boo")
    qobj1 = Q(y="bar") | Q(z="boo") & Q(x="foo")
    q_eq(qobj0, qobj1)

AssertaionErrorが出たときのdiffの表示が適当過ぎるような気もするけれど。

実行結果

5つテストして、2つ失敗するテスト.

$ nosetest compare_qobject.py
correct: nosetest -> nosetests [nyae]? y
y
======================================================================
FAIL: compare_qobject.test_fail_simple
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/nose/case.py", line 187, in runTest
    self.test(*self.arg)
  File "/home/podhmo/compare_qobject.py", line 31, in test_fail_simple
    q_eq(Q(x="foo"), Q(x="bar"))
  File "/home/podhmo/compare_qobject.py", line 24, in q_eq
    raise e
AssertionError: 
-------------------- >> begin captured stdout << ---------------------
a:(AND: ('x', 'foo'))
b:(AND: ('x', 'bar'))

--------------------- >> end captured stdout << ----------------------

======================================================================
FAIL: compare_qobject.test_fail_3elements
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/nose/case.py", line 187, in runTest
    self.test(*self.arg)
  File "/home/podhmo/compare_qobject.py", line 44, in test_fail_3elements
    q_eq(qobj0, qobj1)
  File "/home/podhmo/compare_qobject.py", line 24, in q_eq
    raise e
AssertionError: 
-------------------- >> begin captured stdout << ---------------------
a:(AND: ('x', 'foo'), ('y', 'bar'), ('z', 'boo'))
b:(OR: ('y', 'bar'), (AND: ('z', 'boo'), ('x', 'foo')))

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 5 tests in 0.002s

FAILED (failures=2)