Commit aa1df0e4 authored by Julien Muchembled's avatar Julien Muchembled

Float divergence testers: workaround issues due to limited precision of floats

This fixes test_01c_PackingListSplitBuildInvoiceBuild (testLegacyTradeModelLine).

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@41890 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 7538d9b5
......@@ -33,6 +33,9 @@ from Products.ERP5Type.Core.Predicate import Predicate
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.mixin.equivalence_tester import EquivalenceTesterMixin
# On Python >= 2.6, we could compute a value based on sys.float_info.epsilon
DEFAULT_PRECISION = 1e-12
class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
""" Compare float values, with support for rounding.
"""
......@@ -79,12 +82,20 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
prevision_value = self._round(prevision_value)
delta = decision_value - prevision_value
if type(delta) is float:
# XXX: What if prevision or decision is 0 ?
# How to know if the other value is negligible or not ?
epsilon = abs(prevision_value * DEFAULT_PRECISION)
__lt__ = lambda a, b: a < b - epsilon
else:
from operator import __lt__
# XXX we should use appropriate property sheets and getter methods
# for these properties.
# Maybe, but beware of default values of quantity when doing so
absolute_tolerance_min = self.getProperty('quantity_range_min')
if absolute_tolerance_min is not None and \
delta < absolute_tolerance_min:
__lt__(delta, absolute_tolerance_min):
return (
prevision_value, decision_value,
'The difference of ${property_name} between decision and prevision is less than ${value}.',
......@@ -92,7 +103,7 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
value=absolute_tolerance_min))
absolute_tolerance_max = self.getProperty('quantity_range_max')
if absolute_tolerance_max is not None and \
delta > absolute_tolerance_max:
__lt__(absolute_tolerance_max, delta):
return (
prevision_value, decision_value,
'The difference of ${property_name} between decision and prevision is larger than ${value}.',
......
......@@ -139,6 +139,15 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
movement = sequence.get('movement')
movement.setQuantity(sim_mvt.getQuantity())
def stepSetPreviousQuantityWithEpsilon(self, sequence=None,
sequence_list=None, **kw):
sim_mvt = sequence.get('sim_mvt')
movement = sequence.get('movement')
prevision = sim_mvt.getQuantity()
decision = prevision * (1 + 1e-15)
self.assertNotEqual(prevision, decision)
movement.setQuantity(decision)
def stepAddQuantityDivergenceTester(self, sequence=None,
sequence_list=None, **kw):
"""
......@@ -155,17 +164,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return
sequence_list = SequenceList()
# Create a clean packing list
sequence_string = ' \
stepGetPackingList \
stepCheckPackingListIsNotDivergent \
stepSetNewQuantity \
stepCheckPackingListIsNotDivergent \
stepAddQuantityDivergenceTester \
stepCheckPackingListIsDivergent \
stepSetPreviousQuantity \
stepCheckPackingListIsNotDivergent \
Tic \
'
sequence_string = """
GetPackingList
CheckPackingListIsNotDivergent
SetNewQuantity
CheckPackingListIsNotDivergent
AddQuantityDivergenceTester
CheckPackingListIsDivergent
SetPreviousQuantity
CheckPackingListIsNotDivergent
SetPreviousQuantityWithEpsilon
CheckPackingListIsNotDivergent
Tic
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet)
......@@ -211,19 +222,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return
sequence_list = SequenceList()
# Create a clean packing list
sequence_string = ' \
stepGetPackingList \
stepCheckPackingListIsNotDivergent \
stepSetNewSource \
stepCheckPackingListIsNotDivergent \
stepAddCategoryDivergenceTester \
stepCheckPackingListIsNotDivergent \
stepConfigureCategoryDivergenceTesterForSource \
stepCheckPackingListIsDivergent \
stepSetPreviousSource \
stepCheckPackingListIsNotDivergent \
Tic \
'
sequence_string = """
GetPackingList
CheckPackingListIsNotDivergent
SetNewSource
CheckPackingListIsNotDivergent
AddCategoryDivergenceTester
CheckPackingListIsNotDivergent
ConfigureCategoryDivergenceTesterForSource
CheckPackingListIsDivergent
SetPreviousSource
CheckPackingListIsNotDivergent
Tic
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet)
......@@ -269,19 +280,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return
sequence_list = SequenceList()
# Create a clean packing list
sequence_string = ' \
stepGetPackingList \
stepCheckPackingListIsNotDivergent \
stepSetNewStartDate \
stepCheckPackingListIsNotDivergent \
stepAddPropertyDivergenceTester \
stepCheckPackingListIsNotDivergent \
stepConfigurePropertyDivergenceTesterForStartDate \
stepCheckPackingListIsDivergent \
stepSetPreviousStartDate \
stepCheckPackingListIsNotDivergent \
Tic \
'
sequence_string = """
GetPackingList
CheckPackingListIsNotDivergent
SetNewStartDate
CheckPackingListIsNotDivergent
AddPropertyDivergenceTester
CheckPackingListIsNotDivergent
ConfigurePropertyDivergenceTesterForStartDate
CheckPackingListIsDivergent
SetPreviousStartDate
CheckPackingListIsNotDivergent
Tic
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet)
......@@ -319,19 +330,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return
sequence_list = SequenceList()
# Create a clean packing list
sequence_string = ' \
stepGetPackingList \
stepCheckPackingListIsNotDivergent \
stepSetNewAggregate \
stepCheckPackingListIsNotDivergent \
stepAddCategoryDivergenceTester \
stepCheckPackingListIsNotDivergent \
stepConfigureCategoryDivergenceTesterForAggregate \
stepCheckPackingListIsDivergent \
stepSetPreviousAggregate \
stepCheckPackingListIsNotDivergent \
Tic \
'
sequence_string = """
GetPackingList
CheckPackingListIsNotDivergent
SetNewAggregate
CheckPackingListIsNotDivergent
AddCategoryDivergenceTester
CheckPackingListIsNotDivergent
ConfigureCategoryDivergenceTesterForAggregate
CheckPackingListIsDivergent
SetPreviousAggregate
CheckPackingListIsNotDivergent
Tic
"""
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet)
......
......@@ -33,6 +33,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.DivergenceMessage import DivergenceMessage
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.FloatEquivalenceTester import DEFAULT_PRECISION
class PropertyDivergenceTester(XMLObject):
"""
......@@ -88,6 +89,13 @@ class PropertyDivergenceTester(XMLObject):
delivery_mvt_property = delivery_mvt_getProperty(tested_property_id)
simulation_mvt_property = simulation_movement_getProperty(tested_property_id)
if delivery_mvt_property != simulation_mvt_property:
try:
# XXX: What if prevision or decision is 0 ?
if abs(delivery_mvt_property - simulation_mvt_property) <= \
abs(simulation_mvt_property * DEFAULT_PRECISION):
continue
except TypeError:
pass
message = DivergenceMessage(
divergence_scope='property',
object_relative_url=delivery_mvt.getRelativeUrl(),
......
......@@ -32,6 +32,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.DivergenceMessage import DivergenceMessage
from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
from Products.ERP5.Document.FloatEquivalenceTester import DEFAULT_PRECISION
from Products.ERP5Legacy.Document.PropertyDivergenceTester import \
PropertyDivergenceTester
......@@ -150,8 +151,7 @@ class QuantityDivergenceTester(PropertyDivergenceTester):
==
Decimal(str(y)).quantize(Decimal(self.getDecimalExponent()),
rounding=rounding_option))
else:
return x==y
return abs(x - y) <= abs(y * DEFAULT_PRECISION) # XXX: What if x or y is 0 ?
def getTestedProperty(self, default=None):
"""
......
......@@ -133,7 +133,7 @@ def checkTradeModelRuleSimulationExpand(self, delivery):
total_price = expected_result_dict[use].get(line.getId())
if total_price:
sm = result_dict.pop(use)
self.assertEqual(sm.getTotalPrice(), total_price)
self.assertEqual(str(sm.getTotalPrice()), str(total_price))
self.assertEqual(1, len(sm.getCausalityValueList()))
self.assertEqual(1, len(sm.getCausalityValueList(
portal_type='Business Path')))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment