/ tests / test.nim
test.nim
  1  # To run these tests, simply execute `nimble test`.
  2  
  3  import unittest
  4  import edn, options, tables, strutils
  5  
  6  # need to re-structure this at some point
  7  test "everything":
  8    var node: EdnNode
  9  
 10    node = read(" nil")
 11    check node.kind == EdnNil
 12  
 13    node = read("10")
 14    check node.kind == EdnInt
 15    check node.num == 10
 16  
 17    node = read("10e10")
 18    check node.kind == EdnFloat
 19    check node.fnum == 10e10
 20  
 21    node = read("+5.0E5")
 22    check node.kind == EdnFloat
 23    check node.fnum == +5.0E5
 24  
 25    node = read("true")
 26    check node.kind == EdnBool
 27    check node.boolVal == true
 28  
 29    node = read("1 2 3")
 30    check node.kind == EdnInt
 31    check node.num == 1
 32  
 33    node = read("(1 2 3)")
 34    check node.kind == EdnList
 35    check node.list.len == 3
 36  
 37    node = read("""(
 38                    ;; comment in a list
 39                     )""")
 40    check node.kind == EdnList
 41    check node.comments.len == 0
 42  
 43    block:
 44      # comment related tests
 45      
 46      var opts: ParseOptions
 47      opts.eof_is_error = true
 48      opts.suppress_read = false
 49      opts.conditional_exprs = asError
 50      opts.comments_handling = keepComments
 51      node = read(""";; this is a coment
 52      ()
 53      """, opts)
 54      check node.kind == EdnCommentLine
 55      check node.comments.len == 0
 56  
 57      node = read("""(
 58      ;; this is a coment
 59      ())
 60      """, opts)
 61      check node.kind == EdnList
 62      check node.list[0].comments.len > 0
 63      
 64      node = read(""";; this is a comment
 65      (1 2
 66      ;; last elem
 67      3)""", opts)
 68      check node.kind == EdnCommentLine
 69  
 70      # the comment should be returned on subsequent read().
 71      # not very clean, but does not require a look-ahead read()
 72      node = read("""()
 73  ;; comment after a list""", opts)
 74      check node.kind == EdnList
 75      check node.comments.len == 0
 76  
 77      node = read("""(
 78                    ;; comment in a list
 79                     )""", opts)
 80      check node.kind == EdnList
 81      check node.comments.len == 1
 82      check node.comments[0].placement == Inside
 83      
 84      node = read(""";; this is a comment
 85      (1 2
 86      ;; last elem
 87      3)""", opts)
 88      check node.kind == EdnCommentLine
 89      check node.comments.len == 0
 90  
 91      node = read("""{:x 1
 92                      ;;comment 
 93                      :y 2} """, opts)
 94      check node.kind == EdnMap
 95  
 96      node = read("""{:view s/Keyword
 97                      ;;comment 
 98                      (s/optional-key :label) s/Str
 99                      (foo 1) 2} """, opts)
100      check node.kind == EdnMap
101  
102  
103    node = read("""{:view s/Keyword
104                    ;;comment 
105                    (s/optional-key :label) s/Str
106                    (foo 1) 2} """)
107    check node.kind == EdnMap
108  
109    node = read(""";; this is a comment
110    (1 2
111    ;; last elem
112    3)""")
113    check node.kind == EdnList
114    check node.comments.len == 0
115    check node.list[2].comments.len == 0
116  
117    node = read("1")
118    check node.kind == EdnInt
119    check node.num == 1
120  
121    node = read("-1")
122    check node.kind == EdnInt
123    check node.num == -1
124  
125    node = read("1M")
126    check node.kind == EdnInt     #TODO: for now...
127  
128    node = read("()")
129    check node.kind == EdnList
130    check node.list.len == 0
131  
132    node = read("(())")
133    check node.kind == EdnList
134    check node.list.len == 1
135    check node.list[0].kind == EdnList
136    check node.list[0].list.len == 0
137  
138    node = read("nil")
139    check node.kind == EdnNil
140  
141    node = read("symbol-👋") #emoji
142    check node.kind == EdnSymbol
143    check node.symbol.name == "symbol-👋"
144  
145    node = read(":foo")
146    check node.kind == EdnKeyword
147    check node.keyword.name == "foo"
148    check node.namespacing == NoNamespace
149    check $node == ":foo"
150  
151    node = read("::foobar")
152    check node.kind == EdnKeyword
153    check node.keyword.name == "foobar"
154    check node.keyword.ns == ""
155    check node.namespacing == LocalNamespace
156    check $node == "::foobar"
157  
158    node = read("+foo+")
159    check node.kind == EdnSymbol
160    check node.symbol.name == "+foo+"
161  
162    node = read("moo/bar")
163    check node.kind == EdnSymbol
164    check node.symbol == ("moo", "bar")
165  
166    node = read("'foo") # -> (quote foo)
167    check node.kind == EdnList
168    check node.list[0] == new_edn_symbol("", "quote")
169  
170    node = read("{}")
171    check node.kind == EdnMap
172    check node.map.len == 0
173  
174    node = read("{:A 1 :B 2}")
175    check node.kind == EdnMap
176    check node.map.len == 2
177  
178    node = read("{:A 1, :B 2}")
179    check node.kind == EdnMap
180    check node.map.len == 2
181  
182    node = read("{:x 1M :y 2}")
183    check node.kind == EdnMap
184    check node.map.len == 2
185  
186    node = read("{:order_date #clj-time/date-time \"2019-12-01T00:00:00.000Z\", :quantity 125.3M, 1 1}")
187    check node.kind == EdnMap
188    check node.map.len == 3
189    
190    try:
191      node = read("moo/bar/baz")
192      raise new_exception(Exception, "FAILURE")
193    except ParseError:
194      discard
195  
196    node = read("[1 2 , 3,4]")
197    check node.kind == EdnVector
198    check node.vec.len == 4
199  
200    node = read("^{:k 1} {}")
201    check node.kind == EdnMap
202    check node.map.count == 0
203    # TODO: define 'len' for HMap
204    check node.map_meta.count == 1
205    check node.map_meta[new_edn_keyword("", "k")].get() == new_edn_int(1)
206  
207    let hh = new_hmap()
208    hh[new_edn_keyword("", "foo")] = edn_true
209    check hh[new_edn_keyword("", "foo")].get() == new_edn_bool(true)
210  
211    node = read("^ :foo []")
212    check node.kind == EdnVector
213    check node.vec.len == 0
214    check node.vec_meta.count == 1
215    check node.vec_meta[new_edn_keyword("", "foo")].get() == new_edn_bool(true)
216  
217    node = read("^foo (1 2 3)")
218    check node.kind == EdnList
219    check node.list.len == 3
220    check node.list_meta.count == 1
221    check node.list_meta[KeyTag].get() == new_edn_symbol("", "foo")
222  
223    node = read("^{:x 1} #{1}")
224    check node.kind == EdnSet
225    check node.set_meta.count == 1
226  
227    node = read("^\"foo\" Symbol")
228    check node.kind == EdnSymbol
229    check node.symbol == new_edn_symbol("", "Symbol").symbol
230    check node.symbol_meta[KeyTag].get().kind == EdnString
231    check node.symbol_meta[KeyTag].get().str == "foo"
232  
233    node = read("\"foo\"")
234    check node.kind == EdnString
235    check node.str == "foo"
236    check node.str.len == 3
237  
238    node = read("#_ [foo bar]")
239    check node == nil
240  
241    node = read("#{foo whateve 1}")
242    check node.kind == EdnSet
243    check node.set_elems.count == 3
244  
245    node = read("#{}")
246    check node.kind == EdnSet
247    check node.set_elems.count == 0
248  
249    node = read("#:foo {:x 1}")
250    check node.kind == EdnMap
251    check node.map.count == 1
252    check node.map[new_edn_keyword("foo", "x")].get == new_edn_int(1)
253  
254    node = read("1/2")
255    check node.kind == EdnRatio
256    check node.rnum == (BiggestInt(1), BiggestInt(2))
257  
258    node = read("{:ratio -1/2}")
259    check node.kind == EdnMap
260    check node.map[new_edn_keyword("", "ratio")].get == new_edn_ratio(-1, 2)
261  
262    node = read("#foo.bar -1")
263    check node.kind == EdnTaggedValue
264    check node.value.kind == EdnInt
265    check node.value == new_edn_int(-1)
266  
267    node = read("#foo.bar [1 2 \"balls\"]")
268    check node.kind == EdnTaggedValue
269    check node.value.kind == EdnVector
270  
271    node = read("#(or % disabled)")
272    check node.kind == EdnList
273  
274    # let's set up conditional forms reading
275    var opts: ParseOptions
276    opts.conditional_exprs = asTagged
277    init_edn_readers(opts)
278  
279    # conditional compilation exprs
280    node = read("#+clj #{foo}")
281    check node.tag == ("", "+clj")
282    check node.kind == EdnTaggedValue
283    check node.value.kind == EdnSet
284  
285    opts.conditional_exprs = cljSource
286    init_edn_readers(opts)
287    node = read("#+clj #{foo}")
288    check node.kind == EdnSet
289    node = read("#+cljs {}")
290    check node == nil
291  
292    node = read("[1 2 #+cljs 3 4]")
293    check node.kind == EdnVector
294    check node.vec.len == 3
295  
296    var opts1: ParseOptions
297    opts1.eof_is_error = true
298    opts1.suppress_read = false
299    opts1.conditional_exprs = cljSource
300  
301    node = read("#?(:clj :x)", opts1)
302    check node.kind == EdnKeyword
303  
304    node = read("#?(:cljs :x)", opts1)
305    check node == nil
306  
307    try:
308      node = read("#?(:cljs :x :clj)", opts1)
309      check false
310    except ParseError:
311      discard
312  
313    node = read("[1 2 #?(:clj 3)]", opts1)
314    check node.kind == EdnVector
315    check node.vec.len == 3
316  
317    opts1.conditional_exprs = cljsSource
318    node = read("[1 2 #?(:clj 3)]", opts1)
319    check node.kind == EdnVector
320    check node.vec.len == 2
321  
322    opts1.conditional_exprs = ignoreConditionals
323    node = read("#?@(:clj [:generator-fn tlsubs/subscriber-timeline-record-generator])", opts1)
324    check node == nil
325  
326    opts1.conditional_exprs = cljSource
327    # this should splice the tuple into key & value of the map,
328    #so result should be a map with one entry in it.
329    node = read("{#?@(:clj [:generator-fn tlsubs/subscriber-timeline-record-generator])}", opts1)
330    check node.kind == EdnMap
331    check node.map[new_edn_keyword("", "generator-fn")].get().kind == EdnSymbol
332  
333    try:
334      node = read("{:ratio 1/-2}")
335      check node.kind == EdnMap
336    except ParseError:
337      discard
338  
339    try:
340      node = read(";; foo bar")
341      check false
342    except ParseError:
343      discard
344  
345    node = read("\"\uffff\"")
346    check node.kind == EdnString
347  
348    node = read("\\uffff")
349    check node.kind == EdnCharacter
350  
351    node = read("()") # for the following to work
352    var n1: EdnNode = EdnNode(kind: EdnNil)
353    var n2: EdnNode = EdnNode(kind: EdnNil)
354    var n3: EdnNode = EdnNode(kind: EdnBool, boolVal: false)
355    var n4: EdnNode = EdnNode(kind: EdnBool, boolVal: false)
356    #echo "===? ", n1 == n2
357    var t = new_table[EdnNode,int]()
358    t[n3] = 3
359    #echo "COUNT OF ELEMS ", t.len, " ", n1.hash, " ", n2.hash, " ", n3.hash
360    t[n4] = 4
361    #echo "COUNT OF ELEMS ", t.len, " ", n1.hash, " ", n2.hash, " ", n3.hash
362    t[n4] = 5
363    #echo "COUNT OF ELEMS ", t.len, " ", n1.hash, " ", n2.hash, " ", n3.hash
364  
365    var mm1 = new_hmap()
366    mm1[n2] = n2
367    mm1[node] = node
368  
369    mm1 = new_hmap(0)
370    mm1[node] = node
371    check mm1.count == 1
372    mm1[n1] = n1
373    check mm1.count == 2
374    mm1[n1] = n2
375    check mm1.count == 2
376    for i in 1..10:
377      mm1[new_edn_int(i.int_to_str())] = new_edn_int(i.int_to_str())
378    check mm1.count == 12
379    check mm1[n1].get() == n2
380  
381    node = read("#\".*\"")
382    check node.kind == EdnRegex
383  
384    node = read("#'some-ns/symbol")
385    check node.kind == EdnVarQuote
386  
387