diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-10-11 17:56:14 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-10-12 13:39:06 -0400 |
| commit | c63658973c95996b73251e0953cf4c598cdb262b (patch) | |
| tree | 1d9aba0b27f2f096369b95cf0a6dbb95f87825ac /test/sql | |
| parent | 3306d4d34d0f78bdda6f85a0a3be81beb2850676 (diff) | |
| download | sqlalchemy-c63658973c95996b73251e0953cf4c598cdb262b.tar.gz | |
Disallow all ambiguous boolean values for Boolean
In release 1.1, the :class:`.Boolean` type was broken in that
boolean coercion via ``bool()`` would occur for backends that did not
feature "native boolean", but would not occur for native boolean backends,
meaning the string ``"0"`` now behaved inconsistently. After a poll, a
consensus was reached that non-boolean values should be raising an error,
especially in the ambiguous case of string ``"0"``; so the :class:`.Boolean`
datatype will now raise ``ValueError`` if an incoming value is not
within the range ``None, True, False, 1, 0``.
Change-Id: If70c4f79c266f0dd1a0306c0ffe7acb9c66c4cc3
Fixes: #4102
Diffstat (limited to 'test/sql')
| -rw-r--r-- | test/sql/test_types.py | 172 |
1 files changed, 167 insertions, 5 deletions
diff --git a/test/sql/test_types.py b/test/sql/test_types.py index f9b5b4945..dd799de1b 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -2621,15 +2621,14 @@ class BooleanTest( def test_nonnative_processor_coerces_to_onezero(self): boolean_table = self.tables.boolean_table with testing.db.connect() as conn: - conn.execute( + assert_raises_message( + exc.StatementError, + "Value 5 is not None, True, or False", + conn.execute, boolean_table.insert(), {"id": 1, "unconstrained_value": 5} ) - eq_( - conn.scalar("select unconstrained_value from boolean_table"), - 1 - ) @testing.skip_if(lambda: testing.db.dialect.supports_native_boolean) def test_nonnative_processor_coerces_integer_to_boolean(self): @@ -2650,6 +2649,169 @@ class BooleanTest( True ) + def test_bind_processor_coercion_native_true(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + is_(proc(True), True) + + def test_bind_processor_coercion_native_false(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + is_(proc(False), False) + + def test_bind_processor_coercion_native_none(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + is_(proc(None), None) + + def test_bind_processor_coercion_native_0(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + is_(proc(0), False) + + def test_bind_processor_coercion_native_1(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + is_(proc(1), True) + + def test_bind_processor_coercion_native_str(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + assert_raises_message( + TypeError, + "Not a boolean value: 'foo'", + proc, "foo" + ) + + def test_bind_processor_coercion_native_int_out_of_range(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=True)) + assert_raises_message( + ValueError, + "Value 15 is not None, True, or False", + proc, 15 + ) + + def test_bind_processor_coercion_nonnative_true(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + eq_(proc(True), 1) + + def test_bind_processor_coercion_nonnative_false(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + eq_(proc(False), 0) + + def test_bind_processor_coercion_nonnative_none(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + is_(proc(None), None) + + def test_bind_processor_coercion_nonnative_0(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + eq_(proc(0), 0) + + def test_bind_processor_coercion_nonnative_1(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + eq_(proc(1), 1) + + def test_bind_processor_coercion_nonnative_str(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + assert_raises_message( + TypeError, + "Not a boolean value: 'foo'", + proc, "foo" + ) + + def test_bind_processor_coercion_nonnative_int_out_of_range(self): + proc = Boolean().bind_processor( + mock.Mock(supports_native_boolean=False)) + assert_raises_message( + ValueError, + "Value 15 is not None, True, or False", + proc, 15 + ) + + def test_literal_processor_coercion_native_true(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + eq_(proc(True), "true") + + def test_literal_processor_coercion_native_false(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + eq_(proc(False), "false") + + def test_literal_processor_coercion_native_1(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + eq_(proc(1), "true") + + def test_literal_processor_coercion_native_0(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + eq_(proc(0), "false") + + def test_literal_processor_coercion_native_str(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + assert_raises_message( + TypeError, + "Not a boolean value: 'foo'", + proc, "foo" + ) + + def test_literal_processor_coercion_native_int_out_of_range(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + assert_raises_message( + ValueError, + "Value 15 is not None, True, or False", + proc, 15 + ) + + def test_literal_processor_coercion_nonnative_true(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=False)) + eq_(proc(True), "1") + + def test_literal_processor_coercion_nonnative_false(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=False)) + eq_(proc(False), "0") + + def test_literal_processor_coercion_nonnative_1(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=False)) + eq_(proc(1), "1") + + def test_literal_processor_coercion_nonnative_0(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=False)) + eq_(proc(0), "0") + + def test_literal_processor_coercion_nonnative_str(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=False)) + assert_raises_message( + TypeError, + "Not a boolean value: 'foo'", + proc, "foo" + ) + + def test_literal_processor_coercion_native_int_out_of_range(self): + proc = Boolean().literal_processor( + default.DefaultDialect(supports_native_boolean=True)) + assert_raises_message( + ValueError, + "Value 15 is not None, True, or False", + proc, 15 + ) + + class PickleTest(fixtures.TestBase): |
