summaryrefslogtreecommitdiff
path: root/tests/test.fnl
blob: 43247d96636423a3621559bb833850f44147df16 (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
(local test {})

(fn eq-fn []
  "Returns recursive equality function.

This function is able to compare tables of any depth, even if one of
the tables uses tables as keys."
  `(fn eq# [left# right#]
     (if (= left# right#)
         true
         (and (= (type left#) :table) (= (type right#) :table))
         (let [oldmeta# (getmetatable right#)]
           ;; In case if we'll get something like
           ;; (eq {[1 2 3] {:a [1 2 3]}} {[1 2 3] {:a [1 2 3]}})
           ;; we have to do even deeper search
           (setmetatable right# {:__index (fn [tbl# key#]
                                            (var res# nil)
                                            (each [k# v# (pairs tbl#)]
                                              (when (eq# k# key#)
                                                (set res# v#)
                                                (lua :break)))
                                            res#)})
           (var [res# count-a# count-b#] [true 0 0])
           (each [k# v# (pairs left#)]
             (set res# (eq# v# (. right# k#)))
             (set count-a# (+ count-a# 1))
             (when (not res#) (lua :break)))
           (when res#
             (each [_# _# (pairs right#)]
               (set count-b# (+ count-b# 1)))
             (set res# (= count-a# count-b#)))
           (setmetatable right# oldmeta#)
           res#)
         false)))

(fn test.assert-eq
  [expr1 expr2 msg]
  "Like `assert`, except compares results of `expr1` and `expr2` for equality.
Generates formatted message if `msg` is not set to other message.

# Example
Compare two expressions:

``` fennel
;; (assert-eq 1 (+1 1))
;; => runtime error: equality assertion failed
;; =>   Left: 1
;; =>   Right: 3
```

Deep compare values:

``` fennel
;; (assert-eq [1 {[2 3] [4 5 6]}] [1 {[2 3] [4 5]}])
;; => runtime error: equality assertion failed
;; =>   Left: [1 {[2 3] [4 5 6]}]
;; =>   Right: [1 {[2 3] [4 5]}]
```"
  `(let [left# ,expr1
         right# ,expr2
         eq# ,(eq-fn)
         fennel# (require :fennel)]
     (assert (pick-values 1 (pcall #(do eq# left# right#)))
             (or ,msg (.. "assertion failed for expression:
(= " ,(view expr1 {:one-line? true}) " " ,(view expr2 {:one-line? true}) ")
  Left:  " (fennel#.view left# {:one-line? true}) "
  Right: " (fennel#.view right# {:one-line? true}) "\n")))))

(fn test.assert-ne
  [expr1 expr2 msg]
  "Assert for unequality.  Like `assert`, except compares results of
`expr1` and `expr2` for equality.  Generates formatted message if
`msg` is not set to other message.  Same as [`assert-eq`](#assert-eq)."
  `(let [left# ,expr1
         right# ,expr2
         eq# ,(eq-fn)
         fennel# (require :fennel)]
     (assert (pick-values 1 (pcall #(not (eq# left# right#))))
             (or ,msg (.. "assertion failed for expression:
(not= " ,(view expr1 {:one-line? true}) " " ,(view expr2 {:one-line? true}) ")
  Left:  " (fennel#.view left# {:one-line? true}) "
  Right: " (fennel#.view right# {:one-line? true}) "\n")))))

(fn test.assert-is
  [expr msg]
  "Assert `expr` for truth. Same as inbuilt `assert`, except generates more
  verbose message if `msg` is not set.

``` fennel
;; (assert-is (= 1 2 3))
;; => runtime error: assertion failed for (= 1 2 3)
```"
  `(assert (pick-values 1 (pcall #(do ,expr)))
           (.. "assertion failed: "
               (or ,msg ,(view expr {:one-line? true})))))

(fn test.assert-not
  [expr msg]
  "Assert `expr` for not truth. Generates more verbose message if
  `msg` is not set. Works the same as [`assert-is`](#assert-is)."
  `(assert (pick-values 1 (pcall #(not ,expr)))
           (.. "assertion failed: "
               (or ,msg ,(view expr {:one-line? true})))))

(fn test.deftest
  [name ...]
  "Simple way of grouping tests with `name`."
  `(do ,...))

(fn test.testing
  [description ...]
  "Print test `description` and run it."
  `(do (io.stdout:write (.. "testing: " ,description "\n"))
       ,...))

(doto test
  (tset :_DOC_ORDER #[:deftest :testing
                      :assert-eq :assert-ne
                      :assert-is :assert-not]))