Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
@ 2020-03-19 10:24 Sergey Bronnikov
  2020-03-19 11:09 ` Oleg Piskunov
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Sergey Bronnikov @ 2020-03-19 10:24 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Oleg Piskunov

Splitted single hash.test.lua to a set of small independent tests.

GitHub branch: https://github.com/tarantool/tarantool/tree/ligurio/hash_test_split

---
 test/box/hash.result                  | 873 --------------------------
 test/box/hash.test.lua                | 364 -----------
 test/box/hash_32bit_delete.result     |  70 +++
 test/box/hash_32bit_delete.test.lua   |  29 +
 test/box/hash_32bit_insert.result     |  38 ++
 test/box/hash_32bit_insert.test.lua   |  16 +
 test/box/hash_32bit_replace.result    |  56 ++
 test/box/hash_32bit_replace.test.lua  |  25 +
 test/box/hash_32bit_select.result     |  70 +++
 test/box/hash_32bit_select.test.lua   |  29 +
 test/box/hash_64bit_delete.result     | 111 ++++
 test/box/hash_64bit_delete.test.lua   |  42 ++
 test/box/hash_64bit_insert.result     |  54 ++
 test/box/hash_64bit_insert.test.lua   |  20 +
 test/box/hash_64bit_replace.result    |  68 ++
 test/box/hash_64bit_replace.test.lua  |  28 +
 test/box/hash_64bit_select.result     |  94 +++
 test/box/hash_64bit_select.test.lua   |  37 ++
 test/box/hash_collation.result        |  62 ++
 test/box/hash_collation.test.lua      |  22 +
 test/box/hash_gh-1467.result          |  17 +
 test/box/hash_gh-1467.test.lua        |   6 +
 test/box/hash_gh-3907.result          |  48 ++
 test/box/hash_gh-3907.test.lua        |  15 +
 test/box/hash_gh-616.result           |  17 +
 test/box/hash_gh-616.test.lua         |   7 +
 test/box/hash_iterate.result          |  21 +
 test/box/hash_iterate.test.lua        |   6 +
 test/box/hash_multipart.result        |   7 -
 test/box/hash_multipart.test.lua      |   2 -
 test/box/hash_not_a_multikey.result   |  17 +
 test/box/hash_not_a_multikey.test.lua |   6 +
 test/box/hash_replace.result          | 256 ++++++++
 test/box/hash_replace.test.lua        |  88 +++
 test/box/hash_string_delete.result    |  62 ++
 test/box/hash_string_delete.test.lua  |  24 +
 test/box/hash_string_insert.result    |  32 +
 test/box/hash_string_insert.test.lua  |  13 +
 test/box/hash_string_replace.result   |  47 ++
 test/box/hash_string_replace.test.lua |  19 +
 test/box/hash_string_select.result    |  63 ++
 test/box/hash_string_select.test.lua  |  25 +
 test/box/hash_with_function.result    |  26 +
 test/box/hash_with_function.test.lua  |   9 +
 44 files changed, 1695 insertions(+), 1246 deletions(-)
 delete mode 100644 test/box/hash.result
 delete mode 100644 test/box/hash.test.lua
 create mode 100644 test/box/hash_32bit_delete.result
 create mode 100644 test/box/hash_32bit_delete.test.lua
 create mode 100644 test/box/hash_32bit_insert.result
 create mode 100644 test/box/hash_32bit_insert.test.lua
 create mode 100644 test/box/hash_32bit_replace.result
 create mode 100644 test/box/hash_32bit_replace.test.lua
 create mode 100644 test/box/hash_32bit_select.result
 create mode 100644 test/box/hash_32bit_select.test.lua
 create mode 100644 test/box/hash_64bit_delete.result
 create mode 100644 test/box/hash_64bit_delete.test.lua
 create mode 100644 test/box/hash_64bit_insert.result
 create mode 100644 test/box/hash_64bit_insert.test.lua
 create mode 100644 test/box/hash_64bit_replace.result
 create mode 100644 test/box/hash_64bit_replace.test.lua
 create mode 100644 test/box/hash_64bit_select.result
 create mode 100644 test/box/hash_64bit_select.test.lua
 create mode 100644 test/box/hash_collation.result
 create mode 100644 test/box/hash_collation.test.lua
 create mode 100644 test/box/hash_gh-1467.result
 create mode 100644 test/box/hash_gh-1467.test.lua
 create mode 100644 test/box/hash_gh-3907.result
 create mode 100644 test/box/hash_gh-3907.test.lua
 create mode 100644 test/box/hash_gh-616.result
 create mode 100644 test/box/hash_gh-616.test.lua
 create mode 100644 test/box/hash_iterate.result
 create mode 100644 test/box/hash_iterate.test.lua
 create mode 100644 test/box/hash_not_a_multikey.result
 create mode 100644 test/box/hash_not_a_multikey.test.lua
 create mode 100644 test/box/hash_replace.result
 create mode 100644 test/box/hash_replace.test.lua
 create mode 100644 test/box/hash_string_delete.result
 create mode 100644 test/box/hash_string_delete.test.lua
 create mode 100644 test/box/hash_string_insert.result
 create mode 100644 test/box/hash_string_insert.test.lua
 create mode 100644 test/box/hash_string_replace.result
 create mode 100644 test/box/hash_string_replace.test.lua
 create mode 100644 test/box/hash_string_select.result
 create mode 100644 test/box/hash_string_select.test.lua
 create mode 100644 test/box/hash_with_function.result
 create mode 100644 test/box/hash_with_function.test.lua

diff --git a/test/box/hash.result b/test/box/hash.result
deleted file mode 100644
index 5e1441ecc..000000000
--- a/test/box/hash.result
+++ /dev/null
@@ -1,873 +0,0 @@
---=============================================================================
--- 32-bit hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- 32-bit hash insert fields tests
--------------------------------------------------------------------------------
-hash = box.schema.space.create('tweedledum')
----
-...
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
----
-...
-bsize = tmp:bsize()
----
-...
--- Insert valid fields
-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
----
-- [1, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
----
-- [2, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
----
-- [3, 'value1 v1.0', 'value2 v1.0']
-...
-tmp:bsize() > bsize
----
-- true
-...
--- Insert invalid fields
-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
----
-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
-...
--------------------------------------------------------------------------------
--- 32-bit hash replace fields tests
--------------------------------------------------------------------------------
--- Replace valid fields
-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
--- Replace invalid fields
-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
----
-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
-...
--------------------------------------------------------------------------------
--- 32-bit hash select fields test
--------------------------------------------------------------------------------
--- select by valid keys
-hash.index['primary']:get{0}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash.index['primary']:get{1}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash.index['primary']:get{2}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash.index['primary']:get{3}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash.index['primary']:get{4}
----
-...
-hash.index['primary']:get{5}
----
-...
--- select by invalid keys
-hash.index['primary']:get{'invalid key'}
----
-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
-...
-hash.index['primary']:get{1, 2}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
--------------------------------------------------------------------------------
--- 32-bit hash delete fields test
--------------------------------------------------------------------------------
--- delete by valid keys
-hash:delete{0}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{1}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash:delete{2}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash:delete{3}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash:delete{4}
----
-...
-hash:delete{5}
----
-...
--- delete by invalid keys
-hash:delete{'invalid key'}
----
-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
-...
-hash:delete{1, 2}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
-hash:truncate()
----
-...
---=============================================================================
--- 64-bit hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- 64-bit hash inset fields tests
--------------------------------------------------------------------------------
--- Insert valid fields
-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [1, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [2, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [3, 'value1 v1.0', 'value2 v1.0']
-...
--- Insert invalid fields
-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
----
-- [100, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
----
-- [101, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
----
-- [102, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
----
-- [103, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
----
-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
-...
--------------------------------------------------------------------------------
--- 64-bit hash replace fields tests
--------------------------------------------------------------------------------
--- Replace valid fields
-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
--- Replace invalid fields
-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
----
-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
-...
--------------------------------------------------------------------------------
--- 64-bit hash select fields test
--------------------------------------------------------------------------------
--- select by valid keys
-hash.index['primary']:get{0ULL}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash.index['primary']:get{1ULL}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash.index['primary']:get{2ULL}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash.index['primary']:get{3ULL}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash.index['primary']:get{4ULL}
----
-...
-hash.index['primary']:get{5ULL}
----
-...
--- select by valid NUM keys
-hash.index['primary']:get{0}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash.index['primary']:get{1}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash.index['primary']:get{2}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash.index['primary']:get{3}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash.index['primary']:get{4}
----
-...
-hash.index['primary']:get{5}
----
-...
--- select by invalid keys
-hash.index['primary']:get{'invalid key'}
----
-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
-...
-hash.index['primary']:get{'00000001', '00000002'}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
--------------------------------------------------------------------------------
--- 64-bit hash delete fields test
--------------------------------------------------------------------------------
--- delete by valid keys
-hash:delete{0ULL}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{1ULL}
----
-- [1, 'value1 v1.32', 'value2 1.72']
-...
-hash:delete{2ULL}
----
-- [2, 'value1 v1.43', 'value2 1.92']
-...
-hash:delete{3ULL}
----
-- [3, 'value1 v1.31', 'value2 1.12']
-...
-hash:delete{4ULL}
----
-...
-hash:delete{5ULL}
----
-...
-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [1, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [2, 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
----
-- [3, 'value1 v1.0', 'value2 v1.0']
-...
--- delete by valid NUM keys
-hash:delete{0}
----
-- [0, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{1}
----
-- [1, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{2}
----
-- [2, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{3}
----
-- [3, 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{4}
----
-...
-hash:delete{5}
----
-...
--- delete by invalid keys
-hash:delete{'invalid key'}
----
-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
-...
-hash:delete{'00000001', '00000002'}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
-hash:truncate()
----
-...
---=============================================================================
--- String hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- String hash inset fields tests
--------------------------------------------------------------------------------
-hash.index['primary']:drop()
----
-...
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
----
-...
--- Insert valid fields
-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
----
-- ['key 0', 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
----
-- ['key 1', 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
----
-- ['key 2', 'value1 v1.0', 'value2 v1.0']
-...
-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
----
-- ['key 3', 'value1 v1.0', 'value2 v1.0']
-...
--------------------------------------------------------------------------------
--- String hash replace fields tests
--------------------------------------------------------------------------------
--- Replace valid fields
-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
----
-- ['key 3', 'value1 v1.31', 'value2 1.12']
-...
-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
----
-- ['key 1', 'value1 v1.32', 'value2 1.72']
-...
-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
----
-- ['key 2', 'value1 v1.43', 'value2 1.92']
-...
--------------------------------------------------------------------------------
--- String hash select fields test
--------------------------------------------------------------------------------
--- select by valid keys
-hash.index['primary']:get{'key 0'}
----
-- ['key 0', 'value1 v1.0', 'value2 v1.0']
-...
-hash.index['primary']:get{'key 1'}
----
-- ['key 1', 'value1 v1.32', 'value2 1.72']
-...
-hash.index['primary']:get{'key 2'}
----
-- ['key 2', 'value1 v1.43', 'value2 1.92']
-...
-hash.index['primary']:get{'key 3'}
----
-- ['key 3', 'value1 v1.31', 'value2 1.12']
-...
-hash.index['primary']:get{'key 4'}
----
-...
-hash.index['primary']:get{'key 5'}
----
-...
--- select by invalid keys
-hash.index['primary']:get{'key 1', 'key 2'}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
--------------------------------------------------------------------------------
--- String hash delete fields test
--------------------------------------------------------------------------------
--- delete by valid keys
-hash:delete{'key 0'}
----
-- ['key 0', 'value1 v1.0', 'value2 v1.0']
-...
-hash:delete{'key 1'}
----
-- ['key 1', 'value1 v1.32', 'value2 1.72']
-...
-hash:delete{'key 2'}
----
-- ['key 2', 'value1 v1.43', 'value2 1.92']
-...
-hash:delete{'key 3'}
----
-- ['key 3', 'value1 v1.31', 'value2 1.12']
-...
-hash:delete{'key 4'}
----
-...
-hash:delete{'key 5'}
----
-...
--- delete by invalid keys
-hash:delete{'key 1', 'key 2'}
----
-- error: Invalid key part count in an exact match (expected 1, got 2)
-...
-hash:truncate()
----
-...
--------------------------------------------------------------------------------
--- Collation test
--------------------------------------------------------------------------------
-hash.index['primary']:drop()
----
-...
-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
----
-...
-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
----
-...
-hash:insert{'Ёж', 'Hedgehog'}
----
-- ['Ёж', 'Hedgehog']
-...
-hash:insert{'Ёлка', 'Spruce'}
----
-- ['Ёлка', 'Spruce']
-...
-hash:insert{'Jogurt', 'Йогурт'}
----
-- ['Jogurt', 'Йогурт']
-...
-hash:insert{'Один', 1}
----
-- ['Один', 1]
-...
-hash.index.primary:get('ёж')
----
-- ['Ёж', 'Hedgehog']
-...
-hash.index.primary:get('елка')
----
-- ['Ёлка', 'Spruce']
-...
-hash.index.secondary:get('spruce')
----
-- ['Ёлка', 'Spruce']
-...
-hash.index.secondary:get('йогурт')
----
-- ['Jogurt', 'Йогурт']
-...
-hash.index.secondary:get(1)
----
-- ['Один', 1]
-...
-hash.index.secondary:get('иогурт')
----
-...
-hash.index.secondary:get(2)
----
-...
-------------------------
--- hash::replace tests
-------------------------
-hash.index['secondary']:drop()
----
-...
-hash.index['primary']:drop()
----
-...
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
----
-...
-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
----
-...
-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
----
-...
-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
----
-...
-hash:insert{0, 0, 0, 0}
----
-- [0, 0, 0, 0]
-...
-hash:insert{1, 1, 1, 1}
----
-- [1, 1, 1, 1]
-...
-hash:insert{2, 2, 2, 2}
----
-- [2, 2, 2, 2]
-...
--- OK
-hash:replace{1, 1, 1, 1}
----
-- [1, 1, 1, 1]
-...
-hash.index['primary']:get{10}
----
-...
-hash.index['field1']:get{10}
----
-...
-hash.index['field2']:get{10}
----
-...
-hash.index['field3']:get{10}
----
-...
-hash.index['primary']:get{1}
----
-- [1, 1, 1, 1]
-...
-hash.index['field1']:get{1}
----
-- [1, 1, 1, 1]
-...
-hash.index['field2']:get{1}
----
-- [1, 1, 1, 1]
-...
-hash.index['field3']:get{1}
----
-- [1, 1, 1, 1]
-...
--- OK
-hash:insert{10, 10, 10, 10}
----
-- [10, 10, 10, 10]
-...
-hash:delete{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['primary']:get{10}
----
-...
-hash.index['field1']:get{10}
----
-...
-hash.index['field2']:get{10}
----
-...
-hash.index['field3']:get{10}
----
-...
--- TupleFound (primary key)
-hash:insert{1, 10, 10, 10}
----
-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
-...
-hash.index['primary']:get{10}
----
-...
-hash.index['field1']:get{10}
----
-...
-hash.index['field2']:get{10}
----
-...
-hash.index['field3']:get{10}
----
-...
-hash.index['primary']:get{1}
----
-- [1, 1, 1, 1]
-...
--- TupleNotFound (primary key)
-hash:replace{10, 10, 10, 10}
----
-- [10, 10, 10, 10]
-...
-hash.index['primary']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field2']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{10}
----
-- [10, 10, 10, 10]
-...
--- TupleFound (key --1)
-hash:insert{10, 0, 10, 10}
----
-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
-...
-hash.index['primary']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field2']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{0}
----
-- [0, 0, 0, 0]
-...
--- TupleFound (key --1)
--- hash:replace_if_exists(2, 0, 10, 10)
-hash.index['primary']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field2']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{0}
----
-- [0, 0, 0, 0]
-...
--- TupleFound (key --3)
-hash:insert{10, 10, 10, 0}
----
-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
-...
-hash.index['primary']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field2']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{0}
----
-- [0, 0, 0, 0]
-...
--- TupleFound (key --3)
--- hash:replace_if_exists(2, 10, 10, 0)
-hash.index['primary']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field1']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field2']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{10}
----
-- [10, 10, 10, 10]
-...
-hash.index['field3']:get{0}
----
-- [0, 0, 0, 0]
-...
-hash:drop()
----
-...
-hash = box.schema.space.create('tweedledum')
----
-...
-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
----
-...
-hash:insert{0}
----
-- [0]
-...
-hash:insert{16}
----
-- [16]
-...
-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
----
-...
-hash:drop()
----
-...
--- 
--- gh-616 "1-based indexing and 0-based error message
---
-_ = box.schema.create_space('test')
----
-...
-_ = box.space.test:create_index('i',{parts={1,'string'}})
----
-...
-box.space.test:insert{1}
----
-- error: 'Tuple field 1 type does not match one required by operation: expected string'
-...
-box.space.test:drop()
----
-...
--- gh-1467: invalid iterator type
-space = box.schema.space.create('test')
----
-...
-index = space:create_index('primary', { type = 'hash' })
----
-...
-space:select({1}, {iterator = 'BITS_ALL_SET' } )
----
-- error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
-    iterator type
-...
-space:drop()
----
-...
--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
--- are hashed as MP_INT/MP_UINT.
-ffi = require('ffi')
----
-...
-s = box.schema.space.create('test')
----
-...
-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
----
-...
-s:insert{ffi.new('double', 0)}
----
-- [0]
-...
-s:insert{ffi.new('double', -1)}
----
-- [-1]
-...
-s:insert{ffi.new('double', 9007199254740992)}
----
-- [9007199254740992]
-...
-s:insert{ffi.new('double', -9007199254740994)}
----
-- [-9007199254740994]
-...
-s:get(0LL)
----
-- [0]
-...
-s:get(-1LL)
----
-- [-1]
-...
-s:get(9007199254740992LL)
----
-- [9007199254740992]
-...
-s:get(-9007199254740994LL)
----
-- [-9007199254740994]
-...
-s:drop()
----
-...
--- Hash index cannot be multikey.
-s = box.schema.space.create('test')
----
-...
-_ = s:create_index('primary')
----
-...
-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
----
-- error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
-    be multikey'
-...
-s:drop()
----
-...
--- Hash index can not use function.
-s = box.schema.space.create('withdata')
----
-...
-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
----
-...
-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
----
-...
-_ = s:create_index('pk')
----
-...
-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
----
-- error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
-    can not use a function'
-...
-s:drop()
----
-...
-box.schema.func.drop('s')
----
-...
diff --git a/test/box/hash.test.lua b/test/box/hash.test.lua
deleted file mode 100644
index 78c831f77..000000000
--- a/test/box/hash.test.lua
+++ /dev/null
@@ -1,364 +0,0 @@
---=============================================================================
--- 32-bit hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- 32-bit hash insert fields tests
--------------------------------------------------------------------------------
-hash = box.schema.space.create('tweedledum')
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
-
-bsize = tmp:bsize()
-
--- Insert valid fields
-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
-
-tmp:bsize() > bsize
-
--- Insert invalid fields
-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
-
--------------------------------------------------------------------------------
--- 32-bit hash replace fields tests
--------------------------------------------------------------------------------
-
--- Replace valid fields
-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
-
--- Replace invalid fields
-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
-
--------------------------------------------------------------------------------
--- 32-bit hash select fields test
--------------------------------------------------------------------------------
-
--- select by valid keys
-hash.index['primary']:get{0}
-hash.index['primary']:get{1}
-hash.index['primary']:get{2}
-hash.index['primary']:get{3}
-hash.index['primary']:get{4}
-hash.index['primary']:get{5}
-
--- select by invalid keys
-hash.index['primary']:get{'invalid key'}
-hash.index['primary']:get{1, 2}
-
--------------------------------------------------------------------------------
--- 32-bit hash delete fields test
--------------------------------------------------------------------------------
-
--- delete by valid keys
-hash:delete{0}
-hash:delete{1}
-hash:delete{2}
-hash:delete{3}
-hash:delete{4}
-hash:delete{5}
-
--- delete by invalid keys
-hash:delete{'invalid key'}
-hash:delete{1, 2}
-
-hash:truncate()
-
---=============================================================================
--- 64-bit hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- 64-bit hash inset fields tests
--------------------------------------------------------------------------------
-
--- Insert valid fields
-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
-
--- Insert invalid fields
-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
-
--------------------------------------------------------------------------------
--- 64-bit hash replace fields tests
--------------------------------------------------------------------------------
-
--- Replace valid fields
-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
-
--- Replace invalid fields
-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
-
--------------------------------------------------------------------------------
--- 64-bit hash select fields test
--------------------------------------------------------------------------------
-
--- select by valid keys
-hash.index['primary']:get{0ULL}
-hash.index['primary']:get{1ULL}
-hash.index['primary']:get{2ULL}
-hash.index['primary']:get{3ULL}
-hash.index['primary']:get{4ULL}
-hash.index['primary']:get{5ULL}
-
--- select by valid NUM keys
-hash.index['primary']:get{0}
-hash.index['primary']:get{1}
-hash.index['primary']:get{2}
-hash.index['primary']:get{3}
-hash.index['primary']:get{4}
-hash.index['primary']:get{5}
-
--- select by invalid keys
-hash.index['primary']:get{'invalid key'}
-hash.index['primary']:get{'00000001', '00000002'}
-
--------------------------------------------------------------------------------
--- 64-bit hash delete fields test
--------------------------------------------------------------------------------
-
--- delete by valid keys
-hash:delete{0ULL}
-hash:delete{1ULL}
-hash:delete{2ULL}
-hash:delete{3ULL}
-hash:delete{4ULL}
-hash:delete{5ULL}
-
-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
-
--- delete by valid NUM keys
-hash:delete{0}
-hash:delete{1}
-hash:delete{2}
-hash:delete{3}
-hash:delete{4}
-hash:delete{5}
-
--- delete by invalid keys
-hash:delete{'invalid key'}
-hash:delete{'00000001', '00000002'}
-hash:truncate()
-
---=============================================================================
--- String hash tests
---=============================================================================
--------------------------------------------------------------------------------
--- String hash inset fields tests
--------------------------------------------------------------------------------
-hash.index['primary']:drop()
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
-
--- Insert valid fields
-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
-
--------------------------------------------------------------------------------
--- String hash replace fields tests
--------------------------------------------------------------------------------
-
--- Replace valid fields
-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
-
--------------------------------------------------------------------------------
--- String hash select fields test
--------------------------------------------------------------------------------
-
--- select by valid keys
-hash.index['primary']:get{'key 0'}
-hash.index['primary']:get{'key 1'}
-hash.index['primary']:get{'key 2'}
-hash.index['primary']:get{'key 3'}
-hash.index['primary']:get{'key 4'}
-hash.index['primary']:get{'key 5'}
-
--- select by invalid keys
-hash.index['primary']:get{'key 1', 'key 2'}
-
--------------------------------------------------------------------------------
--- String hash delete fields test
--------------------------------------------------------------------------------
-
--- delete by valid keys
-hash:delete{'key 0'}
-hash:delete{'key 1'}
-hash:delete{'key 2'}
-hash:delete{'key 3'}
-hash:delete{'key 4'}
-hash:delete{'key 5'}
-
--- delete by invalid keys
-hash:delete{'key 1', 'key 2'}
-hash:truncate()
-
--------------------------------------------------------------------------------
--- Collation test
--------------------------------------------------------------------------------
-hash.index['primary']:drop()
-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
-
-hash:insert{'Ёж', 'Hedgehog'}
-hash:insert{'Ёлка', 'Spruce'}
-hash:insert{'Jogurt', 'Йогурт'}
-hash:insert{'Один', 1}
-
-hash.index.primary:get('ёж')
-hash.index.primary:get('елка')
-hash.index.secondary:get('spruce')
-hash.index.secondary:get('йогурт')
-hash.index.secondary:get(1)
-hash.index.secondary:get('иогурт')
-hash.index.secondary:get(2)
-
-------------------------
--- hash::replace tests
-------------------------
-hash.index['secondary']:drop()
-hash.index['primary']:drop()
-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
-
-hash:insert{0, 0, 0, 0}
-hash:insert{1, 1, 1, 1}
-hash:insert{2, 2, 2, 2}
-
--- OK
-hash:replace{1, 1, 1, 1}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['primary']:get{1}
-hash.index['field1']:get{1}
-hash.index['field2']:get{1}
-hash.index['field3']:get{1}
-
--- OK
-hash:insert{10, 10, 10, 10}
-hash:delete{10}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-
--- TupleFound (primary key)
-hash:insert{1, 10, 10, 10}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['primary']:get{1}
-
--- TupleNotFound (primary key)
-hash:replace{10, 10, 10, 10}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-
--- TupleFound (key --1)
-hash:insert{10, 0, 10, 10}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['field1']:get{0}
-
--- TupleFound (key --1)
--- hash:replace_if_exists(2, 0, 10, 10)
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['field1']:get{0}
-
--- TupleFound (key --3)
-hash:insert{10, 10, 10, 0}
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['field3']:get{0}
-
--- TupleFound (key --3)
--- hash:replace_if_exists(2, 10, 10, 0)
-hash.index['primary']:get{10}
-hash.index['field1']:get{10}
-hash.index['field2']:get{10}
-hash.index['field3']:get{10}
-hash.index['field3']:get{0}
-
-hash:drop()
-
-hash = box.schema.space.create('tweedledum')
-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
-hash:insert{0}
-hash:insert{16}
-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
-hash:drop()
-
--- 
--- gh-616 "1-based indexing and 0-based error message
---
-_ = box.schema.create_space('test')
-_ = box.space.test:create_index('i',{parts={1,'string'}})
-box.space.test:insert{1}
-box.space.test:drop()
-
--- gh-1467: invalid iterator type
-space = box.schema.space.create('test')
-index = space:create_index('primary', { type = 'hash' })
-space:select({1}, {iterator = 'BITS_ALL_SET' } )
-space:drop()
-
--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
--- are hashed as MP_INT/MP_UINT.
-ffi = require('ffi')
-s = box.schema.space.create('test')
-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
-s:insert{ffi.new('double', 0)}
-s:insert{ffi.new('double', -1)}
-s:insert{ffi.new('double', 9007199254740992)}
-s:insert{ffi.new('double', -9007199254740994)}
-s:get(0LL)
-s:get(-1LL)
-s:get(9007199254740992LL)
-s:get(-9007199254740994LL)
-s:drop()
-
--- Hash index cannot be multikey.
-s = box.schema.space.create('test')
-_ = s:create_index('primary')
-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
-s:drop()
-
--- Hash index can not use function.
-s = box.schema.space.create('withdata')
-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
-_ = s:create_index('pk')
-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
-s:drop()
-box.schema.func.drop('s')
diff --git a/test/box/hash_32bit_delete.result b/test/box/hash_32bit_delete.result
new file mode 100644
index 000000000..b35143b10
--- /dev/null
+++ b/test/box/hash_32bit_delete.result
@@ -0,0 +1,70 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 32-bit hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{0}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{1}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{2}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{3}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{4}
+ | ---
+ | ...
+hash:delete{5}
+ | ---
+ | ...
+
+-- delete by invalid keys
+hash:delete{'invalid key'}
+ | ---
+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
+ | ...
+hash:delete{1, 2}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_32bit_delete.test.lua b/test/box/hash_32bit_delete.test.lua
new file mode 100644
index 000000000..682e0bc96
--- /dev/null
+++ b/test/box/hash_32bit_delete.test.lua
@@ -0,0 +1,29 @@
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 32-bit hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{0}
+hash:delete{1}
+hash:delete{2}
+hash:delete{3}
+hash:delete{4}
+hash:delete{5}
+
+-- delete by invalid keys
+hash:delete{'invalid key'}
+hash:delete{1, 2}
+
+hash:drop()
diff --git a/test/box/hash_32bit_insert.result b/test/box/hash_32bit_insert.result
new file mode 100644
index 000000000..72c7c4842
--- /dev/null
+++ b/test/box/hash_32bit_insert.result
@@ -0,0 +1,38 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-- Insert invalid fields
+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_32bit_insert.test.lua b/test/box/hash_32bit_insert.test.lua
new file mode 100644
index 000000000..308b27d3e
--- /dev/null
+++ b/test/box/hash_32bit_insert.test.lua
@@ -0,0 +1,16 @@
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+
+-- Insert invalid fields
+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+
+hash:drop()
diff --git a/test/box/hash_32bit_replace.result b/test/box/hash_32bit_replace.result
new file mode 100644
index 000000000..a1feba851
--- /dev/null
+++ b/test/box/hash_32bit_replace.result
@@ -0,0 +1,56 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 32-bit hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
+ | ---
+ | - [3, 'value1 v1.31', 'value2 1.12']
+ | ...
+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
+ | ---
+ | - [1, 'value1 v1.32', 'value2 1.72']
+ | ...
+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
+ | ---
+ | - [2, 'value1 v1.43', 'value2 1.92']
+ | ...
+
+-- Replace invalid fields
+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_32bit_replace.test.lua b/test/box/hash_32bit_replace.test.lua
new file mode 100644
index 000000000..a00b02185
--- /dev/null
+++ b/test/box/hash_32bit_replace.test.lua
@@ -0,0 +1,25 @@
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 32-bit hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
+
+-- Replace invalid fields
+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+
+hash:drop()
diff --git a/test/box/hash_32bit_select.result b/test/box/hash_32bit_select.result
new file mode 100644
index 000000000..f80df9bbd
--- /dev/null
+++ b/test/box/hash_32bit_select.result
@@ -0,0 +1,70 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 32-bit hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{0}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{1}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{2}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{3}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{4}
+ | ---
+ | ...
+hash.index['primary']:get{5}
+ | ---
+ | ...
+
+-- select by invalid keys
+hash.index['primary']:get{'invalid key'}
+ | ---
+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
+ | ...
+hash.index['primary']:get{1, 2}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_32bit_select.test.lua b/test/box/hash_32bit_select.test.lua
new file mode 100644
index 000000000..e077cc48d
--- /dev/null
+++ b/test/box/hash_32bit_select.test.lua
@@ -0,0 +1,29 @@
+-------------------------------------------------------------------------------
+-- 32-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 32-bit hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{0}
+hash.index['primary']:get{1}
+hash.index['primary']:get{2}
+hash.index['primary']:get{3}
+hash.index['primary']:get{4}
+hash.index['primary']:get{5}
+
+-- select by invalid keys
+hash.index['primary']:get{'invalid key'}
+hash.index['primary']:get{1, 2}
+
+hash:drop()
diff --git a/test/box/hash_64bit_delete.result b/test/box/hash_64bit_delete.result
new file mode 100644
index 000000000..88079e6f2
--- /dev/null
+++ b/test/box/hash_64bit_delete.result
@@ -0,0 +1,111 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 64-bit hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{0ULL}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{1ULL}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{2ULL}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{3ULL}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{4ULL}
+ | ---
+ | ...
+hash:delete{5ULL}
+ | ---
+ | ...
+
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-- delete by valid NUM keys
+hash:delete{0}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{1}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{2}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{3}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{4}
+ | ---
+ | ...
+hash:delete{5}
+ | ---
+ | ...
+
+-- delete by invalid keys
+hash:delete{'invalid key'}
+ | ---
+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
+ | ...
+hash:delete{'00000001', '00000002'}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_64bit_delete.test.lua b/test/box/hash_64bit_delete.test.lua
new file mode 100644
index 000000000..75675381f
--- /dev/null
+++ b/test/box/hash_64bit_delete.test.lua
@@ -0,0 +1,42 @@
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 64-bit hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{0ULL}
+hash:delete{1ULL}
+hash:delete{2ULL}
+hash:delete{3ULL}
+hash:delete{4ULL}
+hash:delete{5ULL}
+
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+
+-- delete by valid NUM keys
+hash:delete{0}
+hash:delete{1}
+hash:delete{2}
+hash:delete{3}
+hash:delete{4}
+hash:delete{5}
+
+-- delete by invalid keys
+hash:delete{'invalid key'}
+hash:delete{'00000001', '00000002'}
+
+hash:drop()
diff --git a/test/box/hash_64bit_insert.result b/test/box/hash_64bit_insert.result
new file mode 100644
index 000000000..3f1275576
--- /dev/null
+++ b/test/box/hash_64bit_insert.result
@@ -0,0 +1,54 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-- Insert invalid fields
+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [100, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [101, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [102, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [103, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_64bit_insert.test.lua b/test/box/hash_64bit_insert.test.lua
new file mode 100644
index 000000000..c69214b4e
--- /dev/null
+++ b/test/box/hash_64bit_insert.test.lua
@@ -0,0 +1,20 @@
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+
+-- Insert invalid fields
+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+
+hash:drop()
diff --git a/test/box/hash_64bit_replace.result b/test/box/hash_64bit_replace.result
new file mode 100644
index 000000000..0bf900818
--- /dev/null
+++ b/test/box/hash_64bit_replace.result
@@ -0,0 +1,68 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 64-bit hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
+ | ---
+ | - [3, 'value1 v1.31', 'value2 1.12']
+ | ...
+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
+ | ---
+ | - [1, 'value1 v1.32', 'value2 1.72']
+ | ...
+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
+ | ---
+ | - [2, 'value1 v1.43', 'value2 1.92']
+ | ...
+
+-- Replace invalid fields
+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
+ | ---
+ | - [3, 'value1 v1.31', 'value2 1.12']
+ | ...
+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
+ | ---
+ | - [1, 'value1 v1.32', 'value2 1.72']
+ | ...
+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
+ | ---
+ | - [2, 'value1 v1.43', 'value2 1.92']
+ | ...
+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_64bit_replace.test.lua b/test/box/hash_64bit_replace.test.lua
new file mode 100644
index 000000000..4213110bc
--- /dev/null
+++ b/test/box/hash_64bit_replace.test.lua
@@ -0,0 +1,28 @@
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 64-bit hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
+
+-- Replace invalid fields
+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
+
+hash:drop()
diff --git a/test/box/hash_64bit_select.result b/test/box/hash_64bit_select.result
new file mode 100644
index 000000000..74dd56727
--- /dev/null
+++ b/test/box/hash_64bit_select.result
@@ -0,0 +1,94 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- 64-bit hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{0ULL}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{1ULL}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{2ULL}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{3ULL}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{4ULL}
+ | ---
+ | ...
+hash.index['primary']:get{5ULL}
+ | ---
+ | ...
+
+-- select by valid NUM keys
+hash.index['primary']:get{0}
+ | ---
+ | - [0, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{1}
+ | ---
+ | - [1, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{2}
+ | ---
+ | - [2, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{3}
+ | ---
+ | - [3, 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{4}
+ | ---
+ | ...
+hash.index['primary']:get{5}
+ | ---
+ | ...
+
+-- select by invalid keys
+hash.index['primary']:get{'invalid key'}
+ | ---
+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
+ | ...
+hash.index['primary']:get{'00000001', '00000002'}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_64bit_select.test.lua b/test/box/hash_64bit_select.test.lua
new file mode 100644
index 000000000..724fb24be
--- /dev/null
+++ b/test/box/hash_64bit_select.test.lua
@@ -0,0 +1,37 @@
+-------------------------------------------------------------------------------
+-- 64-bit hash insert fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+
+-- Insert valid fields
+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- 64-bit hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{0ULL}
+hash.index['primary']:get{1ULL}
+hash.index['primary']:get{2ULL}
+hash.index['primary']:get{3ULL}
+hash.index['primary']:get{4ULL}
+hash.index['primary']:get{5ULL}
+
+-- select by valid NUM keys
+hash.index['primary']:get{0}
+hash.index['primary']:get{1}
+hash.index['primary']:get{2}
+hash.index['primary']:get{3}
+hash.index['primary']:get{4}
+hash.index['primary']:get{5}
+
+-- select by invalid keys
+hash.index['primary']:get{'invalid key'}
+hash.index['primary']:get{'00000001', '00000002'}
+
+hash:drop()
diff --git a/test/box/hash_collation.result b/test/box/hash_collation.result
new file mode 100644
index 000000000..ea80b577d
--- /dev/null
+++ b/test/box/hash_collation.result
@@ -0,0 +1,62 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- Collation test
+-------------------------------------------------------------------------------
+
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
+ | ---
+ | ...
+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
+ | ---
+ | ...
+
+hash:insert{'Ёж', 'Hedgehog'}
+ | ---
+ | - ['Ёж', 'Hedgehog']
+ | ...
+hash:insert{'Ёлка', 'Spruce'}
+ | ---
+ | - ['Ёлка', 'Spruce']
+ | ...
+hash:insert{'Jogurt', 'Йогурт'}
+ | ---
+ | - ['Jogurt', 'Йогурт']
+ | ...
+hash:insert{'Один', 1}
+ | ---
+ | - ['Один', 1]
+ | ...
+
+hash.index.primary:get('ёж')
+ | ---
+ | - ['Ёж', 'Hedgehog']
+ | ...
+hash.index.primary:get('елка')
+ | ---
+ | - ['Ёлка', 'Spruce']
+ | ...
+hash.index.secondary:get('spruce')
+ | ---
+ | - ['Ёлка', 'Spruce']
+ | ...
+hash.index.secondary:get('йогурт')
+ | ---
+ | - ['Jogurt', 'Йогурт']
+ | ...
+hash.index.secondary:get(1)
+ | ---
+ | - ['Один', 1]
+ | ...
+hash.index.secondary:get('иогурт')
+ | ---
+ | ...
+hash.index.secondary:get(2)
+ | ---
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_collation.test.lua b/test/box/hash_collation.test.lua
new file mode 100644
index 000000000..f9bca79f6
--- /dev/null
+++ b/test/box/hash_collation.test.lua
@@ -0,0 +1,22 @@
+-------------------------------------------------------------------------------
+-- Collation test
+-------------------------------------------------------------------------------
+
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
+
+hash:insert{'Ёж', 'Hedgehog'}
+hash:insert{'Ёлка', 'Spruce'}
+hash:insert{'Jogurt', 'Йогурт'}
+hash:insert{'Один', 1}
+
+hash.index.primary:get('ёж')
+hash.index.primary:get('елка')
+hash.index.secondary:get('spruce')
+hash.index.secondary:get('йогурт')
+hash.index.secondary:get(1)
+hash.index.secondary:get('иогурт')
+hash.index.secondary:get(2)
+
+hash:drop()
diff --git a/test/box/hash_gh-1467.result b/test/box/hash_gh-1467.result
new file mode 100644
index 000000000..a2c736a11
--- /dev/null
+++ b/test/box/hash_gh-1467.result
@@ -0,0 +1,17 @@
+-- test-run result file version 2
+-- gh-1467: invalid iterator type
+
+space = box.schema.space.create('test')
+ | ---
+ | ...
+index = space:create_index('primary', { type = 'hash' })
+ | ---
+ | ...
+space:select({1}, {iterator = 'BITS_ALL_SET' } )
+ | ---
+ | - error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
+ |     iterator type
+ | ...
+space:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_gh-1467.test.lua b/test/box/hash_gh-1467.test.lua
new file mode 100644
index 000000000..d98c31734
--- /dev/null
+++ b/test/box/hash_gh-1467.test.lua
@@ -0,0 +1,6 @@
+-- gh-1467: invalid iterator type
+
+space = box.schema.space.create('test')
+index = space:create_index('primary', { type = 'hash' })
+space:select({1}, {iterator = 'BITS_ALL_SET' } )
+space:drop()
diff --git a/test/box/hash_gh-3907.result b/test/box/hash_gh-3907.result
new file mode 100644
index 000000000..4ce7e40f4
--- /dev/null
+++ b/test/box/hash_gh-3907.result
@@ -0,0 +1,48 @@
+-- test-run result file version 2
+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
+-- are hashed as MP_INT/MP_UINT.
+
+ffi = require('ffi')
+ | ---
+ | ...
+s = box.schema.space.create('test')
+ | ---
+ | ...
+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
+ | ---
+ | ...
+s:insert{ffi.new('double', 0)}
+ | ---
+ | - [0]
+ | ...
+s:insert{ffi.new('double', -1)}
+ | ---
+ | - [-1]
+ | ...
+s:insert{ffi.new('double', 9007199254740992)}
+ | ---
+ | - [9007199254740992]
+ | ...
+s:insert{ffi.new('double', -9007199254740994)}
+ | ---
+ | - [-9007199254740994]
+ | ...
+s:get(0LL)
+ | ---
+ | - [0]
+ | ...
+s:get(-1LL)
+ | ---
+ | - [-1]
+ | ...
+s:get(9007199254740992LL)
+ | ---
+ | - [9007199254740992]
+ | ...
+s:get(-9007199254740994LL)
+ | ---
+ | - [-9007199254740994]
+ | ...
+s:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_gh-3907.test.lua b/test/box/hash_gh-3907.test.lua
new file mode 100644
index 000000000..2bef03b0d
--- /dev/null
+++ b/test/box/hash_gh-3907.test.lua
@@ -0,0 +1,15 @@
+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
+-- are hashed as MP_INT/MP_UINT.
+
+ffi = require('ffi')
+s = box.schema.space.create('test')
+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
+s:insert{ffi.new('double', 0)}
+s:insert{ffi.new('double', -1)}
+s:insert{ffi.new('double', 9007199254740992)}
+s:insert{ffi.new('double', -9007199254740994)}
+s:get(0LL)
+s:get(-1LL)
+s:get(9007199254740992LL)
+s:get(-9007199254740994LL)
+s:drop()
diff --git a/test/box/hash_gh-616.result b/test/box/hash_gh-616.result
new file mode 100644
index 000000000..d5ee1eed9
--- /dev/null
+++ b/test/box/hash_gh-616.result
@@ -0,0 +1,17 @@
+-- test-run result file version 2
+-- 
+-- gh-616 "1-based indexing and 0-based error message
+--
+_ = box.schema.create_space('test')
+ | ---
+ | ...
+_ = box.space.test:create_index('i',{parts={1,'string'}})
+ | ---
+ | ...
+box.space.test:insert{1}
+ | ---
+ | - error: 'Tuple field 1 type does not match one required by operation: expected string'
+ | ...
+box.space.test:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_gh-616.test.lua b/test/box/hash_gh-616.test.lua
new file mode 100644
index 000000000..8ea5f725a
--- /dev/null
+++ b/test/box/hash_gh-616.test.lua
@@ -0,0 +1,7 @@
+-- 
+-- gh-616 "1-based indexing and 0-based error message
+--
+_ = box.schema.create_space('test')
+_ = box.space.test:create_index('i',{parts={1,'string'}})
+box.space.test:insert{1}
+box.space.test:drop()
diff --git a/test/box/hash_iterate.result b/test/box/hash_iterate.result
new file mode 100644
index 000000000..64660ad6d
--- /dev/null
+++ b/test/box/hash_iterate.result
@@ -0,0 +1,21 @@
+-- test-run result file version 2
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+hash:insert{0}
+ | ---
+ | - [0]
+ | ...
+hash:insert{16}
+ | ---
+ | - [16]
+ | ...
+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
+ | ---
+ | ...
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_iterate.test.lua b/test/box/hash_iterate.test.lua
new file mode 100644
index 000000000..1ee758a66
--- /dev/null
+++ b/test/box/hash_iterate.test.lua
@@ -0,0 +1,6 @@
+hash = box.schema.space.create('tweedledum')
+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+hash:insert{0}
+hash:insert{16}
+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
+hash:drop()
diff --git a/test/box/hash_multipart.result b/test/box/hash_multipart.result
index 3de8ee3be..e94313b62 100644
--- a/test/box/hash_multipart.result
+++ b/test/box/hash_multipart.result
@@ -131,13 +131,6 @@ hash.index['unique']:select{1, 'baz'}
 - error: 'Supplied key type of part 1 does not match index part type: expected unsigned'
 ...
 -- cleanup
-hash:truncate()
----
-...
-hash:len()
----
-- 0
-...
 hash:drop()
 ---
 ...
diff --git a/test/box/hash_multipart.test.lua b/test/box/hash_multipart.test.lua
index 8b40504b1..c0a871bee 100644
--- a/test/box/hash_multipart.test.lua
+++ b/test/box/hash_multipart.test.lua
@@ -53,6 +53,4 @@ hash.index['unique']:get{1}
 hash.index['unique']:select{1, 'baz'}
 
 -- cleanup
-hash:truncate()
-hash:len()
 hash:drop()
diff --git a/test/box/hash_not_a_multikey.result b/test/box/hash_not_a_multikey.result
new file mode 100644
index 000000000..334aa676d
--- /dev/null
+++ b/test/box/hash_not_a_multikey.result
@@ -0,0 +1,17 @@
+-- test-run result file version 2
+-- Hash index cannot be multikey.
+
+s = box.schema.space.create('test')
+ | ---
+ | ...
+_ = s:create_index('primary')
+ | ---
+ | ...
+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
+ | ---
+ | - error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
+ |     be multikey'
+ | ...
+s:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_not_a_multikey.test.lua b/test/box/hash_not_a_multikey.test.lua
new file mode 100644
index 000000000..bd82dfb83
--- /dev/null
+++ b/test/box/hash_not_a_multikey.test.lua
@@ -0,0 +1,6 @@
+-- Hash index cannot be multikey.
+
+s = box.schema.space.create('test')
+_ = s:create_index('primary')
+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
+s:drop()
diff --git a/test/box/hash_replace.result b/test/box/hash_replace.result
new file mode 100644
index 000000000..1b45f7914
--- /dev/null
+++ b/test/box/hash_replace.result
@@ -0,0 +1,256 @@
+-- test-run result file version 2
+------------------------
+-- hash::replace tests
+------------------------
+
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
+ | ---
+ | ...
+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
+ | ---
+ | ...
+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
+ | ---
+ | ...
+
+hash:insert{0, 0, 0, 0}
+ | ---
+ | - [0, 0, 0, 0]
+ | ...
+hash:insert{1, 1, 1, 1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+hash:insert{2, 2, 2, 2}
+ | ---
+ | - [2, 2, 2, 2]
+ | ...
+
+-- OK
+hash:replace{1, 1, 1, 1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | ...
+hash.index['primary']:get{1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+hash.index['field1']:get{1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+hash.index['field2']:get{1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+hash.index['field3']:get{1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+
+-- OK
+hash:insert{10, 10, 10, 10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash:delete{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | ...
+
+-- TupleFound (primary key)
+hash:insert{1, 10, 10, 10}
+ | ---
+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | ...
+hash.index['primary']:get{1}
+ | ---
+ | - [1, 1, 1, 1]
+ | ...
+
+-- TupleNotFound (primary key)
+hash:replace{10, 10, 10, 10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+
+-- TupleFound (key --1)
+hash:insert{10, 0, 10, 10}
+ | ---
+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{0}
+ | ---
+ | - [0, 0, 0, 0]
+ | ...
+
+-- TupleFound (key --1)
+-- hash:replace_if_exists(2, 0, 10, 10)
+hash.index['primary']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{0}
+ | ---
+ | - [0, 0, 0, 0]
+ | ...
+
+-- TupleFound (key --3)
+hash:insert{10, 10, 10, 0}
+ | ---
+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
+ | ...
+hash.index['primary']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{0}
+ | ---
+ | - [0, 0, 0, 0]
+ | ...
+
+-- TupleFound (key --3)
+-- hash:replace_if_exists(2, 10, 10, 0)
+hash.index['primary']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field1']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field2']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{10}
+ | ---
+ | - [10, 10, 10, 10]
+ | ...
+hash.index['field3']:get{0}
+ | ---
+ | - [0, 0, 0, 0]
+ | ...
+
+hash:drop()
+ | ---
+ | ...
+
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+ | ---
+ | ...
+hash:insert{0}
+ | ---
+ | - [0]
+ | ...
+hash:insert{16}
+ | ---
+ | - [16]
+ | ...
+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
+ | ---
+ | ...
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_replace.test.lua b/test/box/hash_replace.test.lua
new file mode 100644
index 000000000..d876f1f12
--- /dev/null
+++ b/test/box/hash_replace.test.lua
@@ -0,0 +1,88 @@
+------------------------
+-- hash::replace tests
+------------------------
+
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
+
+hash:insert{0, 0, 0, 0}
+hash:insert{1, 1, 1, 1}
+hash:insert{2, 2, 2, 2}
+
+-- OK
+hash:replace{1, 1, 1, 1}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['primary']:get{1}
+hash.index['field1']:get{1}
+hash.index['field2']:get{1}
+hash.index['field3']:get{1}
+
+-- OK
+hash:insert{10, 10, 10, 10}
+hash:delete{10}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+
+-- TupleFound (primary key)
+hash:insert{1, 10, 10, 10}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['primary']:get{1}
+
+-- TupleNotFound (primary key)
+hash:replace{10, 10, 10, 10}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+
+-- TupleFound (key --1)
+hash:insert{10, 0, 10, 10}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['field1']:get{0}
+
+-- TupleFound (key --1)
+-- hash:replace_if_exists(2, 0, 10, 10)
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['field1']:get{0}
+
+-- TupleFound (key --3)
+hash:insert{10, 10, 10, 0}
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['field3']:get{0}
+
+-- TupleFound (key --3)
+-- hash:replace_if_exists(2, 10, 10, 0)
+hash.index['primary']:get{10}
+hash.index['field1']:get{10}
+hash.index['field2']:get{10}
+hash.index['field3']:get{10}
+hash.index['field3']:get{0}
+
+hash:drop()
+
+hash = box.schema.space.create('tweedledum')
+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
+hash:insert{0}
+hash:insert{16}
+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
+hash:drop()
diff --git a/test/box/hash_string_delete.result b/test/box/hash_string_delete.result
new file mode 100644
index 000000000..3458f3c68
--- /dev/null
+++ b/test/box/hash_string_delete.result
@@ -0,0 +1,62 @@
+-- test-run result file version 2
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- String hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{'key 0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{'key 1'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{'key 2'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{'key 3'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:delete{'key 4'}
+ | ---
+ | ...
+hash:delete{'key 5'}
+ | ---
+ | ...
+
+-- delete by invalid keys
+hash:delete{'key 1', 'key 2'}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_string_delete.test.lua b/test/box/hash_string_delete.test.lua
new file mode 100644
index 000000000..612217ec9
--- /dev/null
+++ b/test/box/hash_string_delete.test.lua
@@ -0,0 +1,24 @@
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- String hash delete fields test
+-------------------------------------------------------------------------------
+
+-- delete by valid keys
+hash:delete{'key 0'}
+hash:delete{'key 1'}
+hash:delete{'key 2'}
+hash:delete{'key 3'}
+hash:delete{'key 4'}
+hash:delete{'key 5'}
+
+-- delete by invalid keys
+hash:delete{'key 1', 'key 2'}
+hash:drop()
diff --git a/test/box/hash_string_insert.result b/test/box/hash_string_insert.result
new file mode 100644
index 000000000..50a52b6a8
--- /dev/null
+++ b/test/box/hash_string_insert.result
@@ -0,0 +1,32 @@
+-- test-run result file version 2
+-------------------------------------------------------------------------------
+-- String hash inset fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_string_insert.test.lua b/test/box/hash_string_insert.test.lua
new file mode 100644
index 000000000..9788abc0d
--- /dev/null
+++ b/test/box/hash_string_insert.test.lua
@@ -0,0 +1,13 @@
+-------------------------------------------------------------------------------
+-- String hash inset fields tests
+-------------------------------------------------------------------------------
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+
+hash:drop()
diff --git a/test/box/hash_string_replace.result b/test/box/hash_string_replace.result
new file mode 100644
index 000000000..1fb525d71
--- /dev/null
+++ b/test/box/hash_string_replace.result
@@ -0,0 +1,47 @@
+-- test-run result file version 2
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- String hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
+ | ---
+ | - ['key 3', 'value1 v1.31', 'value2 1.12']
+ | ...
+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
+ | ---
+ | - ['key 1', 'value1 v1.32', 'value2 1.72']
+ | ...
+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
+ | ---
+ | - ['key 2', 'value1 v1.43', 'value2 1.92']
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_string_replace.test.lua b/test/box/hash_string_replace.test.lua
new file mode 100644
index 000000000..db5cfa93e
--- /dev/null
+++ b/test/box/hash_string_replace.test.lua
@@ -0,0 +1,19 @@
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- String hash replace fields tests
+-------------------------------------------------------------------------------
+
+-- Replace valid fields
+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
+
+hash:drop()
diff --git a/test/box/hash_string_select.result b/test/box/hash_string_select.result
new file mode 100644
index 000000000..16cb22d3c
--- /dev/null
+++ b/test/box/hash_string_select.result
@@ -0,0 +1,63 @@
+-- test-run result file version 2
+hash = box.schema.space.create('tweedledum')
+ | ---
+ | ...
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+ | ---
+ | ...
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+
+-------------------------------------------------------------------------------
+-- String hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{'key 0'}
+ | ---
+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{'key 1'}
+ | ---
+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{'key 2'}
+ | ---
+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{'key 3'}
+ | ---
+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
+ | ...
+hash.index['primary']:get{'key 4'}
+ | ---
+ | ...
+hash.index['primary']:get{'key 5'}
+ | ---
+ | ...
+
+-- select by invalid keys
+hash.index['primary']:get{'key 1', 'key 2'}
+ | ---
+ | - error: Invalid key part count in an exact match (expected 1, got 2)
+ | ...
+
+hash:drop()
+ | ---
+ | ...
diff --git a/test/box/hash_string_select.test.lua b/test/box/hash_string_select.test.lua
new file mode 100644
index 000000000..ef3f10018
--- /dev/null
+++ b/test/box/hash_string_select.test.lua
@@ -0,0 +1,25 @@
+hash = box.schema.space.create('tweedledum')
+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
+
+-- Insert valid fields
+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
+
+-------------------------------------------------------------------------------
+-- String hash select fields test
+-------------------------------------------------------------------------------
+
+-- select by valid keys
+hash.index['primary']:get{'key 0'}
+hash.index['primary']:get{'key 1'}
+hash.index['primary']:get{'key 2'}
+hash.index['primary']:get{'key 3'}
+hash.index['primary']:get{'key 4'}
+hash.index['primary']:get{'key 5'}
+
+-- select by invalid keys
+hash.index['primary']:get{'key 1', 'key 2'}
+
+hash:drop()
diff --git a/test/box/hash_with_function.result b/test/box/hash_with_function.result
new file mode 100644
index 000000000..cac268281
--- /dev/null
+++ b/test/box/hash_with_function.result
@@ -0,0 +1,26 @@
+-- test-run result file version 2
+-- Hash index can not use function.
+
+s = box.schema.space.create('withdata')
+ | ---
+ | ...
+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
+ | ---
+ | ...
+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
+ | ---
+ | ...
+_ = s:create_index('pk')
+ | ---
+ | ...
+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
+ | ---
+ | - error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
+ |     can not use a function'
+ | ...
+s:drop()
+ | ---
+ | ...
+box.schema.func.drop('s')
+ | ---
+ | ...
diff --git a/test/box/hash_with_function.test.lua b/test/box/hash_with_function.test.lua
new file mode 100644
index 000000000..9653de68e
--- /dev/null
+++ b/test/box/hash_with_function.test.lua
@@ -0,0 +1,9 @@
+-- Hash index can not use function.
+
+s = box.schema.space.create('withdata')
+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
+_ = s:create_index('pk')
+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
+s:drop()
+box.schema.func.drop('s')
-- 
2.23.0


-- 
sergeyb@

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-19 10:24 [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests Sergey Bronnikov
@ 2020-03-19 11:09 ` Oleg Piskunov
  2020-03-19 14:22 ` Alexander Tikhonov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Oleg Piskunov @ 2020-03-19 11:09 UTC (permalink / raw)
  To: Sergey Bronnikov; +Cc: tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 94742 bytes --]


LGTM.
  
>Четверг, 19 марта 2020, 13:25 +03:00 от Sergey Bronnikov <sergeyb@tarantool.org>:
> 
>Splitted single hash.test.lua to a set of small independent tests.
>
>GitHub branch:  https://github.com/tarantool/tarantool/tree/ligurio/hash_test_split
>
>---
> test/box/hash.result | 873 --------------------------
> test/box/hash.test.lua | 364 -----------
> test/box/hash_32bit_delete.result | 70 +++
> test/box/hash_32bit_delete.test.lua | 29 +
> test/box/hash_32bit_insert.result | 38 ++
> test/box/hash_32bit_insert.test.lua | 16 +
> test/box/hash_32bit_replace.result | 56 ++
> test/box/hash_32bit_replace.test.lua | 25 +
> test/box/hash_32bit_select.result | 70 +++
> test/box/hash_32bit_select.test.lua | 29 +
> test/box/hash_64bit_delete.result | 111 ++++
> test/box/hash_64bit_delete.test.lua | 42 ++
> test/box/hash_64bit_insert.result | 54 ++
> test/box/hash_64bit_insert.test.lua | 20 +
> test/box/hash_64bit_replace.result | 68 ++
> test/box/hash_64bit_replace.test.lua | 28 +
> test/box/hash_64bit_select.result | 94 +++
> test/box/hash_64bit_select.test.lua | 37 ++
> test/box/hash_collation.result | 62 ++
> test/box/hash_collation.test.lua | 22 +
> test/box/hash_gh-1467.result | 17 +
> test/box/hash_gh-1467.test.lua | 6 +
> test/box/hash_gh-3907.result | 48 ++
> test/box/hash_gh-3907.test.lua | 15 +
> test/box/hash_gh-616.result | 17 +
> test/box/hash_gh-616.test.lua | 7 +
> test/box/hash_iterate.result | 21 +
> test/box/hash_iterate.test.lua | 6 +
> test/box/hash_multipart.result | 7 -
> test/box/hash_multipart.test.lua | 2 -
> test/box/hash_not_a_multikey.result | 17 +
> test/box/hash_not_a_multikey.test.lua | 6 +
> test/box/hash_replace.result | 256 ++++++++
> test/box/hash_replace.test.lua | 88 +++
> test/box/hash_string_delete.result | 62 ++
> test/box/hash_string_delete.test.lua | 24 +
> test/box/hash_string_insert.result | 32 +
> test/box/hash_string_insert.test.lua | 13 +
> test/box/hash_string_replace.result | 47 ++
> test/box/hash_string_replace.test.lua | 19 +
> test/box/hash_string_select.result | 63 ++
> test/box/hash_string_select.test.lua | 25 +
> test/box/hash_with_function.result | 26 +
> test/box/hash_with_function.test.lua | 9 +
> 44 files changed, 1695 insertions(+), 1246 deletions(-)
> delete mode 100644 test/box/hash.result
> delete mode 100644 test/box/hash.test.lua
> create mode 100644 test/box/hash_32bit_delete.result
> create mode 100644 test/box/hash_32bit_delete.test.lua
> create mode 100644 test/box/hash_32bit_insert.result
> create mode 100644 test/box/hash_32bit_insert.test.lua
> create mode 100644 test/box/hash_32bit_replace.result
> create mode 100644 test/box/hash_32bit_replace.test.lua
> create mode 100644 test/box/hash_32bit_select.result
> create mode 100644 test/box/hash_32bit_select.test.lua
> create mode 100644 test/box/hash_64bit_delete.result
> create mode 100644 test/box/hash_64bit_delete.test.lua
> create mode 100644 test/box/hash_64bit_insert.result
> create mode 100644 test/box/hash_64bit_insert.test.lua
> create mode 100644 test/box/hash_64bit_replace.result
> create mode 100644 test/box/hash_64bit_replace.test.lua
> create mode 100644 test/box/hash_64bit_select.result
> create mode 100644 test/box/hash_64bit_select.test.lua
> create mode 100644 test/box/hash_collation.result
> create mode 100644 test/box/hash_collation.test.lua
> create mode 100644 test/box/hash_gh-1467.result
> create mode 100644 test/box/hash_gh-1467.test.lua
> create mode 100644 test/box/hash_gh-3907.result
> create mode 100644 test/box/hash_gh-3907.test.lua
> create mode 100644 test/box/hash_gh-616.result
> create mode 100644 test/box/hash_gh-616.test.lua
> create mode 100644 test/box/hash_iterate.result
> create mode 100644 test/box/hash_iterate.test.lua
> create mode 100644 test/box/hash_not_a_multikey.result
> create mode 100644 test/box/hash_not_a_multikey.test.lua
> create mode 100644 test/box/hash_replace.result
> create mode 100644 test/box/hash_replace.test.lua
> create mode 100644 test/box/hash_string_delete.result
> create mode 100644 test/box/hash_string_delete.test.lua
> create mode 100644 test/box/hash_string_insert.result
> create mode 100644 test/box/hash_string_insert.test.lua
> create mode 100644 test/box/hash_string_replace.result
> create mode 100644 test/box/hash_string_replace.test.lua
> create mode 100644 test/box/hash_string_select.result
> create mode 100644 test/box/hash_string_select.test.lua
> create mode 100644 test/box/hash_with_function.result
> create mode 100644 test/box/hash_with_function.test.lua
>
>diff --git a/test/box/hash.result b/test/box/hash.result
>deleted file mode 100644
>index 5e1441ecc..000000000
>--- a/test/box/hash.result
>+++ /dev/null
>@@ -1,873 +0,0 @@
>---=============================================================================
>--- 32-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 32-bit hash insert fields tests
>--------------------------------------------------------------------------------
>-hash = box.schema.space.create('tweedledum')
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-bsize = tmp:bsize()
>----
>-...
>--- Insert valid fields
>-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>-tmp:bsize() > bsize
>----
>-- true
>-...
>--- Insert invalid fields
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>--- Replace invalid fields
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4}
>----
>-...
>-hash.index['primary']:get{5}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash.index['primary']:get{1, 2}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{4}
>----
>-...
>-hash:delete{5}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash:delete{1, 2}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>---=============================================================================
>--- 64-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 64-bit hash inset fields tests
>--------------------------------------------------------------------------------
>--- Insert valid fields
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>--- Insert invalid fields
>-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [100, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [101, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [102, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [103, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>--- Replace invalid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{0ULL}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1ULL}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2ULL}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3ULL}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4ULL}
>----
>-...
>-hash.index['primary']:get{5ULL}
>----
>-...
>--- select by valid NUM keys
>-hash.index['primary']:get{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4}
>----
>-...
>-hash.index['primary']:get{5}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash.index['primary']:get{'00000001', '00000002'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{0ULL}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1ULL}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{2ULL}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{3ULL}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{4ULL}
>----
>-...
>-hash:delete{5ULL}
>----
>-...
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>--- delete by valid NUM keys
>-hash:delete{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{2}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{3}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{4}
>----
>-...
>-hash:delete{5}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash:delete{'00000001', '00000002'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>---=============================================================================
>--- String hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- String hash inset fields tests
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>----
>-...
>--- Insert valid fields
>-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 1', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 2', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 3', 'value1 v1.0', 'value2 v1.0']
>-...
>--------------------------------------------------------------------------------
>--- String hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>--------------------------------------------------------------------------------
>--- String hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{'key 0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{'key 1'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{'key 2'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{'key 3'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{'key 4'}
>----
>-...
>-hash.index['primary']:get{'key 5'}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'key 1', 'key 2'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- String hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{'key 0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{'key 1'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{'key 2'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{'key 3'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{'key 4'}
>----
>-...
>-hash:delete{'key 5'}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'key 1', 'key 2'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>--------------------------------------------------------------------------------
>--- Collation test
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>----
>-...
>-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>----
>-...
>-hash:insert{'Ёж', 'Hedgehog'}
>----
>-- ['Ёж', 'Hedgehog']
>-...
>-hash:insert{'Ёлка', 'Spruce'}
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash:insert{'Jogurt', 'Йогурт'}
>----
>-- ['Jogurt', 'Йогурт']
>-...
>-hash:insert{'Один', 1}
>----
>-- ['Один', 1]
>-...
>-hash.index.primary:get('ёж')
>----
>-- ['Ёж', 'Hedgehog']
>-...
>-hash.index.primary:get('елка')
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash.index.secondary:get('spruce')
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash.index.secondary:get('йогурт')
>----
>-- ['Jogurt', 'Йогурт']
>-...
>-hash.index.secondary:get(1)
>----
>-- ['Один', 1]
>-...
>-hash.index.secondary:get('иогурт')
>----
>-...
>-hash.index.secondary:get(2)
>----
>-...
>-------------------------
>--- hash::replace tests
>-------------------------
>-hash.index['secondary']:drop()
>----
>-...
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>----
>-...
>-hash:insert{0, 0, 0, 0}
>----
>-- [0, 0, 0, 0]
>-...
>-hash:insert{1, 1, 1, 1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash:insert{2, 2, 2, 2}
>----
>-- [2, 2, 2, 2]
>-...
>--- OK
>-hash:replace{1, 1, 1, 1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field1']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field2']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field3']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>--- OK
>-hash:insert{10, 10, 10, 10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash:delete{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>--- TupleFound (primary key)
>-hash:insert{1, 10, 10, 10}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>--- TupleNotFound (primary key)
>-hash:replace{10, 10, 10, 10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>--- TupleFound (key --1)
>-hash:insert{10, 0, 10, 10}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --1)
>--- hash:replace_if_exists(2, 0, 10, 10)
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --3)
>-hash:insert{10, 10, 10, 0}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --3)
>--- hash:replace_if_exists(2, 10, 10, 0)
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>-hash:drop()
>----
>-...
>-hash = box.schema.space.create('tweedledum')
>----
>-...
>-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-hash:insert{0}
>----
>-- [0]
>-...
>-hash:insert{16}
>----
>-- [16]
>-...
>-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>----
>-...
>-hash:drop()
>----
>-...
>---
>--- gh-616 "1-based indexing and 0-based error message
>---
>-_ = box.schema.create_space('test')
>----
>-...
>-_ = box.space.test:create_index('i',{parts={1,'string'}})
>----
>-...
>-box.space.test:insert{1}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected string'
>-...
>-box.space.test:drop()
>----
>-...
>--- gh-1467: invalid iterator type
>-space = box.schema.space.create('test')
>----
>-...
>-index = space:create_index('primary', { type = 'hash' })
>----
>-...
>-space:select({1}, {iterator = 'BITS_ALL_SET' } )
>----
>-- error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
>- iterator type
>-...
>-space:drop()
>----
>-...
>--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>--- are hashed as MP_INT/MP_UINT.
>-ffi = require('ffi')
>----
>-...
>-s = box.schema.space.create('test')
>----
>-...
>-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>----
>-...
>-s:insert{ffi.new('double', 0)}
>----
>-- [0]
>-...
>-s:insert{ffi.new('double', -1)}
>----
>-- [-1]
>-...
>-s:insert{ffi.new('double', 9007199254740992)}
>----
>-- [9007199254740992]
>-...
>-s:insert{ffi.new('double', -9007199254740994)}
>----
>-- [-9007199254740994]
>-...
>-s:get(0LL)
>----
>-- [0]
>-...
>-s:get(-1LL)
>----
>-- [-1]
>-...
>-s:get(9007199254740992LL)
>----
>-- [9007199254740992]
>-...
>-s:get(-9007199254740994LL)
>----
>-- [-9007199254740994]
>-...
>-s:drop()
>----
>-...
>--- Hash index cannot be multikey.
>-s = box.schema.space.create('test')
>----
>-...
>-_ = s:create_index('primary')
>----
>-...
>-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>----
>-- error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
>- be multikey'
>-...
>-s:drop()
>----
>-...
>--- Hash index can not use function.
>-s = box.schema.space.create('withdata')
>----
>-...
>-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>----
>-...
>-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>----
>-...
>-_ = s:create_index('pk')
>----
>-...
>-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>----
>-- error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
>- can not use a function'
>-...
>-s:drop()
>----
>-...
>-box.schema.func.drop('s')
>----
>-...
>diff --git a/test/box/hash.test.lua b/test/box/hash.test.lua
>deleted file mode 100644
>index 78c831f77..000000000
>--- a/test/box/hash.test.lua
>+++ /dev/null
>@@ -1,364 +0,0 @@
>---=============================================================================
>--- 32-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 32-bit hash insert fields tests
>--------------------------------------------------------------------------------
>-hash = box.schema.space.create('tweedledum')
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-
>-bsize = tmp:bsize()
>-
>--- Insert valid fields
>-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>-
>-tmp:bsize() > bsize
>-
>--- Insert invalid fields
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>-
>--- Replace invalid fields
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{0}
>-hash.index['primary']:get{1}
>-hash.index['primary']:get{2}
>-hash.index['primary']:get{3}
>-hash.index['primary']:get{4}
>-hash.index['primary']:get{5}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>-hash.index['primary']:get{1, 2}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{0}
>-hash:delete{1}
>-hash:delete{2}
>-hash:delete{3}
>-hash:delete{4}
>-hash:delete{5}
>-
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>-hash:delete{1, 2}
>-
>-hash:truncate()
>-
>---=============================================================================
>--- 64-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 64-bit hash inset fields tests
>--------------------------------------------------------------------------------
>-
>--- Insert valid fields
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>-
>--- Insert invalid fields
>-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>-
>--- Replace invalid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{0ULL}
>-hash.index['primary']:get{1ULL}
>-hash.index['primary']:get{2ULL}
>-hash.index['primary']:get{3ULL}
>-hash.index['primary']:get{4ULL}
>-hash.index['primary']:get{5ULL}
>-
>--- select by valid NUM keys
>-hash.index['primary']:get{0}
>-hash.index['primary']:get{1}
>-hash.index['primary']:get{2}
>-hash.index['primary']:get{3}
>-hash.index['primary']:get{4}
>-hash.index['primary']:get{5}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>-hash.index['primary']:get{'00000001', '00000002'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{0ULL}
>-hash:delete{1ULL}
>-hash:delete{2ULL}
>-hash:delete{3ULL}
>-hash:delete{4ULL}
>-hash:delete{5ULL}
>-
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>-
>--- delete by valid NUM keys
>-hash:delete{0}
>-hash:delete{1}
>-hash:delete{2}
>-hash:delete{3}
>-hash:delete{4}
>-hash:delete{5}
>-
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>-hash:delete{'00000001', '00000002'}
>-hash:truncate()
>-
>---=============================================================================
>--- String hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- String hash inset fields tests
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>-
>--- Insert valid fields
>-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- String hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>-
>--------------------------------------------------------------------------------
>--- String hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{'key 0'}
>-hash.index['primary']:get{'key 1'}
>-hash.index['primary']:get{'key 2'}
>-hash.index['primary']:get{'key 3'}
>-hash.index['primary']:get{'key 4'}
>-hash.index['primary']:get{'key 5'}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'key 1', 'key 2'}
>-
>--------------------------------------------------------------------------------
>--- String hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{'key 0'}
>-hash:delete{'key 1'}
>-hash:delete{'key 2'}
>-hash:delete{'key 3'}
>-hash:delete{'key 4'}
>-hash:delete{'key 5'}
>-
>--- delete by invalid keys
>-hash:delete{'key 1', 'key 2'}
>-hash:truncate()
>-
>--------------------------------------------------------------------------------
>--- Collation test
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>-
>-hash:insert{'Ёж', 'Hedgehog'}
>-hash:insert{'Ёлка', 'Spruce'}
>-hash:insert{'Jogurt', 'Йогурт'}
>-hash:insert{'Один', 1}
>-
>-hash.index.primary:get('ёж')
>-hash.index.primary:get('елка')
>-hash.index.secondary:get('spruce')
>-hash.index.secondary:get('йогурт')
>-hash.index.secondary:get(1)
>-hash.index.secondary:get('иогурт')
>-hash.index.secondary:get(2)
>-
>-------------------------
>--- hash::replace tests
>-------------------------
>-hash.index['secondary']:drop()
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>-
>-hash:insert{0, 0, 0, 0}
>-hash:insert{1, 1, 1, 1}
>-hash:insert{2, 2, 2, 2}
>-
>--- OK
>-hash:replace{1, 1, 1, 1}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['primary']:get{1}
>-hash.index['field1']:get{1}
>-hash.index['field2']:get{1}
>-hash.index['field3']:get{1}
>-
>--- OK
>-hash:insert{10, 10, 10, 10}
>-hash:delete{10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-
>--- TupleFound (primary key)
>-hash:insert{1, 10, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['primary']:get{1}
>-
>--- TupleNotFound (primary key)
>-hash:replace{10, 10, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-
>--- TupleFound (key --1)
>-hash:insert{10, 0, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field1']:get{0}
>-
>--- TupleFound (key --1)
>--- hash:replace_if_exists(2, 0, 10, 10)
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field1']:get{0}
>-
>--- TupleFound (key --3)
>-hash:insert{10, 10, 10, 0}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field3']:get{0}
>-
>--- TupleFound (key --3)
>--- hash:replace_if_exists(2, 10, 10, 0)
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field3']:get{0}
>-
>-hash:drop()
>-
>-hash = box.schema.space.create('tweedledum')
>-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-hash:insert{0}
>-hash:insert{16}
>-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>-hash:drop()
>-
>---
>--- gh-616 "1-based indexing and 0-based error message
>---
>-_ = box.schema.create_space('test')
>-_ = box.space.test:create_index('i',{parts={1,'string'}})
>-box.space.test:insert{1}
>-box.space.test:drop()
>-
>--- gh-1467: invalid iterator type
>-space = box.schema.space.create('test')
>-index = space:create_index('primary', { type = 'hash' })
>-space:select({1}, {iterator = 'BITS_ALL_SET' } )
>-space:drop()
>-
>--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>--- are hashed as MP_INT/MP_UINT.
>-ffi = require('ffi')
>-s = box.schema.space.create('test')
>-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>-s:insert{ffi.new('double', 0)}
>-s:insert{ffi.new('double', -1)}
>-s:insert{ffi.new('double', 9007199254740992)}
>-s:insert{ffi.new('double', -9007199254740994)}
>-s:get(0LL)
>-s:get(-1LL)
>-s:get(9007199254740992LL)
>-s:get(-9007199254740994LL)
>-s:drop()
>-
>--- Hash index cannot be multikey.
>-s = box.schema.space.create('test')
>-_ = s:create_index('primary')
>-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>-s:drop()
>-
>--- Hash index can not use function.
>-s = box.schema.space.create('withdata')
>-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>-_ = s:create_index('pk')
>-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>-s:drop()
>-box.schema.func.drop('s')
>diff --git a/test/box/hash_32bit_delete.result b/test/box/hash_32bit_delete.result
>new file mode 100644
>index 000000000..b35143b10
>--- /dev/null
>+++ b/test/box/hash_32bit_delete.result
>@@ -0,0 +1,70 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4}
>+ | ---
>+ | ...
>+hash:delete{5}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash:delete{1, 2}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_delete.test.lua b/test/box/hash_32bit_delete.test.lua
>new file mode 100644
>index 000000000..682e0bc96
>--- /dev/null
>+++ b/test/box/hash_32bit_delete.test.lua
>@@ -0,0 +1,29 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0}
>+hash:delete{1}
>+hash:delete{2}
>+hash:delete{3}
>+hash:delete{4}
>+hash:delete{5}
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+hash:delete{1, 2}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_insert.result b/test/box/hash_32bit_insert.result
>new file mode 100644
>index 000000000..72c7c4842
>--- /dev/null
>+++ b/test/box/hash_32bit_insert.result
>@@ -0,0 +1,38 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- Insert invalid fields
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_insert.test.lua b/test/box/hash_32bit_insert.test.lua
>new file mode 100644
>index 000000000..308b27d3e
>--- /dev/null
>+++ b/test/box/hash_32bit_insert.test.lua
>@@ -0,0 +1,16 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- Insert invalid fields
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_replace.result b/test/box/hash_32bit_replace.result
>new file mode 100644
>index 000000000..a1feba851
>--- /dev/null
>+++ b/test/box/hash_32bit_replace.result
>@@ -0,0 +1,56 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+-- Replace invalid fields
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_replace.test.lua b/test/box/hash_32bit_replace.test.lua
>new file mode 100644
>index 000000000..a00b02185
>--- /dev/null
>+++ b/test/box/hash_32bit_replace.test.lua
>@@ -0,0 +1,25 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+
>+-- Replace invalid fields
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_select.result b/test/box/hash_32bit_select.result
>new file mode 100644
>index 000000000..f80df9bbd
>--- /dev/null
>+++ b/test/box/hash_32bit_select.result
>@@ -0,0 +1,70 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash.index['primary']:get{1, 2}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_select.test.lua b/test/box/hash_32bit_select.test.lua
>new file mode 100644
>index 000000000..e077cc48d
>--- /dev/null
>+++ b/test/box/hash_32bit_select.test.lua
>@@ -0,0 +1,29 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0}
>+hash.index['primary']:get{1}
>+hash.index['primary']:get{2}
>+hash.index['primary']:get{3}
>+hash.index['primary']:get{4}
>+hash.index['primary']:get{5}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+hash.index['primary']:get{1, 2}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_delete.result b/test/box/hash_64bit_delete.result
>new file mode 100644
>index 000000000..88079e6f2
>--- /dev/null
>+++ b/test/box/hash_64bit_delete.result
>@@ -0,0 +1,111 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0ULL}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1ULL}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2ULL}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3ULL}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4ULL}
>+ | ---
>+ | ...
>+hash:delete{5ULL}
>+ | ---
>+ | ...
>+
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- delete by valid NUM keys
>+hash:delete{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4}
>+ | ---
>+ | ...
>+hash:delete{5}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash:delete{'00000001', '00000002'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_delete.test.lua b/test/box/hash_64bit_delete.test.lua
>new file mode 100644
>index 000000000..75675381f
>--- /dev/null
>+++ b/test/box/hash_64bit_delete.test.lua
>@@ -0,0 +1,42 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0ULL}
>+hash:delete{1ULL}
>+hash:delete{2ULL}
>+hash:delete{3ULL}
>+hash:delete{4ULL}
>+hash:delete{5ULL}
>+
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- delete by valid NUM keys
>+hash:delete{0}
>+hash:delete{1}
>+hash:delete{2}
>+hash:delete{3}
>+hash:delete{4}
>+hash:delete{5}
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+hash:delete{'00000001', '00000002'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_insert.result b/test/box/hash_64bit_insert.result
>new file mode 100644
>index 000000000..3f1275576
>--- /dev/null
>+++ b/test/box/hash_64bit_insert.result
>@@ -0,0 +1,54 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- Insert invalid fields
>+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [100, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [101, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [102, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [103, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_insert.test.lua b/test/box/hash_64bit_insert.test.lua
>new file mode 100644
>index 000000000..c69214b4e
>--- /dev/null
>+++ b/test/box/hash_64bit_insert.test.lua
>@@ -0,0 +1,20 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- Insert invalid fields
>+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_replace.result b/test/box/hash_64bit_replace.result
>new file mode 100644
>index 000000000..0bf900818
>--- /dev/null
>+++ b/test/box/hash_64bit_replace.result
>@@ -0,0 +1,68 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+-- Replace invalid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_replace.test.lua b/test/box/hash_64bit_replace.test.lua
>new file mode 100644
>index 000000000..4213110bc
>--- /dev/null
>+++ b/test/box/hash_64bit_replace.test.lua
>@@ -0,0 +1,28 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>+
>+-- Replace invalid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_select.result b/test/box/hash_64bit_select.result
>new file mode 100644
>index 000000000..74dd56727
>--- /dev/null
>+++ b/test/box/hash_64bit_select.result
>@@ -0,0 +1,94 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0ULL}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1ULL}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2ULL}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3ULL}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4ULL}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5ULL}
>+ | ---
>+ | ...
>+
>+-- select by valid NUM keys
>+hash.index['primary']:get{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash.index['primary']:get{'00000001', '00000002'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_select.test.lua b/test/box/hash_64bit_select.test.lua
>new file mode 100644
>index 000000000..724fb24be
>--- /dev/null
>+++ b/test/box/hash_64bit_select.test.lua
>@@ -0,0 +1,37 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0ULL}
>+hash.index['primary']:get{1ULL}
>+hash.index['primary']:get{2ULL}
>+hash.index['primary']:get{3ULL}
>+hash.index['primary']:get{4ULL}
>+hash.index['primary']:get{5ULL}
>+
>+-- select by valid NUM keys
>+hash.index['primary']:get{0}
>+hash.index['primary']:get{1}
>+hash.index['primary']:get{2}
>+hash.index['primary']:get{3}
>+hash.index['primary']:get{4}
>+hash.index['primary']:get{5}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+hash.index['primary']:get{'00000001', '00000002'}
>+
>+hash:drop()
>diff --git a/test/box/hash_collation.result b/test/box/hash_collation.result
>new file mode 100644
>index 000000000..ea80b577d
>--- /dev/null
>+++ b/test/box/hash_collation.result
>@@ -0,0 +1,62 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- Collation test
>+-------------------------------------------------------------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>+ | ---
>+ | ...
>+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>+ | ---
>+ | ...
>+
>+hash:insert{'Ёж', 'Hedgehog'}
>+ | ---
>+ | - ['Ёж', 'Hedgehog']
>+ | ...
>+hash:insert{'Ёлка', 'Spruce'}
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash:insert{'Jogurt', 'Йогурт'}
>+ | ---
>+ | - ['Jogurt', 'Йогурт']
>+ | ...
>+hash:insert{'Один', 1}
>+ | ---
>+ | - ['Один', 1]
>+ | ...
>+
>+hash.index.primary:get('ёж')
>+ | ---
>+ | - ['Ёж', 'Hedgehog']
>+ | ...
>+hash.index.primary:get('елка')
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash.index.secondary:get('spruce')
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash.index.secondary:get('йогурт')
>+ | ---
>+ | - ['Jogurt', 'Йогурт']
>+ | ...
>+hash.index.secondary:get(1)
>+ | ---
>+ | - ['Один', 1]
>+ | ...
>+hash.index.secondary:get('иогурт')
>+ | ---
>+ | ...
>+hash.index.secondary:get(2)
>+ | ---
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_collation.test.lua b/test/box/hash_collation.test.lua
>new file mode 100644
>index 000000000..f9bca79f6
>--- /dev/null
>+++ b/test/box/hash_collation.test.lua
>@@ -0,0 +1,22 @@
>+-------------------------------------------------------------------------------
>+-- Collation test
>+-------------------------------------------------------------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>+
>+hash:insert{'Ёж', 'Hedgehog'}
>+hash:insert{'Ёлка', 'Spruce'}
>+hash:insert{'Jogurt', 'Йогурт'}
>+hash:insert{'Один', 1}
>+
>+hash.index.primary:get('ёж')
>+hash.index.primary:get('елка')
>+hash.index.secondary:get('spruce')
>+hash.index.secondary:get('йогурт')
>+hash.index.secondary:get(1)
>+hash.index.secondary:get('иогурт')
>+hash.index.secondary:get(2)
>+
>+hash:drop()
>diff --git a/test/box/hash_gh-1467.result b/test/box/hash_gh-1467.result
>new file mode 100644
>index 000000000..a2c736a11
>--- /dev/null
>+++ b/test/box/hash_gh-1467.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+-- gh-1467: invalid iterator type
>+
>+space = box.schema.space.create('test')
>+ | ---
>+ | ...
>+index = space:create_index('primary', { type = 'hash' })
>+ | ---
>+ | ...
>+space:select({1}, {iterator = 'BITS_ALL_SET' } )
>+ | ---
>+ | - error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
>+ | iterator type
>+ | ...
>+space:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-1467.test.lua b/test/box/hash_gh-1467.test.lua
>new file mode 100644
>index 000000000..d98c31734
>--- /dev/null
>+++ b/test/box/hash_gh-1467.test.lua
>@@ -0,0 +1,6 @@
>+-- gh-1467: invalid iterator type
>+
>+space = box.schema.space.create('test')
>+index = space:create_index('primary', { type = 'hash' })
>+space:select({1}, {iterator = 'BITS_ALL_SET' } )
>+space:drop()
>diff --git a/test/box/hash_gh-3907.result b/test/box/hash_gh-3907.result
>new file mode 100644
>index 000000000..4ce7e40f4
>--- /dev/null
>+++ b/test/box/hash_gh-3907.result
>@@ -0,0 +1,48 @@
>+-- test-run result file version 2
>+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>+-- are hashed as MP_INT/MP_UINT.
>+
>+ffi = require('ffi')
>+ | ---
>+ | ...
>+s = box.schema.space.create('test')
>+ | ---
>+ | ...
>+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>+ | ---
>+ | ...
>+s:insert{ffi.new('double', 0)}
>+ | ---
>+ | - [0]
>+ | ...
>+s:insert{ffi.new('double', -1)}
>+ | ---
>+ | - [-1]
>+ | ...
>+s:insert{ffi.new('double', 9007199254740992)}
>+ | ---
>+ | - [9007199254740992]
>+ | ...
>+s:insert{ffi.new('double', -9007199254740994)}
>+ | ---
>+ | - [-9007199254740994]
>+ | ...
>+s:get(0LL)
>+ | ---
>+ | - [0]
>+ | ...
>+s:get(-1LL)
>+ | ---
>+ | - [-1]
>+ | ...
>+s:get(9007199254740992LL)
>+ | ---
>+ | - [9007199254740992]
>+ | ...
>+s:get(-9007199254740994LL)
>+ | ---
>+ | - [-9007199254740994]
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-3907.test.lua b/test/box/hash_gh-3907.test.lua
>new file mode 100644
>index 000000000..2bef03b0d
>--- /dev/null
>+++ b/test/box/hash_gh-3907.test.lua
>@@ -0,0 +1,15 @@
>+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>+-- are hashed as MP_INT/MP_UINT.
>+
>+ffi = require('ffi')
>+s = box.schema.space.create('test')
>+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>+s:insert{ffi.new('double', 0)}
>+s:insert{ffi.new('double', -1)}
>+s:insert{ffi.new('double', 9007199254740992)}
>+s:insert{ffi.new('double', -9007199254740994)}
>+s:get(0LL)
>+s:get(-1LL)
>+s:get(9007199254740992LL)
>+s:get(-9007199254740994LL)
>+s:drop()
>diff --git a/test/box/hash_gh-616.result b/test/box/hash_gh-616.result
>new file mode 100644
>index 000000000..d5ee1eed9
>--- /dev/null
>+++ b/test/box/hash_gh-616.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+--
>+-- gh-616 "1-based indexing and 0-based error message
>+--
>+_ = box.schema.create_space('test')
>+ | ---
>+ | ...
>+_ = box.space.test:create_index('i',{parts={1,'string'}})
>+ | ---
>+ | ...
>+box.space.test:insert{1}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected string'
>+ | ...
>+box.space.test:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-616.test.lua b/test/box/hash_gh-616.test.lua
>new file mode 100644
>index 000000000..8ea5f725a
>--- /dev/null
>+++ b/test/box/hash_gh-616.test.lua
>@@ -0,0 +1,7 @@
>+--
>+-- gh-616 "1-based indexing and 0-based error message
>+--
>+_ = box.schema.create_space('test')
>+_ = box.space.test:create_index('i',{parts={1,'string'}})
>+box.space.test:insert{1}
>+box.space.test:drop()
>diff --git a/test/box/hash_iterate.result b/test/box/hash_iterate.result
>new file mode 100644
>index 000000000..64660ad6d
>--- /dev/null
>+++ b/test/box/hash_iterate.result
>@@ -0,0 +1,21 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+hash:insert{0}
>+ | ---
>+ | - [0]
>+ | ...
>+hash:insert{16}
>+ | ---
>+ | - [16]
>+ | ...
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+ | ---
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_iterate.test.lua b/test/box/hash_iterate.test.lua
>new file mode 100644
>index 000000000..1ee758a66
>--- /dev/null
>+++ b/test/box/hash_iterate.test.lua
>@@ -0,0 +1,6 @@
>+hash = box.schema.space.create('tweedledum')
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+hash:insert{0}
>+hash:insert{16}
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+hash:drop()
>diff --git a/test/box/hash_multipart.result b/test/box/hash_multipart.result
>index 3de8ee3be..e94313b62 100644
>--- a/test/box/hash_multipart.result
>+++ b/test/box/hash_multipart.result
>@@ -131,13 +131,6 @@ hash.index['unique']:select{1, 'baz'}
> - error: 'Supplied key type of part 1 does not match index part type: expected unsigned'
> ...
> -- cleanup
>-hash:truncate()
>----
>-...
>-hash:len()
>----
>-- 0
>-...
> hash:drop()
> ---
> ...
>diff --git a/test/box/hash_multipart.test.lua b/test/box/hash_multipart.test.lua
>index 8b40504b1..c0a871bee 100644
>--- a/test/box/hash_multipart.test.lua
>+++ b/test/box/hash_multipart.test.lua
>@@ -53,6 +53,4 @@ hash.index['unique']:get{1}
> hash.index['unique']:select{1, 'baz'}
> 
> -- cleanup
>-hash:truncate()
>-hash:len()
> hash:drop()
>diff --git a/test/box/hash_not_a_multikey.result b/test/box/hash_not_a_multikey.result
>new file mode 100644
>index 000000000..334aa676d
>--- /dev/null
>+++ b/test/box/hash_not_a_multikey.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+-- Hash index cannot be multikey.
>+
>+s = box.schema.space.create('test')
>+ | ---
>+ | ...
>+_ = s:create_index('primary')
>+ | ---
>+ | ...
>+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>+ | ---
>+ | - error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
>+ | be multikey'
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_not_a_multikey.test.lua b/test/box/hash_not_a_multikey.test.lua
>new file mode 100644
>index 000000000..bd82dfb83
>--- /dev/null
>+++ b/test/box/hash_not_a_multikey.test.lua
>@@ -0,0 +1,6 @@
>+-- Hash index cannot be multikey.
>+
>+s = box.schema.space.create('test')
>+_ = s:create_index('primary')
>+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>+s:drop()
>diff --git a/test/box/hash_replace.result b/test/box/hash_replace.result
>new file mode 100644
>index 000000000..1b45f7914
>--- /dev/null
>+++ b/test/box/hash_replace.result
>@@ -0,0 +1,256 @@
>+-- test-run result file version 2
>+------------------------
>+-- hash::replace tests
>+------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+hash:insert{0, 0, 0, 0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+hash:insert{1, 1, 1, 1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash:insert{2, 2, 2, 2}
>+ | ---
>+ | - [2, 2, 2, 2]
>+ | ...
>+
>+-- OK
>+hash:replace{1, 1, 1, 1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field1']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field2']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field3']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+
>+-- OK
>+hash:insert{10, 10, 10, 10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash:delete{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+
>+-- TupleFound (primary key)
>+hash:insert{1, 10, 10, 10}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+
>+-- TupleNotFound (primary key)
>+hash:replace{10, 10, 10, 10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+
>+-- TupleFound (key --1)
>+hash:insert{10, 0, 10, 10}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --1)
>+-- hash:replace_if_exists(2, 0, 10, 10)
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --3)
>+hash:insert{10, 10, 10, 0}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --3)
>+-- hash:replace_if_exists(2, 10, 10, 0)
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+hash:insert{0}
>+ | ---
>+ | - [0]
>+ | ...
>+hash:insert{16}
>+ | ---
>+ | - [16]
>+ | ...
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+ | ---
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_replace.test.lua b/test/box/hash_replace.test.lua
>new file mode 100644
>index 000000000..d876f1f12
>--- /dev/null
>+++ b/test/box/hash_replace.test.lua
>@@ -0,0 +1,88 @@
>+------------------------
>+-- hash::replace tests
>+------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>+
>+hash:insert{0, 0, 0, 0}
>+hash:insert{1, 1, 1, 1}
>+hash:insert{2, 2, 2, 2}
>+
>+-- OK
>+hash:replace{1, 1, 1, 1}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['primary']:get{1}
>+hash.index['field1']:get{1}
>+hash.index['field2']:get{1}
>+hash.index['field3']:get{1}
>+
>+-- OK
>+hash:insert{10, 10, 10, 10}
>+hash:delete{10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+
>+-- TupleFound (primary key)
>+hash:insert{1, 10, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['primary']:get{1}
>+
>+-- TupleNotFound (primary key)
>+hash:replace{10, 10, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+
>+-- TupleFound (key --1)
>+hash:insert{10, 0, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field1']:get{0}
>+
>+-- TupleFound (key --1)
>+-- hash:replace_if_exists(2, 0, 10, 10)
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field1']:get{0}
>+
>+-- TupleFound (key --3)
>+hash:insert{10, 10, 10, 0}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field3']:get{0}
>+
>+-- TupleFound (key --3)
>+-- hash:replace_if_exists(2, 10, 10, 0)
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field3']:get{0}
>+
>+hash:drop()
>+
>+hash = box.schema.space.create('tweedledum')
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+hash:insert{0}
>+hash:insert{16}
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+hash:drop()
>diff --git a/test/box/hash_string_delete.result b/test/box/hash_string_delete.result
>new file mode 100644
>index 000000000..3458f3c68
>--- /dev/null
>+++ b/test/box/hash_string_delete.result
>@@ -0,0 +1,62 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{'key 0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 1'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 2'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 3'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 4'}
>+ | ---
>+ | ...
>+hash:delete{'key 5'}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'key 1', 'key 2'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_delete.test.lua b/test/box/hash_string_delete.test.lua
>new file mode 100644
>index 000000000..612217ec9
>--- /dev/null
>+++ b/test/box/hash_string_delete.test.lua
>@@ -0,0 +1,24 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{'key 0'}
>+hash:delete{'key 1'}
>+hash:delete{'key 2'}
>+hash:delete{'key 3'}
>+hash:delete{'key 4'}
>+hash:delete{'key 5'}
>+
>+-- delete by invalid keys
>+hash:delete{'key 1', 'key 2'}
>+hash:drop()
>diff --git a/test/box/hash_string_insert.result b/test/box/hash_string_insert.result
>new file mode 100644
>index 000000000..50a52b6a8
>--- /dev/null
>+++ b/test/box/hash_string_insert.result
>@@ -0,0 +1,32 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- String hash inset fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_insert.test.lua b/test/box/hash_string_insert.test.lua
>new file mode 100644
>index 000000000..9788abc0d
>--- /dev/null
>+++ b/test/box/hash_string_insert.test.lua
>@@ -0,0 +1,13 @@
>+-------------------------------------------------------------------------------
>+-- String hash inset fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_string_replace.result b/test/box/hash_string_replace.result
>new file mode 100644
>index 000000000..1fb525d71
>--- /dev/null
>+++ b/test/box/hash_string_replace.result
>@@ -0,0 +1,47 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - ['key 3', 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - ['key 1', 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - ['key 2', 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_replace.test.lua b/test/box/hash_string_replace.test.lua
>new file mode 100644
>index 000000000..db5cfa93e
>--- /dev/null
>+++ b/test/box/hash_string_replace.test.lua
>@@ -0,0 +1,19 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>+
>+hash:drop()
>diff --git a/test/box/hash_string_select.result b/test/box/hash_string_select.result
>new file mode 100644
>index 000000000..16cb22d3c
>--- /dev/null
>+++ b/test/box/hash_string_select.result
>@@ -0,0 +1,63 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{'key 0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 1'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 2'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 3'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 4'}
>+ | ---
>+ | ...
>+hash.index['primary']:get{'key 5'}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'key 1', 'key 2'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_select.test.lua b/test/box/hash_string_select.test.lua
>new file mode 100644
>index 000000000..ef3f10018
>--- /dev/null
>+++ b/test/box/hash_string_select.test.lua
>@@ -0,0 +1,25 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{'key 0'}
>+hash.index['primary']:get{'key 1'}
>+hash.index['primary']:get{'key 2'}
>+hash.index['primary']:get{'key 3'}
>+hash.index['primary']:get{'key 4'}
>+hash.index['primary']:get{'key 5'}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'key 1', 'key 2'}
>+
>+hash:drop()
>diff --git a/test/box/hash_with_function.result b/test/box/hash_with_function.result
>new file mode 100644
>index 000000000..cac268281
>--- /dev/null
>+++ b/test/box/hash_with_function.result
>@@ -0,0 +1,26 @@
>+-- test-run result file version 2
>+-- Hash index can not use function.
>+
>+s = box.schema.space.create('withdata')
>+ | ---
>+ | ...
>+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>+ | ---
>+ | ...
>+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>+ | ---
>+ | ...
>+_ = s:create_index('pk')
>+ | ---
>+ | ...
>+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>+ | ---
>+ | - error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
>+ | can not use a function'
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>+box.schema.func.drop('s')
>+ | ---
>+ | ...
>diff --git a/test/box/hash_with_function.test.lua b/test/box/hash_with_function.test.lua
>new file mode 100644
>index 000000000..9653de68e
>--- /dev/null
>+++ b/test/box/hash_with_function.test.lua
>@@ -0,0 +1,9 @@
>+-- Hash index can not use function.
>+
>+s = box.schema.space.create('withdata')
>+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>+_ = s:create_index('pk')
>+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>+s:drop()
>+box.schema.func.drop('s')
>--
>2.23.0
>
>
>--
>sergeyb@ 
 
 
--
Oleg Piskunov
 

[-- Attachment #2: Type: text/html, Size: 102286 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-19 10:24 [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests Sergey Bronnikov
  2020-03-19 11:09 ` Oleg Piskunov
@ 2020-03-19 14:22 ` Alexander Tikhonov
  2020-03-19 21:31 ` Konstantin Osipov
  2020-03-25  9:13 ` Kirill Yukhin
  3 siblings, 0 replies; 7+ messages in thread
From: Alexander Tikhonov @ 2020-03-19 14:22 UTC (permalink / raw)
  To: Sergey Bronnikov; +Cc: Oleg Piskunov, tarantool-patches

[-- Attachment #1: Type: text/plain, Size: 95086 bytes --]


Sergey, thanks for the patch, LGTM,



Отправлено из мобильной Почты Mail.ru


четверг, 19 марта 2020 г., 13:25 +0300 от Sergey Bronnikov  <sergeyb@tarantool.org>:
>Splitted single hash.test.lua to a set of small independent tests.
>
>GitHub branch:  https://github.com/tarantool/tarantool/tree/ligurio/hash_test_split
>
>---
> test/box/hash.result                  | 873 --------------------------
> test/box/hash.test.lua                | 364 -----------
> test/box/hash_32bit_delete.result     |  70 +++
> test/box/hash_32bit_delete.test.lua   |  29 +
> test/box/hash_32bit_insert.result     |  38 ++
> test/box/hash_32bit_insert.test.lua   |  16 +
> test/box/hash_32bit_replace.result    |  56 ++
> test/box/hash_32bit_replace.test.lua  |  25 +
> test/box/hash_32bit_select.result     |  70 +++
> test/box/hash_32bit_select.test.lua   |  29 +
> test/box/hash_64bit_delete.result     | 111 ++++
> test/box/hash_64bit_delete.test.lua   |  42 ++
> test/box/hash_64bit_insert.result     |  54 ++
> test/box/hash_64bit_insert.test.lua   |  20 +
> test/box/hash_64bit_replace.result    |  68 ++
> test/box/hash_64bit_replace.test.lua  |  28 +
> test/box/hash_64bit_select.result     |  94 +++
> test/box/hash_64bit_select.test.lua   |  37 ++
> test/box/hash_collation.result        |  62 ++
> test/box/hash_collation.test.lua      |  22 +
> test/box/hash_gh-1467.result          |  17 +
> test/box/hash_gh-1467.test.lua        |   6 +
> test/box/hash_gh-3907.result          |  48 ++
> test/box/hash_gh-3907.test.lua        |  15 +
> test/box/hash_gh-616.result           |  17 +
> test/box/hash_gh-616.test.lua         |   7 +
> test/box/hash_iterate.result          |  21 +
> test/box/hash_iterate.test.lua        |   6 +
> test/box/hash_multipart.result        |   7 -
> test/box/hash_multipart.test.lua      |   2 -
> test/box/hash_not_a_multikey.result   |  17 +
> test/box/hash_not_a_multikey.test.lua |   6 +
> test/box/hash_replace.result          | 256 ++++++++
> test/box/hash_replace.test.lua        |  88 +++
> test/box/hash_string_delete.result    |  62 ++
> test/box/hash_string_delete.test.lua  |  24 +
> test/box/hash_string_insert.result    |  32 +
> test/box/hash_string_insert.test.lua  |  13 +
> test/box/hash_string_replace.result   |  47 ++
> test/box/hash_string_replace.test.lua |  19 +
> test/box/hash_string_select.result    |  63 ++
> test/box/hash_string_select.test.lua  |  25 +
> test/box/hash_with_function.result    |  26 +
> test/box/hash_with_function.test.lua  |   9 +
> 44 files changed, 1695 insertions(+), 1246 deletions(-)
> delete mode 100644 test/box/hash.result
> delete mode 100644 test/box/hash.test.lua
> create mode 100644 test/box/hash_32bit_delete.result
> create mode 100644 test/box/hash_32bit_delete.test.lua
> create mode 100644 test/box/hash_32bit_insert.result
> create mode 100644 test/box/hash_32bit_insert.test.lua
> create mode 100644 test/box/hash_32bit_replace.result
> create mode 100644 test/box/hash_32bit_replace.test.lua
> create mode 100644 test/box/hash_32bit_select.result
> create mode 100644 test/box/hash_32bit_select.test.lua
> create mode 100644 test/box/hash_64bit_delete.result
> create mode 100644 test/box/hash_64bit_delete.test.lua
> create mode 100644 test/box/hash_64bit_insert.result
> create mode 100644 test/box/hash_64bit_insert.test.lua
> create mode 100644 test/box/hash_64bit_replace.result
> create mode 100644 test/box/hash_64bit_replace.test.lua
> create mode 100644 test/box/hash_64bit_select.result
> create mode 100644 test/box/hash_64bit_select.test.lua
> create mode 100644 test/box/hash_collation.result
> create mode 100644 test/box/hash_collation.test.lua
> create mode 100644 test/box/hash_gh-1467.result
> create mode 100644 test/box/hash_gh-1467.test.lua
> create mode 100644 test/box/hash_gh-3907.result
> create mode 100644 test/box/hash_gh-3907.test.lua
> create mode 100644 test/box/hash_gh-616.result
> create mode 100644 test/box/hash_gh-616.test.lua
> create mode 100644 test/box/hash_iterate.result
> create mode 100644 test/box/hash_iterate.test.lua
> create mode 100644 test/box/hash_not_a_multikey.result
> create mode 100644 test/box/hash_not_a_multikey.test.lua
> create mode 100644 test/box/hash_replace.result
> create mode 100644 test/box/hash_replace.test.lua
> create mode 100644 test/box/hash_string_delete.result
> create mode 100644 test/box/hash_string_delete.test.lua
> create mode 100644 test/box/hash_string_insert.result
> create mode 100644 test/box/hash_string_insert.test.lua
> create mode 100644 test/box/hash_string_replace.result
> create mode 100644 test/box/hash_string_replace.test.lua
> create mode 100644 test/box/hash_string_select.result
> create mode 100644 test/box/hash_string_select.test.lua
> create mode 100644 test/box/hash_with_function.result
> create mode 100644 test/box/hash_with_function.test.lua
>
>diff --git a/test/box/hash.result b/test/box/hash.result
>deleted file mode 100644
>index 5e1441ecc..000000000
>--- a/test/box/hash.result
>+++ /dev/null
>@@ -1,873 +0,0 @@
>---=============================================================================
>--- 32-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 32-bit hash insert fields tests
>--------------------------------------------------------------------------------
>-hash = box.schema.space.create('tweedledum')
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-bsize = tmp:bsize()
>----
>-...
>--- Insert valid fields
>-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>-tmp:bsize() > bsize
>----
>-- true
>-...
>--- Insert invalid fields
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>--- Replace invalid fields
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4}
>----
>-...
>-hash.index['primary']:get{5}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash.index['primary']:get{1, 2}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- 32-bit hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{4}
>----
>-...
>-hash:delete{5}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash:delete{1, 2}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>---=============================================================================
>--- 64-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 64-bit hash inset fields tests
>--------------------------------------------------------------------------------
>--- Insert valid fields
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>--- Insert invalid fields
>-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [100, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [101, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [102, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [103, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>--- Replace invalid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{0ULL}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1ULL}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2ULL}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3ULL}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4ULL}
>----
>-...
>-hash.index['primary']:get{5ULL}
>----
>-...
>--- select by valid NUM keys
>-hash.index['primary']:get{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{2}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{3}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{4}
>----
>-...
>-hash.index['primary']:get{5}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash.index['primary']:get{'00000001', '00000002'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- 64-bit hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{0ULL}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1ULL}
>----
>-- [1, 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{2ULL}
>----
>-- [2, 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{3ULL}
>----
>-- [3, 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{4ULL}
>----
>-...
>-hash:delete{5ULL}
>----
>-...
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>--- delete by valid NUM keys
>-hash:delete{0}
>----
>-- [0, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{1}
>----
>-- [1, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{2}
>----
>-- [2, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{3}
>----
>-- [3, 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{4}
>----
>-...
>-hash:delete{5}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>----
>-- error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>-...
>-hash:delete{'00000001', '00000002'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>---=============================================================================
>--- String hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- String hash inset fields tests
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>----
>-...
>--- Insert valid fields
>-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 1', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 2', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>----
>-- ['key 3', 'value1 v1.0', 'value2 v1.0']
>-...
>--------------------------------------------------------------------------------
>--- String hash replace fields tests
>--------------------------------------------------------------------------------
>--- Replace valid fields
>-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>--------------------------------------------------------------------------------
>--- String hash select fields test
>--------------------------------------------------------------------------------
>--- select by valid keys
>-hash.index['primary']:get{'key 0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash.index['primary']:get{'key 1'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash.index['primary']:get{'key 2'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>-hash.index['primary']:get{'key 3'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash.index['primary']:get{'key 4'}
>----
>-...
>-hash.index['primary']:get{'key 5'}
>----
>-...
>--- select by invalid keys
>-hash.index['primary']:get{'key 1', 'key 2'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>--------------------------------------------------------------------------------
>--- String hash delete fields test
>--------------------------------------------------------------------------------
>--- delete by valid keys
>-hash:delete{'key 0'}
>----
>-- ['key 0', 'value1 v1.0', 'value2 v1.0']
>-...
>-hash:delete{'key 1'}
>----
>-- ['key 1', 'value1 v1.32', 'value2 1.72']
>-...
>-hash:delete{'key 2'}
>----
>-- ['key 2', 'value1 v1.43', 'value2 1.92']
>-...
>-hash:delete{'key 3'}
>----
>-- ['key 3', 'value1 v1.31', 'value2 1.12']
>-...
>-hash:delete{'key 4'}
>----
>-...
>-hash:delete{'key 5'}
>----
>-...
>--- delete by invalid keys
>-hash:delete{'key 1', 'key 2'}
>----
>-- error: Invalid key part count in an exact match (expected 1, got 2)
>-...
>-hash:truncate()
>----
>-...
>--------------------------------------------------------------------------------
>--- Collation test
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>----
>-...
>-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>----
>-...
>-hash:insert{'Ёж', 'Hedgehog'}
>----
>-- ['Ёж', 'Hedgehog']
>-...
>-hash:insert{'Ёлка', 'Spruce'}
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash:insert{'Jogurt', 'Йогурт'}
>----
>-- ['Jogurt', 'Йогурт']
>-...
>-hash:insert{'Один', 1}
>----
>-- ['Один', 1]
>-...
>-hash.index.primary:get('ёж')
>----
>-- ['Ёж', 'Hedgehog']
>-...
>-hash.index.primary:get('елка')
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash.index.secondary:get('spruce')
>----
>-- ['Ёлка', 'Spruce']
>-...
>-hash.index.secondary:get('йогурт')
>----
>-- ['Jogurt', 'Йогурт']
>-...
>-hash.index.secondary:get(1)
>----
>-- ['Один', 1]
>-...
>-hash.index.secondary:get('иогурт')
>----
>-...
>-hash.index.secondary:get(2)
>----
>-...
>-------------------------
>--- hash::replace tests
>-------------------------
>-hash.index['secondary']:drop()
>----
>-...
>-hash.index['primary']:drop()
>----
>-...
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>----
>-...
>-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>----
>-...
>-hash:insert{0, 0, 0, 0}
>----
>-- [0, 0, 0, 0]
>-...
>-hash:insert{1, 1, 1, 1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash:insert{2, 2, 2, 2}
>----
>-- [2, 2, 2, 2]
>-...
>--- OK
>-hash:replace{1, 1, 1, 1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field1']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field2']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>-hash.index['field3']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>--- OK
>-hash:insert{10, 10, 10, 10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash:delete{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>--- TupleFound (primary key)
>-hash:insert{1, 10, 10, 10}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-...
>-hash.index['field1']:get{10}
>----
>-...
>-hash.index['field2']:get{10}
>----
>-...
>-hash.index['field3']:get{10}
>----
>-...
>-hash.index['primary']:get{1}
>----
>-- [1, 1, 1, 1]
>-...
>--- TupleNotFound (primary key)
>-hash:replace{10, 10, 10, 10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>--- TupleFound (key --1)
>-hash:insert{10, 0, 10, 10}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --1)
>--- hash:replace_if_exists(2, 0, 10, 10)
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --3)
>-hash:insert{10, 10, 10, 0}
>----
>-- error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>-...
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>--- TupleFound (key --3)
>--- hash:replace_if_exists(2, 10, 10, 0)
>-hash.index['primary']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field1']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field2']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{10}
>----
>-- [10, 10, 10, 10]
>-...
>-hash.index['field3']:get{0}
>----
>-- [0, 0, 0, 0]
>-...
>-hash:drop()
>----
>-...
>-hash = box.schema.space.create('tweedledum')
>----
>-...
>-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>----
>-...
>-hash:insert{0}
>----
>-- [0]
>-...
>-hash:insert{16}
>----
>-- [16]
>-...
>-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>----
>-...
>-hash:drop()
>----
>-...
>--- 
>--- gh-616 "1-based indexing and 0-based error message
>---
>-_ = box.schema.create_space('test')
>----
>-...
>-_ = box.space.test:create_index('i',{parts={1,'string'}})
>----
>-...
>-box.space.test:insert{1}
>----
>-- error: 'Tuple field 1 type does not match one required by operation: expected string'
>-...
>-box.space.test:drop()
>----
>-...
>--- gh-1467: invalid iterator type
>-space = box.schema.space.create('test')
>----
>-...
>-index = space:create_index('primary', { type = 'hash' })
>----
>-...
>-space:select({1}, {iterator = 'BITS_ALL_SET' } )
>----
>-- error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
>-    iterator type
>-...
>-space:drop()
>----
>-...
>--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>--- are hashed as MP_INT/MP_UINT.
>-ffi = require('ffi')
>----
>-...
>-s = box.schema.space.create('test')
>----
>-...
>-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>----
>-...
>-s:insert{ffi.new('double', 0)}
>----
>-- [0]
>-...
>-s:insert{ffi.new('double', -1)}
>----
>-- [-1]
>-...
>-s:insert{ffi.new('double', 9007199254740992)}
>----
>-- [9007199254740992]
>-...
>-s:insert{ffi.new('double', -9007199254740994)}
>----
>-- [-9007199254740994]
>-...
>-s:get(0LL)
>----
>-- [0]
>-...
>-s:get(-1LL)
>----
>-- [-1]
>-...
>-s:get(9007199254740992LL)
>----
>-- [9007199254740992]
>-...
>-s:get(-9007199254740994LL)
>----
>-- [-9007199254740994]
>-...
>-s:drop()
>----
>-...
>--- Hash index cannot be multikey.
>-s = box.schema.space.create('test')
>----
>-...
>-_ = s:create_index('primary')
>----
>-...
>-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>----
>-- error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
>-    be multikey'
>-...
>-s:drop()
>----
>-...
>--- Hash index can not use function.
>-s = box.schema.space.create('withdata')
>----
>-...
>-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>----
>-...
>-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>----
>-...
>-_ = s:create_index('pk')
>----
>-...
>-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>----
>-- error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
>-    can not use a function'
>-...
>-s:drop()
>----
>-...
>-box.schema.func.drop('s')
>----
>-...
>diff --git a/test/box/hash.test.lua b/test/box/hash.test.lua
>deleted file mode 100644
>index 78c831f77..000000000
>--- a/test/box/hash.test.lua
>+++ /dev/null
>@@ -1,364 +0,0 @@
>---=============================================================================
>--- 32-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 32-bit hash insert fields tests
>--------------------------------------------------------------------------------
>-hash = box.schema.space.create('tweedledum')
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-
>-bsize = tmp:bsize()
>-
>--- Insert valid fields
>-hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>-
>-tmp:bsize() > bsize
>-
>--- Insert invalid fields
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>-
>--- Replace invalid fields
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{0}
>-hash.index['primary']:get{1}
>-hash.index['primary']:get{2}
>-hash.index['primary']:get{3}
>-hash.index['primary']:get{4}
>-hash.index['primary']:get{5}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>-hash.index['primary']:get{1, 2}
>-
>--------------------------------------------------------------------------------
>--- 32-bit hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{0}
>-hash:delete{1}
>-hash:delete{2}
>-hash:delete{3}
>-hash:delete{4}
>-hash:delete{5}
>-
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>-hash:delete{1, 2}
>-
>-hash:truncate()
>-
>---=============================================================================
>--- 64-bit hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- 64-bit hash inset fields tests
>--------------------------------------------------------------------------------
>-
>--- Insert valid fields
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>-
>--- Insert invalid fields
>-hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>-
>--- Replace invalid fields
>-hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>-hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>-hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>-hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{0ULL}
>-hash.index['primary']:get{1ULL}
>-hash.index['primary']:get{2ULL}
>-hash.index['primary']:get{3ULL}
>-hash.index['primary']:get{4ULL}
>-hash.index['primary']:get{5ULL}
>-
>--- select by valid NUM keys
>-hash.index['primary']:get{0}
>-hash.index['primary']:get{1}
>-hash.index['primary']:get{2}
>-hash.index['primary']:get{3}
>-hash.index['primary']:get{4}
>-hash.index['primary']:get{5}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'invalid key'}
>-hash.index['primary']:get{'00000001', '00000002'}
>-
>--------------------------------------------------------------------------------
>--- 64-bit hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{0ULL}
>-hash:delete{1ULL}
>-hash:delete{2ULL}
>-hash:delete{3ULL}
>-hash:delete{4ULL}
>-hash:delete{5ULL}
>-
>-hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>-
>--- delete by valid NUM keys
>-hash:delete{0}
>-hash:delete{1}
>-hash:delete{2}
>-hash:delete{3}
>-hash:delete{4}
>-hash:delete{5}
>-
>--- delete by invalid keys
>-hash:delete{'invalid key'}
>-hash:delete{'00000001', '00000002'}
>-hash:truncate()
>-
>---=============================================================================
>--- String hash tests
>---=============================================================================
>--------------------------------------------------------------------------------
>--- String hash inset fields tests
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>-
>--- Insert valid fields
>-hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>-hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>-
>--------------------------------------------------------------------------------
>--- String hash replace fields tests
>--------------------------------------------------------------------------------
>-
>--- Replace valid fields
>-hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>-hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>-hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>-
>--------------------------------------------------------------------------------
>--- String hash select fields test
>--------------------------------------------------------------------------------
>-
>--- select by valid keys
>-hash.index['primary']:get{'key 0'}
>-hash.index['primary']:get{'key 1'}
>-hash.index['primary']:get{'key 2'}
>-hash.index['primary']:get{'key 3'}
>-hash.index['primary']:get{'key 4'}
>-hash.index['primary']:get{'key 5'}
>-
>--- select by invalid keys
>-hash.index['primary']:get{'key 1', 'key 2'}
>-
>--------------------------------------------------------------------------------
>--- String hash delete fields test
>--------------------------------------------------------------------------------
>-
>--- delete by valid keys
>-hash:delete{'key 0'}
>-hash:delete{'key 1'}
>-hash:delete{'key 2'}
>-hash:delete{'key 3'}
>-hash:delete{'key 4'}
>-hash:delete{'key 5'}
>-
>--- delete by invalid keys
>-hash:delete{'key 1', 'key 2'}
>-hash:truncate()
>-
>--------------------------------------------------------------------------------
>--- Collation test
>--------------------------------------------------------------------------------
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>-tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>-
>-hash:insert{'Ёж', 'Hedgehog'}
>-hash:insert{'Ёлка', 'Spruce'}
>-hash:insert{'Jogurt', 'Йогурт'}
>-hash:insert{'Один', 1}
>-
>-hash.index.primary:get('ёж')
>-hash.index.primary:get('елка')
>-hash.index.secondary:get('spruce')
>-hash.index.secondary:get('йогурт')
>-hash.index.secondary:get(1)
>-hash.index.secondary:get('иогурт')
>-hash.index.secondary:get(2)
>-
>-------------------------
>--- hash::replace tests
>-------------------------
>-hash.index['secondary']:drop()
>-hash.index['primary']:drop()
>-tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>-tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>-
>-hash:insert{0, 0, 0, 0}
>-hash:insert{1, 1, 1, 1}
>-hash:insert{2, 2, 2, 2}
>-
>--- OK
>-hash:replace{1, 1, 1, 1}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['primary']:get{1}
>-hash.index['field1']:get{1}
>-hash.index['field2']:get{1}
>-hash.index['field3']:get{1}
>-
>--- OK
>-hash:insert{10, 10, 10, 10}
>-hash:delete{10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-
>--- TupleFound (primary key)
>-hash:insert{1, 10, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['primary']:get{1}
>-
>--- TupleNotFound (primary key)
>-hash:replace{10, 10, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-
>--- TupleFound (key --1)
>-hash:insert{10, 0, 10, 10}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field1']:get{0}
>-
>--- TupleFound (key --1)
>--- hash:replace_if_exists(2, 0, 10, 10)
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field1']:get{0}
>-
>--- TupleFound (key --3)
>-hash:insert{10, 10, 10, 0}
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field3']:get{0}
>-
>--- TupleFound (key --3)
>--- hash:replace_if_exists(2, 10, 10, 0)
>-hash.index['primary']:get{10}
>-hash.index['field1']:get{10}
>-hash.index['field2']:get{10}
>-hash.index['field3']:get{10}
>-hash.index['field3']:get{0}
>-
>-hash:drop()
>-
>-hash = box.schema.space.create('tweedledum')
>-hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>-hash:insert{0}
>-hash:insert{16}
>-for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>-hash:drop()
>-
>--- 
>--- gh-616 "1-based indexing and 0-based error message
>---
>-_ = box.schema.create_space('test')
>-_ = box.space.test:create_index('i',{parts={1,'string'}})
>-box.space.test:insert{1}
>-box.space.test:drop()
>-
>--- gh-1467: invalid iterator type
>-space = box.schema.space.create('test')
>-index = space:create_index('primary', { type = 'hash' })
>-space:select({1}, {iterator = 'BITS_ALL_SET' } )
>-space:drop()
>-
>--- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>--- are hashed as MP_INT/MP_UINT.
>-ffi = require('ffi')
>-s = box.schema.space.create('test')
>-_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>-s:insert{ffi.new('double', 0)}
>-s:insert{ffi.new('double', -1)}
>-s:insert{ffi.new('double', 9007199254740992)}
>-s:insert{ffi.new('double', -9007199254740994)}
>-s:get(0LL)
>-s:get(-1LL)
>-s:get(9007199254740992LL)
>-s:get(-9007199254740994LL)
>-s:drop()
>-
>--- Hash index cannot be multikey.
>-s = box.schema.space.create('test')
>-_ = s:create_index('primary')
>-_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>-s:drop()
>-
>--- Hash index can not use function.
>-s = box.schema.space.create('withdata')
>-lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>-box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>-_ = s:create_index('pk')
>-_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>-s:drop()
>-box.schema.func.drop('s')
>diff --git a/test/box/hash_32bit_delete.result b/test/box/hash_32bit_delete.result
>new file mode 100644
>index 000000000..b35143b10
>--- /dev/null
>+++ b/test/box/hash_32bit_delete.result
>@@ -0,0 +1,70 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4}
>+ | ---
>+ | ...
>+hash:delete{5}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash:delete{1, 2}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_delete.test.lua b/test/box/hash_32bit_delete.test.lua
>new file mode 100644
>index 000000000..682e0bc96
>--- /dev/null
>+++ b/test/box/hash_32bit_delete.test.lua
>@@ -0,0 +1,29 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0}
>+hash:delete{1}
>+hash:delete{2}
>+hash:delete{3}
>+hash:delete{4}
>+hash:delete{5}
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+hash:delete{1, 2}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_insert.result b/test/box/hash_32bit_insert.result
>new file mode 100644
>index 000000000..72c7c4842
>--- /dev/null
>+++ b/test/box/hash_32bit_insert.result
>@@ -0,0 +1,38 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- Insert invalid fields
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_insert.test.lua b/test/box/hash_32bit_insert.test.lua
>new file mode 100644
>index 000000000..308b27d3e
>--- /dev/null
>+++ b/test/box/hash_32bit_insert.test.lua
>@@ -0,0 +1,16 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- Insert invalid fields
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_replace.result b/test/box/hash_32bit_replace.result
>new file mode 100644
>index 000000000..a1feba851
>--- /dev/null
>+++ b/test/box/hash_32bit_replace.result
>@@ -0,0 +1,56 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+-- Replace invalid fields
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_replace.test.lua b/test/box/hash_32bit_replace.test.lua
>new file mode 100644
>index 000000000..a00b02185
>--- /dev/null
>+++ b/test/box/hash_32bit_replace.test.lua
>@@ -0,0 +1,25 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+
>+-- Replace invalid fields
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_32bit_select.result b/test/box/hash_32bit_select.result
>new file mode 100644
>index 000000000..f80df9bbd
>--- /dev/null
>+++ b/test/box/hash_32bit_select.result
>@@ -0,0 +1,70 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash.index['primary']:get{1, 2}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_32bit_select.test.lua b/test/box/hash_32bit_select.test.lua
>new file mode 100644
>index 000000000..e077cc48d
>--- /dev/null
>+++ b/test/box/hash_32bit_select.test.lua
>@@ -0,0 +1,29 @@
>+-------------------------------------------------------------------------------
>+-- 32-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 32-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0}
>+hash.index['primary']:get{1}
>+hash.index['primary']:get{2}
>+hash.index['primary']:get{3}
>+hash.index['primary']:get{4}
>+hash.index['primary']:get{5}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+hash.index['primary']:get{1, 2}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_delete.result b/test/box/hash_64bit_delete.result
>new file mode 100644
>index 000000000..88079e6f2
>--- /dev/null
>+++ b/test/box/hash_64bit_delete.result
>@@ -0,0 +1,111 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0ULL}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1ULL}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2ULL}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3ULL}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4ULL}
>+ | ---
>+ | ...
>+hash:delete{5ULL}
>+ | ---
>+ | ...
>+
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- delete by valid NUM keys
>+hash:delete{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{4}
>+ | ---
>+ | ...
>+hash:delete{5}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash:delete{'00000001', '00000002'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_delete.test.lua b/test/box/hash_64bit_delete.test.lua
>new file mode 100644
>index 000000000..75675381f
>--- /dev/null
>+++ b/test/box/hash_64bit_delete.test.lua
>@@ -0,0 +1,42 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{0ULL}
>+hash:delete{1ULL}
>+hash:delete{2ULL}
>+hash:delete{3ULL}
>+hash:delete{4ULL}
>+hash:delete{5ULL}
>+
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- delete by valid NUM keys
>+hash:delete{0}
>+hash:delete{1}
>+hash:delete{2}
>+hash:delete{3}
>+hash:delete{4}
>+hash:delete{5}
>+
>+-- delete by invalid keys
>+hash:delete{'invalid key'}
>+hash:delete{'00000001', '00000002'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_insert.result b/test/box/hash_64bit_insert.result
>new file mode 100644
>index 000000000..3f1275576
>--- /dev/null
>+++ b/test/box/hash_64bit_insert.result
>@@ -0,0 +1,54 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-- Insert invalid fields
>+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [100, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [101, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [102, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [103, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_insert.test.lua b/test/box/hash_64bit_insert.test.lua
>new file mode 100644
>index 000000000..c69214b4e
>--- /dev/null
>+++ b/test/box/hash_64bit_insert.test.lua
>@@ -0,0 +1,20 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-- Insert invalid fields
>+hash:insert{100, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{101, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{102, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{103, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_replace.result b/test/box/hash_64bit_replace.result
>new file mode 100644
>index 000000000..0bf900818
>--- /dev/null
>+++ b/test/box/hash_64bit_replace.result
>@@ -0,0 +1,68 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+-- Replace invalid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - [3, 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - [1, 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - [2, 'value1 v1.43', 'value2 1.92']
>+ | ...
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_replace.test.lua b/test/box/hash_64bit_replace.test.lua
>new file mode 100644
>index 000000000..4213110bc
>--- /dev/null
>+++ b/test/box/hash_64bit_replace.test.lua
>@@ -0,0 +1,28 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{3ULL, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1ULL, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2ULL, 'value1 v1.43', 'value2 1.92'}
>+
>+-- Replace invalid fields
>+hash:replace{3, 'value1 v1.31', 'value2 1.12'}
>+hash:replace{1, 'value1 v1.32', 'value2 1.72'}
>+hash:replace{2, 'value1 v1.43', 'value2 1.92'}
>+hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_64bit_select.result b/test/box/hash_64bit_select.result
>new file mode 100644
>index 000000000..74dd56727
>--- /dev/null
>+++ b/test/box/hash_64bit_select.result
>@@ -0,0 +1,94 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0ULL}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1ULL}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2ULL}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3ULL}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4ULL}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5ULL}
>+ | ---
>+ | ...
>+
>+-- select by valid NUM keys
>+hash.index['primary']:get{0}
>+ | ---
>+ | - [0, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{2}
>+ | ---
>+ | - [2, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{3}
>+ | ---
>+ | - [3, 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{4}
>+ | ---
>+ | ...
>+hash.index['primary']:get{5}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+ | ---
>+ | - error: 'Supplied key type of part 0 does not match index part type: expected unsigned'
>+ | ...
>+hash.index['primary']:get{'00000001', '00000002'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_64bit_select.test.lua b/test/box/hash_64bit_select.test.lua
>new file mode 100644
>index 000000000..724fb24be
>--- /dev/null
>+++ b/test/box/hash_64bit_select.test.lua
>@@ -0,0 +1,37 @@
>+-------------------------------------------------------------------------------
>+-- 64-bit hash insert fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{0ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{1ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{2ULL, 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{3ULL, 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- 64-bit hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{0ULL}
>+hash.index['primary']:get{1ULL}
>+hash.index['primary']:get{2ULL}
>+hash.index['primary']:get{3ULL}
>+hash.index['primary']:get{4ULL}
>+hash.index['primary']:get{5ULL}
>+
>+-- select by valid NUM keys
>+hash.index['primary']:get{0}
>+hash.index['primary']:get{1}
>+hash.index['primary']:get{2}
>+hash.index['primary']:get{3}
>+hash.index['primary']:get{4}
>+hash.index['primary']:get{5}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'invalid key'}
>+hash.index['primary']:get{'00000001', '00000002'}
>+
>+hash:drop()
>diff --git a/test/box/hash_collation.result b/test/box/hash_collation.result
>new file mode 100644
>index 000000000..ea80b577d
>--- /dev/null
>+++ b/test/box/hash_collation.result
>@@ -0,0 +1,62 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- Collation test
>+-------------------------------------------------------------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>+ | ---
>+ | ...
>+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>+ | ---
>+ | ...
>+
>+hash:insert{'Ёж', 'Hedgehog'}
>+ | ---
>+ | - ['Ёж', 'Hedgehog']
>+ | ...
>+hash:insert{'Ёлка', 'Spruce'}
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash:insert{'Jogurt', 'Йогурт'}
>+ | ---
>+ | - ['Jogurt', 'Йогурт']
>+ | ...
>+hash:insert{'Один', 1}
>+ | ---
>+ | - ['Один', 1]
>+ | ...
>+
>+hash.index.primary:get('ёж')
>+ | ---
>+ | - ['Ёж', 'Hedgehog']
>+ | ...
>+hash.index.primary:get('елка')
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash.index.secondary:get('spruce')
>+ | ---
>+ | - ['Ёлка', 'Spruce']
>+ | ...
>+hash.index.secondary:get('йогурт')
>+ | ---
>+ | - ['Jogurt', 'Йогурт']
>+ | ...
>+hash.index.secondary:get(1)
>+ | ---
>+ | - ['Один', 1]
>+ | ...
>+hash.index.secondary:get('иогурт')
>+ | ---
>+ | ...
>+hash.index.secondary:get(2)
>+ | ---
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_collation.test.lua b/test/box/hash_collation.test.lua
>new file mode 100644
>index 000000000..f9bca79f6
>--- /dev/null
>+++ b/test/box/hash_collation.test.lua
>@@ -0,0 +1,22 @@
>+-------------------------------------------------------------------------------
>+-- Collation test
>+-------------------------------------------------------------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {{1, 'string', collation = 'unicode_ci'}}, unique = true})
>+tmp = hash:create_index('secondary', { type = 'hash', parts = {{2, 'scalar', collation = 'unicode_ci'}}, unique = true})
>+
>+hash:insert{'Ёж', 'Hedgehog'}
>+hash:insert{'Ёлка', 'Spruce'}
>+hash:insert{'Jogurt', 'Йогурт'}
>+hash:insert{'Один', 1}
>+
>+hash.index.primary:get('ёж')
>+hash.index.primary:get('елка')
>+hash.index.secondary:get('spruce')
>+hash.index.secondary:get('йогурт')
>+hash.index.secondary:get(1)
>+hash.index.secondary:get('иогурт')
>+hash.index.secondary:get(2)
>+
>+hash:drop()
>diff --git a/test/box/hash_gh-1467.result b/test/box/hash_gh-1467.result
>new file mode 100644
>index 000000000..a2c736a11
>--- /dev/null
>+++ b/test/box/hash_gh-1467.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+-- gh-1467: invalid iterator type
>+
>+space = box.schema.space.create('test')
>+ | ---
>+ | ...
>+index = space:create_index('primary', { type = 'hash' })
>+ | ---
>+ | ...
>+space:select({1}, {iterator = 'BITS_ALL_SET' } )
>+ | ---
>+ | - error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
>+ |     iterator type
>+ | ...
>+space:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-1467.test.lua b/test/box/hash_gh-1467.test.lua
>new file mode 100644
>index 000000000..d98c31734
>--- /dev/null
>+++ b/test/box/hash_gh-1467.test.lua
>@@ -0,0 +1,6 @@
>+-- gh-1467: invalid iterator type
>+
>+space = box.schema.space.create('test')
>+index = space:create_index('primary', { type = 'hash' })
>+space:select({1}, {iterator = 'BITS_ALL_SET' } )
>+space:drop()
>diff --git a/test/box/hash_gh-3907.result b/test/box/hash_gh-3907.result
>new file mode 100644
>index 000000000..4ce7e40f4
>--- /dev/null
>+++ b/test/box/hash_gh-3907.result
>@@ -0,0 +1,48 @@
>+-- test-run result file version 2
>+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>+-- are hashed as MP_INT/MP_UINT.
>+
>+ffi = require('ffi')
>+ | ---
>+ | ...
>+s = box.schema.space.create('test')
>+ | ---
>+ | ...
>+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>+ | ---
>+ | ...
>+s:insert{ffi.new('double', 0)}
>+ | ---
>+ | - [0]
>+ | ...
>+s:insert{ffi.new('double', -1)}
>+ | ---
>+ | - [-1]
>+ | ...
>+s:insert{ffi.new('double', 9007199254740992)}
>+ | ---
>+ | - [9007199254740992]
>+ | ...
>+s:insert{ffi.new('double', -9007199254740994)}
>+ | ---
>+ | - [-9007199254740994]
>+ | ...
>+s:get(0LL)
>+ | ---
>+ | - [0]
>+ | ...
>+s:get(-1LL)
>+ | ---
>+ | - [-1]
>+ | ...
>+s:get(9007199254740992LL)
>+ | ---
>+ | - [9007199254740992]
>+ | ...
>+s:get(-9007199254740994LL)
>+ | ---
>+ | - [-9007199254740994]
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-3907.test.lua b/test/box/hash_gh-3907.test.lua
>new file mode 100644
>index 000000000..2bef03b0d
>--- /dev/null
>+++ b/test/box/hash_gh-3907.test.lua
>@@ -0,0 +1,15 @@
>+-- gh-3907: check that integer numbers stored as MP_FLOAT/MP_DOUBLE
>+-- are hashed as MP_INT/MP_UINT.
>+
>+ffi = require('ffi')
>+s = box.schema.space.create('test')
>+_ = s:create_index('primary', {type = 'hash', parts = {1, 'number'}})
>+s:insert{ffi.new('double', 0)}
>+s:insert{ffi.new('double', -1)}
>+s:insert{ffi.new('double', 9007199254740992)}
>+s:insert{ffi.new('double', -9007199254740994)}
>+s:get(0LL)
>+s:get(-1LL)
>+s:get(9007199254740992LL)
>+s:get(-9007199254740994LL)
>+s:drop()
>diff --git a/test/box/hash_gh-616.result b/test/box/hash_gh-616.result
>new file mode 100644
>index 000000000..d5ee1eed9
>--- /dev/null
>+++ b/test/box/hash_gh-616.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+-- 
>+-- gh-616 "1-based indexing and 0-based error message
>+--
>+_ = box.schema.create_space('test')
>+ | ---
>+ | ...
>+_ = box.space.test:create_index('i',{parts={1,'string'}})
>+ | ---
>+ | ...
>+box.space.test:insert{1}
>+ | ---
>+ | - error: 'Tuple field 1 type does not match one required by operation: expected string'
>+ | ...
>+box.space.test:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_gh-616.test.lua b/test/box/hash_gh-616.test.lua
>new file mode 100644
>index 000000000..8ea5f725a
>--- /dev/null
>+++ b/test/box/hash_gh-616.test.lua
>@@ -0,0 +1,7 @@
>+-- 
>+-- gh-616 "1-based indexing and 0-based error message
>+--
>+_ = box.schema.create_space('test')
>+_ = box.space.test:create_index('i',{parts={1,'string'}})
>+box.space.test:insert{1}
>+box.space.test:drop()
>diff --git a/test/box/hash_iterate.result b/test/box/hash_iterate.result
>new file mode 100644
>index 000000000..64660ad6d
>--- /dev/null
>+++ b/test/box/hash_iterate.result
>@@ -0,0 +1,21 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+hash:insert{0}
>+ | ---
>+ | - [0]
>+ | ...
>+hash:insert{16}
>+ | ---
>+ | - [16]
>+ | ...
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+ | ---
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_iterate.test.lua b/test/box/hash_iterate.test.lua
>new file mode 100644
>index 000000000..1ee758a66
>--- /dev/null
>+++ b/test/box/hash_iterate.test.lua
>@@ -0,0 +1,6 @@
>+hash = box.schema.space.create('tweedledum')
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+hash:insert{0}
>+hash:insert{16}
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+hash:drop()
>diff --git a/test/box/hash_multipart.result b/test/box/hash_multipart.result
>index 3de8ee3be..e94313b62 100644
>--- a/test/box/hash_multipart.result
>+++ b/test/box/hash_multipart.result
>@@ -131,13 +131,6 @@ hash.index['unique']:select{1, 'baz'}
> - error: 'Supplied key type of part 1 does not match index part type: expected unsigned'
> ...
> -- cleanup
>-hash:truncate()
>----
>-...
>-hash:len()
>----
>-- 0
>-...
> hash:drop()
> ---
> ...
>diff --git a/test/box/hash_multipart.test.lua b/test/box/hash_multipart.test.lua
>index 8b40504b1..c0a871bee 100644
>--- a/test/box/hash_multipart.test.lua
>+++ b/test/box/hash_multipart.test.lua
>@@ -53,6 +53,4 @@ hash.index['unique']:get{1}
> hash.index['unique']:select{1, 'baz'}
> 
> -- cleanup
>-hash:truncate()
>-hash:len()
> hash:drop()
>diff --git a/test/box/hash_not_a_multikey.result b/test/box/hash_not_a_multikey.result
>new file mode 100644
>index 000000000..334aa676d
>--- /dev/null
>+++ b/test/box/hash_not_a_multikey.result
>@@ -0,0 +1,17 @@
>+-- test-run result file version 2
>+-- Hash index cannot be multikey.
>+
>+s = box.schema.space.create('test')
>+ | ---
>+ | ...
>+_ = s:create_index('primary')
>+ | ---
>+ | ...
>+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>+ | ---
>+ | - error: 'Can''t create or modify index ''hash'' in space ''test'': HASH index cannot
>+ |     be multikey'
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_not_a_multikey.test.lua b/test/box/hash_not_a_multikey.test.lua
>new file mode 100644
>index 000000000..bd82dfb83
>--- /dev/null
>+++ b/test/box/hash_not_a_multikey.test.lua
>@@ -0,0 +1,6 @@
>+-- Hash index cannot be multikey.
>+
>+s = box.schema.space.create('test')
>+_ = s:create_index('primary')
>+_ = s:create_index('hash', {type = 'hash', parts = {{'[2][*]', 'unsigned'}}})
>+s:drop()
>diff --git a/test/box/hash_replace.result b/test/box/hash_replace.result
>new file mode 100644
>index 000000000..1b45f7914
>--- /dev/null
>+++ b/test/box/hash_replace.result
>@@ -0,0 +1,256 @@
>+-- test-run result file version 2
>+------------------------
>+-- hash::replace tests
>+------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+
>+hash:insert{0, 0, 0, 0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+hash:insert{1, 1, 1, 1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash:insert{2, 2, 2, 2}
>+ | ---
>+ | - [2, 2, 2, 2]
>+ | ...
>+
>+-- OK
>+hash:replace{1, 1, 1, 1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field1']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field2']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+hash.index['field3']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+
>+-- OK
>+hash:insert{10, 10, 10, 10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash:delete{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+
>+-- TupleFound (primary key)
>+hash:insert{1, 10, 10, 10}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | ...
>+hash.index['primary']:get{1}
>+ | ---
>+ | - [1, 1, 1, 1]
>+ | ...
>+
>+-- TupleNotFound (primary key)
>+hash:replace{10, 10, 10, 10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+
>+-- TupleFound (key --1)
>+hash:insert{10, 0, 10, 10}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --1)
>+-- hash:replace_if_exists(2, 0, 10, 10)
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --3)
>+hash:insert{10, 10, 10, 0}
>+ | ---
>+ | - error: Duplicate key exists in unique index 'primary' in space 'tweedledum'
>+ | ...
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+-- TupleFound (key --3)
>+-- hash:replace_if_exists(2, 10, 10, 0)
>+hash.index['primary']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field1']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field2']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{10}
>+ | ---
>+ | - [10, 10, 10, 10]
>+ | ...
>+hash.index['field3']:get{0}
>+ | ---
>+ | - [0, 0, 0, 0]
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>+
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+ | ---
>+ | ...
>+hash:insert{0}
>+ | ---
>+ | - [0]
>+ | ...
>+hash:insert{16}
>+ | ---
>+ | - [16]
>+ | ...
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+ | ---
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_replace.test.lua b/test/box/hash_replace.test.lua
>new file mode 100644
>index 000000000..d876f1f12
>--- /dev/null
>+++ b/test/box/hash_replace.test.lua
>@@ -0,0 +1,88 @@
>+------------------------
>+-- hash::replace tests
>+------------------------
>+
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field1', { type = 'hash', parts = {2, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field2', { type = 'hash', parts = {3, 'unsigned'}, unique = true })
>+tmp = hash:create_index('field3', { type = 'hash', parts = {4, 'unsigned'}, unique = true })
>+
>+hash:insert{0, 0, 0, 0}
>+hash:insert{1, 1, 1, 1}
>+hash:insert{2, 2, 2, 2}
>+
>+-- OK
>+hash:replace{1, 1, 1, 1}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['primary']:get{1}
>+hash.index['field1']:get{1}
>+hash.index['field2']:get{1}
>+hash.index['field3']:get{1}
>+
>+-- OK
>+hash:insert{10, 10, 10, 10}
>+hash:delete{10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+
>+-- TupleFound (primary key)
>+hash:insert{1, 10, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['primary']:get{1}
>+
>+-- TupleNotFound (primary key)
>+hash:replace{10, 10, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+
>+-- TupleFound (key --1)
>+hash:insert{10, 0, 10, 10}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field1']:get{0}
>+
>+-- TupleFound (key --1)
>+-- hash:replace_if_exists(2, 0, 10, 10)
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field1']:get{0}
>+
>+-- TupleFound (key --3)
>+hash:insert{10, 10, 10, 0}
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field3']:get{0}
>+
>+-- TupleFound (key --3)
>+-- hash:replace_if_exists(2, 10, 10, 0)
>+hash.index['primary']:get{10}
>+hash.index['field1']:get{10}
>+hash.index['field2']:get{10}
>+hash.index['field3']:get{10}
>+hash.index['field3']:get{0}
>+
>+hash:drop()
>+
>+hash = box.schema.space.create('tweedledum')
>+hi = hash:create_index('primary', { type = 'hash', parts = {1, 'unsigned'}, unique = true })
>+hash:insert{0}
>+hash:insert{16}
>+for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end
>+hash:drop()
>diff --git a/test/box/hash_string_delete.result b/test/box/hash_string_delete.result
>new file mode 100644
>index 000000000..3458f3c68
>--- /dev/null
>+++ b/test/box/hash_string_delete.result
>@@ -0,0 +1,62 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{'key 0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 1'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 2'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 3'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:delete{'key 4'}
>+ | ---
>+ | ...
>+hash:delete{'key 5'}
>+ | ---
>+ | ...
>+
>+-- delete by invalid keys
>+hash:delete{'key 1', 'key 2'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_delete.test.lua b/test/box/hash_string_delete.test.lua
>new file mode 100644
>index 000000000..612217ec9
>--- /dev/null
>+++ b/test/box/hash_string_delete.test.lua
>@@ -0,0 +1,24 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash delete fields test
>+-------------------------------------------------------------------------------
>+
>+-- delete by valid keys
>+hash:delete{'key 0'}
>+hash:delete{'key 1'}
>+hash:delete{'key 2'}
>+hash:delete{'key 3'}
>+hash:delete{'key 4'}
>+hash:delete{'key 5'}
>+
>+-- delete by invalid keys
>+hash:delete{'key 1', 'key 2'}
>+hash:drop()
>diff --git a/test/box/hash_string_insert.result b/test/box/hash_string_insert.result
>new file mode 100644
>index 000000000..50a52b6a8
>--- /dev/null
>+++ b/test/box/hash_string_insert.result
>@@ -0,0 +1,32 @@
>+-- test-run result file version 2
>+-------------------------------------------------------------------------------
>+-- String hash inset fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_insert.test.lua b/test/box/hash_string_insert.test.lua
>new file mode 100644
>index 000000000..9788abc0d
>--- /dev/null
>+++ b/test/box/hash_string_insert.test.lua
>@@ -0,0 +1,13 @@
>+-------------------------------------------------------------------------------
>+-- String hash inset fields tests
>+-------------------------------------------------------------------------------
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+hash:drop()
>diff --git a/test/box/hash_string_replace.result b/test/box/hash_string_replace.result
>new file mode 100644
>index 000000000..1fb525d71
>--- /dev/null
>+++ b/test/box/hash_string_replace.result
>@@ -0,0 +1,47 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>+ | ---
>+ | - ['key 3', 'value1 v1.31', 'value2 1.12']
>+ | ...
>+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>+ | ---
>+ | - ['key 1', 'value1 v1.32', 'value2 1.72']
>+ | ...
>+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>+ | ---
>+ | - ['key 2', 'value1 v1.43', 'value2 1.92']
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_replace.test.lua b/test/box/hash_string_replace.test.lua
>new file mode 100644
>index 000000000..db5cfa93e
>--- /dev/null
>+++ b/test/box/hash_string_replace.test.lua
>@@ -0,0 +1,19 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash replace fields tests
>+-------------------------------------------------------------------------------
>+
>+-- Replace valid fields
>+hash:replace{'key 3', 'value1 v1.31', 'value2 1.12'}
>+hash:replace{'key 1', 'value1 v1.32', 'value2 1.72'}
>+hash:replace{'key 2', 'value1 v1.43', 'value2 1.92'}
>+
>+hash:drop()
>diff --git a/test/box/hash_string_select.result b/test/box/hash_string_select.result
>new file mode 100644
>index 000000000..16cb22d3c
>--- /dev/null
>+++ b/test/box/hash_string_select.result
>@@ -0,0 +1,63 @@
>+-- test-run result file version 2
>+hash = box.schema.space.create('tweedledum')
>+ | ---
>+ | ...
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+ | ---
>+ | ...
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+
>+-------------------------------------------------------------------------------
>+-- String hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{'key 0'}
>+ | ---
>+ | - ['key 0', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 1'}
>+ | ---
>+ | - ['key 1', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 2'}
>+ | ---
>+ | - ['key 2', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 3'}
>+ | ---
>+ | - ['key 3', 'value1 v1.0', 'value2 v1.0']
>+ | ...
>+hash.index['primary']:get{'key 4'}
>+ | ---
>+ | ...
>+hash.index['primary']:get{'key 5'}
>+ | ---
>+ | ...
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'key 1', 'key 2'}
>+ | ---
>+ | - error: Invalid key part count in an exact match (expected 1, got 2)
>+ | ...
>+
>+hash:drop()
>+ | ---
>+ | ...
>diff --git a/test/box/hash_string_select.test.lua b/test/box/hash_string_select.test.lua
>new file mode 100644
>index 000000000..ef3f10018
>--- /dev/null
>+++ b/test/box/hash_string_select.test.lua
>@@ -0,0 +1,25 @@
>+hash = box.schema.space.create('tweedledum')
>+tmp = hash:create_index('primary', { type = 'hash', parts = {1, 'string'}, unique = true })
>+
>+-- Insert valid fields
>+hash:insert{'key 0', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 1', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 2', 'value1 v1.0', 'value2 v1.0'}
>+hash:insert{'key 3', 'value1 v1.0', 'value2 v1.0'}
>+
>+-------------------------------------------------------------------------------
>+-- String hash select fields test
>+-------------------------------------------------------------------------------
>+
>+-- select by valid keys
>+hash.index['primary']:get{'key 0'}
>+hash.index['primary']:get{'key 1'}
>+hash.index['primary']:get{'key 2'}
>+hash.index['primary']:get{'key 3'}
>+hash.index['primary']:get{'key 4'}
>+hash.index['primary']:get{'key 5'}
>+
>+-- select by invalid keys
>+hash.index['primary']:get{'key 1', 'key 2'}
>+
>+hash:drop()
>diff --git a/test/box/hash_with_function.result b/test/box/hash_with_function.result
>new file mode 100644
>index 000000000..cac268281
>--- /dev/null
>+++ b/test/box/hash_with_function.result
>@@ -0,0 +1,26 @@
>+-- test-run result file version 2
>+-- Hash index can not use function.
>+
>+s = box.schema.space.create('withdata')
>+ | ---
>+ | ...
>+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>+ | ---
>+ | ...
>+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>+ | ---
>+ | ...
>+_ = s:create_index('pk')
>+ | ---
>+ | ...
>+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>+ | ---
>+ | - error: 'Can''t create or modify index ''idx'' in space ''withdata'': HASH index
>+ |     can not use a function'
>+ | ...
>+s:drop()
>+ | ---
>+ | ...
>+box.schema.func.drop('s')
>+ | ---
>+ | ...
>diff --git a/test/box/hash_with_function.test.lua b/test/box/hash_with_function.test.lua
>new file mode 100644
>index 000000000..9653de68e
>--- /dev/null
>+++ b/test/box/hash_with_function.test.lua
>@@ -0,0 +1,9 @@
>+-- Hash index can not use function.
>+
>+s = box.schema.space.create('withdata')
>+lua_code = [[function(tuple) return tuple[1] + tuple[2] end]]
>+box.schema.func.create('s', {body = lua_code, is_deterministic = true, is_sandboxed = true})
>+_ = s:create_index('pk')
>+_ = s:create_index('idx', {type = 'hash', func = box.func.s.id, parts = {{1, 'unsigned'}}})
>+s:drop()
>+box.schema.func.drop('s')
>-- 
>2.23.0
>
>
>-- 
>sergeyb@

[-- Attachment #2: Type: text/html, Size: 106379 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-19 10:24 [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests Sergey Bronnikov
  2020-03-19 11:09 ` Oleg Piskunov
  2020-03-19 14:22 ` Alexander Tikhonov
@ 2020-03-19 21:31 ` Konstantin Osipov
  2020-03-20  7:09   ` Sergey Bronnikov
  2020-03-25  9:13 ` Kirill Yukhin
  3 siblings, 1 reply; 7+ messages in thread
From: Konstantin Osipov @ 2020-03-19 21:31 UTC (permalink / raw)
  To: Sergey Bronnikov; +Cc: Oleg Piskunov, tarantool-patches

* Sergey Bronnikov <sergeyb@tarantool.org> [20/03/19 13:25]:
> Splitted single hash.test.lua to a set of small independent tests.

No rationale?

-- 
Konstantin Osipov, Moscow, Russia

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-19 21:31 ` Konstantin Osipov
@ 2020-03-20  7:09   ` Sergey Bronnikov
  2020-03-20  9:20     ` Konstantin Osipov
  0 siblings, 1 reply; 7+ messages in thread
From: Sergey Bronnikov @ 2020-03-20  7:09 UTC (permalink / raw)
  To: Konstantin Osipov, tarantool-patches, Oleg Piskunov

On 00:31 Fri 20 Mar , Konstantin Osipov wrote:
> * Sergey Bronnikov <sergeyb@tarantool.org> [20/03/19 13:25]:
> > Splitted single hash.test.lua to a set of small independent tests.
>
> No rationale?

No, there are.
Right now the most tarantool tests looks like a huge unstructured pieces
of code. There are no clear boundaries between testcases and it is
unclear what we want to test exactly, sometimes comments understand
these boundaries. Often setup/teardown mixed between testcases and
testcases doesn't make cleanup at the end. It means that tests left
'dirty' environment and it may affect next testcases.

I want to follow pattern AAA (Act-Arrange-Assert) in tarantool tests in
future and make tests more clear, maintainable and stable. Splitting
huge tests for an independent testcase is a first step into this
direction. Perhaps we can split testcases into separate functions, but
AFAIK test-run.py cannot manage Lua functions as a separate testcases.

> --
> Konstantin Osipov, Moscow, Russia

--
sergeyb@

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-20  7:09   ` Sergey Bronnikov
@ 2020-03-20  9:20     ` Konstantin Osipov
  0 siblings, 0 replies; 7+ messages in thread
From: Konstantin Osipov @ 2020-03-20  9:20 UTC (permalink / raw)
  To: Sergey Bronnikov; +Cc: Oleg Piskunov, tarantool-patches

* Sergey Bronnikov <sergeyb@tarantool.org> [20/03/20 10:10]:
> On 00:31 Fri 20 Mar , Konstantin Osipov wrote:
> > * Sergey Bronnikov <sergeyb@tarantool.org> [20/03/19 13:25]:
> > > Splitted single hash.test.lua to a set of small independent tests.
> >
> > No rationale?
> 
> No, there are.
> Right now the most tarantool tests looks like a huge unstructured pieces
> of code.

> There are no clear boundaries between testcases and it is
> unclear what we want to test exactly, sometimes comments understand
> these boundaries. Often setup/teardown mixed between testcases and
> testcases doesn't make cleanup at the end. It means that tests left
> 'dirty' environment and it may affect next testcases.
> 
> I want to follow pattern AAA (Act-Arrange-Assert) in tarantool tests in
> future and make tests more clear, maintainable and stable. Splitting
> huge tests for an independent testcase is a first step into this
> direction. Perhaps we can split testcases into separate functions, but
> AFAIK test-run.py cannot manage Lua functions as a separate testcases.

This rationale belongs to the commit comment. 

My take is - the rationale is weak. From the outside it looks like
you do not understand this code well enough but try to modify it
to match your expectations. Besides, it is puzzling why you spend
time on it, as if there were no areas in the code that required
testing (transactional data dictionary!). The tests were written by developers 
and serve their purpose quite well. If you feel you would like to
exercise AAA pattern, go ahead and write some new tests - and
make an effort that they are as fast, clean and easy to use as
existing ones. 

-- 
Konstantin Osipov, Moscow, Russia
https://scylladb.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests
  2020-03-19 10:24 [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests Sergey Bronnikov
                   ` (2 preceding siblings ...)
  2020-03-19 21:31 ` Konstantin Osipov
@ 2020-03-25  9:13 ` Kirill Yukhin
  3 siblings, 0 replies; 7+ messages in thread
From: Kirill Yukhin @ 2020-03-25  9:13 UTC (permalink / raw)
  To: Sergey Bronnikov; +Cc: Oleg Piskunov, tarantool-patches

Hello,

On 19 мар 13:24, Sergey Bronnikov wrote:
> Splitted single hash.test.lua to a set of small independent tests.
> 
> GitHub branch: https://github.com/tarantool/tarantool/tree/ligurio/hash_test_split

I've checked your patch into master.

--
Regards, Kirill Yukhin

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-03-25  9:13 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-19 10:24 [Tarantool-patches] [PATCH v2] Split box/hash.test.lua to a set of small independent tests Sergey Bronnikov
2020-03-19 11:09 ` Oleg Piskunov
2020-03-19 14:22 ` Alexander Tikhonov
2020-03-19 21:31 ` Konstantin Osipov
2020-03-20  7:09   ` Sergey Bronnikov
2020-03-20  9:20     ` Konstantin Osipov
2020-03-25  9:13 ` Kirill Yukhin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox