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 ...@@ -33,6 +33,9 @@ from Products.ERP5Type.Core.Predicate import Predicate
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.mixin.equivalence_tester import EquivalenceTesterMixin 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): class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
""" Compare float values, with support for rounding. """ Compare float values, with support for rounding.
""" """
...@@ -79,12 +82,20 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin): ...@@ -79,12 +82,20 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
prevision_value = self._round(prevision_value) prevision_value = self._round(prevision_value)
delta = decision_value - 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 # XXX we should use appropriate property sheets and getter methods
# for these properties. # for these properties.
# Maybe, but beware of default values of quantity when doing so # Maybe, but beware of default values of quantity when doing so
absolute_tolerance_min = self.getProperty('quantity_range_min') absolute_tolerance_min = self.getProperty('quantity_range_min')
if absolute_tolerance_min is not None and \ if absolute_tolerance_min is not None and \
delta < absolute_tolerance_min: __lt__(delta, absolute_tolerance_min):
return ( return (
prevision_value, decision_value, prevision_value, decision_value,
'The difference of ${property_name} between decision and prevision is less than ${value}.', 'The difference of ${property_name} between decision and prevision is less than ${value}.',
...@@ -92,7 +103,7 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin): ...@@ -92,7 +103,7 @@ class FloatEquivalenceTester(Predicate, EquivalenceTesterMixin):
value=absolute_tolerance_min)) value=absolute_tolerance_min))
absolute_tolerance_max = self.getProperty('quantity_range_max') absolute_tolerance_max = self.getProperty('quantity_range_max')
if absolute_tolerance_max is not None and \ if absolute_tolerance_max is not None and \
delta > absolute_tolerance_max: __lt__(absolute_tolerance_max, delta):
return ( return (
prevision_value, decision_value, prevision_value, decision_value,
'The difference of ${property_name} between decision and prevision is larger than ${value}.', 'The difference of ${property_name} between decision and prevision is larger than ${value}.',
......
...@@ -139,6 +139,15 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase): ...@@ -139,6 +139,15 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
movement = sequence.get('movement') movement = sequence.get('movement')
movement.setQuantity(sim_mvt.getQuantity()) 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, def stepAddQuantityDivergenceTester(self, sequence=None,
sequence_list=None, **kw): sequence_list=None, **kw):
""" """
...@@ -155,17 +164,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase): ...@@ -155,17 +164,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return if not run: return
sequence_list = SequenceList() sequence_list = SequenceList()
# Create a clean packing list # Create a clean packing list
sequence_string = ' \ sequence_string = """
stepGetPackingList \ GetPackingList
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepSetNewQuantity \ SetNewQuantity
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepAddQuantityDivergenceTester \ AddQuantityDivergenceTester
stepCheckPackingListIsDivergent \ CheckPackingListIsDivergent
stepSetPreviousQuantity \ SetPreviousQuantity
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
Tic \ SetPreviousQuantityWithEpsilon
' CheckPackingListIsNotDivergent
Tic
"""
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet) sequence_list.play(self, quiet=self.quiet)
...@@ -211,19 +222,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase): ...@@ -211,19 +222,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return if not run: return
sequence_list = SequenceList() sequence_list = SequenceList()
# Create a clean packing list # Create a clean packing list
sequence_string = ' \ sequence_string = """
stepGetPackingList \ GetPackingList
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepSetNewSource \ SetNewSource
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepAddCategoryDivergenceTester \ AddCategoryDivergenceTester
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepConfigureCategoryDivergenceTesterForSource \ ConfigureCategoryDivergenceTesterForSource
stepCheckPackingListIsDivergent \ CheckPackingListIsDivergent
stepSetPreviousSource \ SetPreviousSource
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
Tic \ Tic
' """
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet) sequence_list.play(self, quiet=self.quiet)
...@@ -269,19 +280,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase): ...@@ -269,19 +280,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return if not run: return
sequence_list = SequenceList() sequence_list = SequenceList()
# Create a clean packing list # Create a clean packing list
sequence_string = ' \ sequence_string = """
stepGetPackingList \ GetPackingList
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepSetNewStartDate \ SetNewStartDate
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepAddPropertyDivergenceTester \ AddPropertyDivergenceTester
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepConfigurePropertyDivergenceTesterForStartDate \ ConfigurePropertyDivergenceTesterForStartDate
stepCheckPackingListIsDivergent \ CheckPackingListIsDivergent
stepSetPreviousStartDate \ SetPreviousStartDate
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
Tic \ Tic
' """
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet) sequence_list.play(self, quiet=self.quiet)
...@@ -319,19 +330,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase): ...@@ -319,19 +330,19 @@ class TestDivergenceTester(TestPackingListMixin, ERP5TypeTestCase):
if not run: return if not run: return
sequence_list = SequenceList() sequence_list = SequenceList()
# Create a clean packing list # Create a clean packing list
sequence_string = ' \ sequence_string = """
stepGetPackingList \ GetPackingList
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepSetNewAggregate \ SetNewAggregate
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepAddCategoryDivergenceTester \ AddCategoryDivergenceTester
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
stepConfigureCategoryDivergenceTesterForAggregate \ ConfigureCategoryDivergenceTesterForAggregate
stepCheckPackingListIsDivergent \ CheckPackingListIsDivergent
stepSetPreviousAggregate \ SetPreviousAggregate
stepCheckPackingListIsNotDivergent \ CheckPackingListIsNotDivergent
Tic \ Tic
' """
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
sequence_list.play(self, quiet=self.quiet) sequence_list.play(self, quiet=self.quiet)
......
...@@ -33,6 +33,7 @@ from AccessControl import ClassSecurityInfo ...@@ -33,6 +33,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.DivergenceMessage import DivergenceMessage from Products.ERP5Type.DivergenceMessage import DivergenceMessage
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.FloatEquivalenceTester import DEFAULT_PRECISION
class PropertyDivergenceTester(XMLObject): class PropertyDivergenceTester(XMLObject):
""" """
...@@ -88,6 +89,13 @@ class PropertyDivergenceTester(XMLObject): ...@@ -88,6 +89,13 @@ class PropertyDivergenceTester(XMLObject):
delivery_mvt_property = delivery_mvt_getProperty(tested_property_id) delivery_mvt_property = delivery_mvt_getProperty(tested_property_id)
simulation_mvt_property = simulation_movement_getProperty(tested_property_id) simulation_mvt_property = simulation_movement_getProperty(tested_property_id)
if delivery_mvt_property != simulation_mvt_property: 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( message = DivergenceMessage(
divergence_scope='property', divergence_scope='property',
object_relative_url=delivery_mvt.getRelativeUrl(), object_relative_url=delivery_mvt.getRelativeUrl(),
......
...@@ -32,6 +32,7 @@ from AccessControl import ClassSecurityInfo ...@@ -32,6 +32,7 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.DivergenceMessage import DivergenceMessage from Products.ERP5Type.DivergenceMessage import DivergenceMessage
from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
from Products.ERP5.Document.FloatEquivalenceTester import DEFAULT_PRECISION
from Products.ERP5Legacy.Document.PropertyDivergenceTester import \ from Products.ERP5Legacy.Document.PropertyDivergenceTester import \
PropertyDivergenceTester PropertyDivergenceTester
...@@ -150,8 +151,7 @@ class QuantityDivergenceTester(PropertyDivergenceTester): ...@@ -150,8 +151,7 @@ class QuantityDivergenceTester(PropertyDivergenceTester):
== ==
Decimal(str(y)).quantize(Decimal(self.getDecimalExponent()), Decimal(str(y)).quantize(Decimal(self.getDecimalExponent()),
rounding=rounding_option)) rounding=rounding_option))
else: return abs(x - y) <= abs(y * DEFAULT_PRECISION) # XXX: What if x or y is 0 ?
return x==y
def getTestedProperty(self, default=None): def getTestedProperty(self, default=None):
""" """
......
...@@ -133,7 +133,7 @@ def checkTradeModelRuleSimulationExpand(self, delivery): ...@@ -133,7 +133,7 @@ def checkTradeModelRuleSimulationExpand(self, delivery):
total_price = expected_result_dict[use].get(line.getId()) total_price = expected_result_dict[use].get(line.getId())
if total_price: if total_price:
sm = result_dict.pop(use) 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()))
self.assertEqual(1, len(sm.getCausalityValueList( self.assertEqual(1, len(sm.getCausalityValueList(
portal_type='Business Path'))) 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