summary refs log tree commit diff stats
path: root/tests/stdlib/thashes.nim
blob: 66857d3ca72e5e0bf3e173c480f3740f85ffda8f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
discard """
  targets: "c cpp js"
"""

import std/hashes
from stdtest/testutils import disableVm, whenVMorJs

when not defined(js) and not defined(cpp):
  block:
    var x = 12
    iterator hello(): int {.closure.} =
      yield x

    discard hash(hello)

block hashes:
  block hashing:
    var dummy = 0.0
    doAssert hash(dummy) == hash(-dummy)

  # "VM and runtime should make the same hash value (hashIdentity)"
  block:
    const hi123 = hashIdentity(123)
    doAssert hashIdentity(123) == hi123

  # "VM and runtime should make the same hash value (hashWangYi1)"
  block:
    const wy123 = hashWangYi1(123)
    doAssert wy123 != 0
    doAssert hashWangYi1(123) == wy123


  # "hashIdentity value incorrect at 456"
  block:
    doAssert hashIdentity(456) == 456

  # "hashWangYi1 value incorrect at 456"
  block:
    when Hash.sizeof < 8:
      doAssert hashWangYi1(456) == 1293320666
    else:
      doAssert hashWangYi1(456) == -6421749900419628582

block empty:
  var
    a = ""
    b = newSeq[char]()
    c = newSeq[int]()
    d = cstring""
    e = "abcd"
  doAssert hash(a) == 0
  doAssert hash(b) == 0
  doAssert hash(c) == 0
  doAssert hash(d) == 0
  doAssert hashIgnoreCase(a) == 0
  doAssert hashIgnoreStyle(a) == 0
  doAssert hash(e, 3, 2) == 0

block sameButDifferent:
  doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
  doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234")
  doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234")
  doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234")

block smallSize: # no multibyte hashing
  let
    xx = @['H', 'i']
    ii = @[72'u8, 105]
    ss = "Hi"
  doAssert hash(xx) == hash(ii)
  doAssert hash(xx) == hash(ss)
  doAssert hash(xx) == hash(xx, 0, xx.high)
  doAssert hash(ss) == hash(ss, 0, ss.high)

block largeSize: # longer than 4 characters
  let
    xx = @['H', 'e', 'l', 'l', 'o']
    xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's']
    ssl = "Helloweens"
  doAssert hash(xxl) == hash(ssl)
  doAssert hash(xxl) == hash(xxl, 0, xxl.high)
  doAssert hash(ssl) == hash(ssl, 0, ssl.high)
  doAssert hash(xx) == hash(xxl, 0, 4)
  doAssert hash(xx) == hash(ssl, 0, 4)
  doAssert hash(xx, 0, 3) == hash(xxl, 0, 3)
  doAssert hash(xx, 0, 3) == hash(ssl, 0, 3)

proc main() =
  doAssert hash(0.0) == hash(0)
  # bug #16061
  doAssert hash(cstring"abracadabra") == 97309975
  doAssert hash(cstring"abracadabra") == hash("abracadabra")

  when sizeof(int) == 8 or defined(js):
    block:
      var s: seq[Hash]
      for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]:
        let b = hash(a)
        doAssert b notin s
        s.add b
    when defined(js):
      doAssert hash(0.345602) == 2035867618
      doAssert hash(234567.45) == -20468103
      doAssert hash(-9999.283456) == -43247422
      doAssert hash(84375674.0) == 707542256
    else:
      doAssert hash(0.345602) == 387936373221941218
      doAssert hash(234567.45) == -8179139172229468551
      doAssert hash(-9999.283456) == 5876943921626224834
      doAssert hash(84375674.0) == 1964453089107524848
  else:
    doAssert hash(0.345602) != 0
    doAssert hash(234567.45) != 0
    doAssert hash(-9999.283456) != 0
    doAssert hash(84375674.0) != 0

  block: # bug #16555
    proc fn(): auto =
      # avoids hardcoding values
      var a = "abc\0def"
      var b = a.cstring
      result = (hash(a), hash(b))
      doAssert result[0] != result[1]
    when not defined(js):
      doAssert fn() == static(fn())
    else:
      # xxx this is a tricky case; consistency of hashes for cstring's containing
      # '\0\' matters for c backend but less for js backend since such strings
      # are much less common in js backend; we make vm for js backend consistent
      # with c backend instead of js backend because FFI code (or other) could
      # run at CT, expecting c semantics.
      discard

  block: # hash(object)
    type
      Obj = object
        x: int
        y: string
      Obj2[T] = object
        x: int
        y: string
      Obj3 = object
        x: int
        y: string
      Obj4 = object
        case t: bool
        of false:
          x: int
        of true:
          y: int
        z: int
      Obj5 = object
        case t: bool
        of false:
          x: int
        of true:
          y: int
        z: int

    proc hash(a: Obj2): Hash = hash(a.x)
    proc hash(a: Obj3): Hash = hash((a.x,))
    proc hash(a: Obj5): Hash =
      case a.t
      of false: hash(a.x)
      of true: hash(a.y)

    doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
    doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
    doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2"))
    doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2"))

    doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1))
    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2))
    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1))

    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2))
    doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1))
    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))

  block: # hash(ref|ptr|pointer)
    var a: array[10, uint8]
    # disableVm:
    whenVMorJs:
      # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
      discard
    do:
      assert a[0].addr.hash != a[1].addr.hash
      assert cast[pointer](a[0].addr).hash == a[0].addr.hash

  block: # hash(ref)
    type A = ref object
      x: int
    let a = A(x: 3)
    disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
      let ha = a.hash
      assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
      a.x = 4
      assert ha == a.hash # the hash only depends on the address

static: main()
main()