From ba47b0d0a19eef192bc89ecfb2b46de52621f344 Mon Sep 17 00:00:00 2001 From: zyd Date: Mon, 4 Jul 2022 22:09:01 +0900 Subject: [PATCH] Fix some todos 1. solve negative zero issues --- ramda/private/_equals.py | 9 ++++++--- ramda/private/_helper.py | 6 ++++++ ramda/uniqBy.py | 1 - test/private/test__helper.py | 18 ++++++++++++++++++ test/test_constructN.py | 1 - test/test_difference.py | 3 +-- test/test_equals.py | 4 ---- test/test_indexOf.py | 3 +-- test/test_intersection.py | 3 ++- test/test_lastIndexOf.py | 3 +-- test/test_propEq.py | 3 ++- test/test_tap.py | 1 - test/test_toString.py | 4 +++- test/test_union.py | 3 ++- test/test_uniq.py | 4 ++-- test/test_uniqBy.py | 3 +-- 16 files changed, 45 insertions(+), 24 deletions(-) create mode 100644 test/private/test__helper.py diff --git a/ramda/private/_equals.py b/ramda/private/_equals.py index 12ace98..50f210f 100644 --- a/ramda/private/_equals.py +++ b/ramda/private/_equals.py @@ -1,14 +1,17 @@ from math import isnan -from ._helper import getAttribute +from ._helper import getAttribute, isNegativeFloatZero from ._isArrayLike import _isArrayLike from ._isFunction import _isFunction from ._isNumber import _isNumber def _equals(a, b): - if _isNumber(a) and isnan(a) and _isNumber(b) and isnan(b): - return True + if _isNumber(a) and _isNumber(b): + if isnan(a) and isnan(b): + return True + if a == 0 and b == 0: + return isNegativeFloatZero(a) == isNegativeFloatZero(b) # pylint: disable=unidiomatic-typecheck if type(a) != type(b): return False diff --git a/ramda/private/_helper.py b/ramda/private/_helper.py index 94531e1..d640337 100644 --- a/ramda/private/_helper.py +++ b/ramda/private/_helper.py @@ -1,4 +1,6 @@ +import math + from ._has import _has from ._isArrayLike import _isArrayLike @@ -76,3 +78,7 @@ def safeLen(x): if _isArrayLike(x): return len(x) return 0 + + +def isNegativeFloatZero(n): + return n == 0 and math.atan2(0.0, 0.0) != math.atan2(0.0, n) diff --git a/ramda/uniqBy.py b/ramda/uniqBy.py index b5344e0..78ecb5e 100644 --- a/ramda/uniqBy.py +++ b/ramda/uniqBy.py @@ -13,7 +13,6 @@ def inner_uniqBy(fn, arr): item = arr[idx] appliedItem = fn(item) if _set.add(appliedItem): - print(appliedItem, _set) result.append(item) idx += 1 return result diff --git a/test/private/test__helper.py b/test/private/test__helper.py new file mode 100644 index 0000000..803513b --- /dev/null +++ b/test/private/test__helper.py @@ -0,0 +1,18 @@ + +import unittest + +from ramda.private._helper import isNegativeFloatZero + + +class Test_Helper(unittest.TestCase): + def test_isNegativeZero(self): + self.assertEqual(True, isNegativeFloatZero(-0.0)) + self.assertEqual(False, isNegativeFloatZero(-0)) + self.assertEqual(False, isNegativeFloatZero(0)) + self.assertEqual(False, isNegativeFloatZero(0.0)) + self.assertEqual(False, isNegativeFloatZero(-0.1)) + self.assertEqual(False, isNegativeFloatZero(0.1)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_constructN.py b/test/test_constructN.py index 66042fd..75b6f5a 100644 --- a/test/test_constructN.py +++ b/test/test_constructN.py @@ -12,7 +12,6 @@ class Circle: def __init__(self, r, *args): - print(args) self.r = r self.colors = list(args) diff --git a/test/test_difference.py b/test/test_difference.py index 9a79216..a0d5dea 100644 --- a/test/test_difference.py +++ b/test/test_difference.py @@ -24,8 +24,7 @@ def test_does_not_allow_duplicates_in_the_output_even_if_the_input_lists_had_dup self.assertEqual([1, 2], R.difference(M2, N2)) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity - # self.assertEqual(1, len(R.difference([0], [-0]))) + self.assertEqual(1, len(R.difference([0.0], [-0.0]))) self.assertEqual(0, len(R.difference([float('nan')], [float('nan')]))) self.assertEqual(0, len(R.difference([Just([42])], [Just([42])]))) diff --git a/test/test_equals.py b/test/test_equals.py index f22ba4a..389f737 100644 --- a/test/test_equals.py +++ b/test/test_equals.py @@ -193,10 +193,6 @@ def equals(self, point): self.assertEqual(False, R.equals(Point(1, 2), ColorPoint(1, 2, 'red'))) self.assertEqual(False, R.equals(ColorPoint(1, 2, 'red'), Point(1, 2))) - def test_clone(self): - pass - #TODO: clone - def test_nan(self): self.assertEqual(True, R.equals(float('nan'), float('nan'))) diff --git a/test/test_indexOf.py b/test/test_indexOf.py index 62852f5..ba7228b 100644 --- a/test/test_indexOf.py +++ b/test/test_indexOf.py @@ -36,8 +36,7 @@ def test_returns_minus_1_for_an_empty_array(self): self.assertEqual(-1, R.indexOf('x', [])) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity - # self.assertEqual(1, len(R.difference([0], [-0]))) + self.assertEqual(1, len(R.difference([0.0], [-0.0]))) self.assertEqual(0, R.indexOf(float('nan'), [float('nan')])) self.assertEqual(0, R.indexOf(Just([42]), [Just([42])])) diff --git a/test/test_intersection.py b/test/test_intersection.py index 6e4286f..83564a8 100644 --- a/test/test_intersection.py +++ b/test/test_intersection.py @@ -28,7 +28,8 @@ def test_does_not_allow_duplicates_in_the_output_even_if_the_second_lists_is_big self.assertEqual([3, 4], R.intersection(M, N2)) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simplicity + self.assertEqual(0, len(R.intersection([0.0], [-0.0]))) + self.assertEqual(0, len(R.intersection([-0.0], [0.0]))) self.assertEqual(1, len(R.intersection([float('nan')], [float('nan')]))) self.assertEqual(1, len(R.intersection([Just([42])], [Just([42])]))) diff --git a/test/test_lastIndexOf.py b/test/test_lastIndexOf.py index c1635ae..d1f403b 100644 --- a/test/test_lastIndexOf.py +++ b/test/test_lastIndexOf.py @@ -34,8 +34,7 @@ def test_returns_minus_1_for_an_empty_array(self): self.assertEqual(-1, R.lastIndexOf('x', [])) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity - # self.assertEqual(-1, R.lastIndexOf(0, [-0])) + self.assertEqual(-1, R.lastIndexOf(0.0, [-0.0])) self.assertEqual(0, R.lastIndexOf(float('nan'), [float('nan')])) self.assertEqual(0, R.lastIndexOf(Just([42]), [Just([42])])) diff --git a/test/test_propEq.py b/test/test_propEq.py index 0047e2f..485d6e1 100644 --- a/test/test_propEq.py +++ b/test/test_propEq.py @@ -15,7 +15,8 @@ class TestPropEq(unittest.TestCase): def test_has_R_equals_semantics(self): - # TODO: handle minus zero + self.assertEqual(False, R.propEq(0.0, 'value', {'value': -0.0})) + self.assertEqual(False, R.propEq(-0.0, 'value', {'value': 0.0})) self.assertEqual(True, R.propEq(float('nan'), 'value', {'value': float('nan')})) self.assertEqual(True, R.propEq(Just([42]), 'value', {'value': Just([42])})) diff --git a/test/test_tap.py b/test/test_tap.py index d90869d..27cf8c7 100644 --- a/test/test_tap.py +++ b/test/test_tap.py @@ -46,7 +46,6 @@ def test_dispatches_to_transformer_objects(self): appendToSideEffect = appendToList(sideEffect) res = R.tap(appendToSideEffect, listXf) - print(res) self.assertEqual(appendToSideEffect, res.f) self.assertEqual(listXf, res.xf) diff --git a/test/test_toString.py b/test/test_toString.py index 388d774..5553b28 100644 --- a/test/test_toString.py +++ b/test/test_toString.py @@ -18,7 +18,9 @@ def test_returns_the_string_representation_of_a_Boolean_primitive(self): def test_returns_the_string_representation_of_a_number_primitive(self): self.assertEqual('0', R.toString(0)) - # TODO: -0 + self.assertEqual('0', R.toString(-0)) + self.assertEqual('0.0', R.toString(0.0)) + self.assertEqual('-0.0', R.toString(-0.0)) self.assertEqual('1.23', R.toString(1.23)) self.assertEqual('-1.23', R.toString(-1.23)) self.assertEqual('1e+23', R.toString(1e+23)) diff --git a/test/test_union.py b/test/test_union.py index 7b1db2a..5d2f951 100644 --- a/test/test_union.py +++ b/test/test_union.py @@ -18,7 +18,8 @@ def test_combines_two_lists_into_the_set_of_all_their_elements(self): self.assertEqual([1, 2, 3, 4, 5, 6], R.union(M, N)) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity + self.assertEqual(2, len(R.union([0.0], [-0.0]))) + self.assertEqual(2, len(R.union([-0.0], [0.0]))) self.assertEqual(1, len(R.union([float('nan')], [float('nan')]))) self.assertEqual(1, len(R.union([Just([42])], [Just([42])]))) diff --git a/test/test_uniq.py b/test/test_uniq.py index 4be34ff..002a65b 100644 --- a/test/test_uniq.py +++ b/test/test_uniq.py @@ -20,8 +20,8 @@ def test_returns_an_empty_array_for_an_empty_array(self): self.assertEqual([], R.uniq([])) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity - # self.assertEqual(2, len(R.uniq([0], [-0]))) + self.assertEqual(1, len(R.uniq([-0.0, -0.0]))) + self.assertEqual(2, len(R.uniq([0.0, -0.0]))) self.assertEqual(1, len(R.uniq([float('nan'), float('nan')]))) # self.assertEqual(1, len(R.uniq([[1], [1]]))) # python only support hashable obj self.assertEqual(1, len(R.uniq([Just([42]), Just([42])]))) diff --git a/test/test_uniqBy.py b/test/test_uniqBy.py index 68b4f4b..c9e42f5 100644 --- a/test/test_uniqBy.py +++ b/test/test_uniqBy.py @@ -20,8 +20,7 @@ def test_returns_an_empty_array_for_an_empty_array(self): self.assertEqual([], R.uniqBy(R.identity, [])) def test_has_R_equals_semantics(self): - # TODO: ignore neg-zero and pos-zero check for now, due to simlicity - # self.assertEqual(2, len(R.uniqBy([0], [-0]))) + self.assertEqual(2, len(R.uniqBy(R.identity, [0.0, -0.0]))) self.assertEqual(1, len(R.uniqBy(R.identity, [float('nan'), float('nan')]))) self.assertEqual(1, len(R.uniqBy(R.identity, [Just([1, 2, 3]), Just([1, 2, 3])])))