Mercurial > lasercutter
comparison src/clojure/test_clojure/evaluation.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
1 ; Copyright (c) Rich Hickey. All rights reserved. | |
2 ; The use and distribution terms for this software are covered by the | |
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
4 ; which can be found in the file epl-v10.html at the root of this distribution. | |
5 ; By using this software in any fashion, you are agreeing to be bound by | |
6 ; the terms of this license. | |
7 ; You must not remove this notice, or any other, from this software. | |
8 | |
9 | |
10 ;; Tests for the Clojure functions documented at the URL: | |
11 ;; | |
12 ;; http://clojure.org/Evaluation | |
13 ;; | |
14 ;; by J. McConnell | |
15 ;; Created 22 October 2008 | |
16 | |
17 (ns clojure.test-clojure.evaluation | |
18 (:use clojure.test)) | |
19 | |
20 (import '(java.lang Boolean) | |
21 '(clojure.lang Compiler Compiler$CompilerException)) | |
22 | |
23 (defmacro test-that | |
24 "Provides a useful way for specifying the purpose of tests. If the first-level | |
25 forms are lists that make a call to a clojure.test function, it supplies the | |
26 purpose as the msg argument to those functions. Otherwise, the purpose just | |
27 acts like a comment and the forms are run unchanged." | |
28 [purpose & test-forms] | |
29 (let [tests (map | |
30 #(if (= (:ns (meta (resolve (first %)))) | |
31 (the-ns 'clojure.test)) | |
32 (concat % (list purpose)) | |
33 %) | |
34 test-forms)] | |
35 `(do ~@tests))) | |
36 | |
37 (deftest Eval | |
38 (is (= (eval '(+ 1 2 3)) (Compiler/eval '(+ 1 2 3)))) | |
39 (is (= (eval '(list 1 2 3)) '(1 2 3))) | |
40 (is (= (eval '(list + 1 2 3)) (list clojure.core/+ 1 2 3))) | |
41 (test-that "Non-closure fns are supported as code" | |
42 (is (= (eval (eval '(list + 1 2 3))) 6))) | |
43 (is (= (eval (list '+ 1 2 3)) 6))) | |
44 | |
45 ; not using Clojure's RT/classForName since a bug in it could hide a bug in | |
46 ; eval's resolution | |
47 (defn class-for-name [name] | |
48 (java.lang.Class/forName name)) | |
49 | |
50 (defmacro in-test-ns [& body] | |
51 `(binding [*ns* *ns*] | |
52 (in-ns 'clojure.test-clojure.evaluation) | |
53 ~@body)) | |
54 | |
55 ;;; Literals tests ;;; | |
56 | |
57 (defmacro #^{:private true} evaluates-to-itself? [expr] | |
58 `(let [v# ~expr | |
59 q# (quote ~expr)] | |
60 (is (= (eval q#) q#) (str q# " does not evaluate to itself")))) | |
61 | |
62 (deftest Literals | |
63 ; Strings, numbers, characters, nil and keywords should evaluate to themselves | |
64 (evaluates-to-itself? "test") | |
65 (evaluates-to-itself? "test | |
66 multi-line | |
67 string") | |
68 (evaluates-to-itself? 1) | |
69 (evaluates-to-itself? 1.0) | |
70 (evaluates-to-itself? 1.123456789) | |
71 (evaluates-to-itself? 1/2) | |
72 (evaluates-to-itself? 1M) | |
73 (evaluates-to-itself? 999999999999999999) | |
74 (evaluates-to-itself? \a) | |
75 (evaluates-to-itself? \newline) | |
76 (evaluates-to-itself? nil) | |
77 (evaluates-to-itself? :test) | |
78 ; Boolean literals should evaluate to Boolean.{TRUE|FALSE} | |
79 (is (identical? (eval true) Boolean/TRUE)) | |
80 (is (identical? (eval false) Boolean/FALSE))) | |
81 | |
82 ;;; Symbol resolution tests ;;; | |
83 | |
84 (def foo "abc") | |
85 (in-ns 'resolution-test) | |
86 (def bar 123) | |
87 (def #^{:private true} baz 456) | |
88 (in-ns 'clojure.test-clojure.evaluation) | |
89 | |
90 (defn a-match? [re s] (not (nil? (re-matches re s)))) | |
91 | |
92 (defmacro throws-with-msg | |
93 ([re form] `(throws-with-msg ~re ~form Exception)) | |
94 ([re form x] `(throws-with-msg | |
95 ~re | |
96 ~form | |
97 ~(if (instance? Exception x) x Exception) | |
98 ~(if (instance? String x) x nil))) | |
99 ([re form class msg] | |
100 `(let [ex# (try | |
101 ~form | |
102 (catch ~class e# e#) | |
103 (catch Exception e# | |
104 (let [cause# (.getCause e#)] | |
105 (if (= ~class (class cause#)) cause# (throw e#)))))] | |
106 (is (a-match? ~re (.toString ex#)) | |
107 (or ~msg | |
108 (str "Expected exception that matched " (pr-str ~re) | |
109 ", but got exception with message: \"" ex#)))))) | |
110 | |
111 (deftest SymbolResolution | |
112 (test-that | |
113 "If a symbol is namespace-qualified, the evaluated value is the value | |
114 of the binding of the global var named by the symbol" | |
115 (is (= (eval 'resolution-test/bar) 123))) | |
116 | |
117 (test-that | |
118 "It is an error if there is no global var named by the symbol" | |
119 (throws-with-msg | |
120 #".*Unable to resolve symbol: bar.*" (eval 'bar))) | |
121 | |
122 (test-that | |
123 "It is an error if the symbol reference is to a non-public var in a | |
124 different namespace" | |
125 (throws-with-msg | |
126 #".*resolution-test/baz is not public.*" | |
127 (eval 'resolution-test/baz) | |
128 Compiler$CompilerException)) | |
129 | |
130 (test-that | |
131 "If a symbol is package-qualified, its value is the Java class named by the | |
132 symbol" | |
133 (is (= (eval 'java.lang.Math) (class-for-name "java.lang.Math")))) | |
134 | |
135 (test-that | |
136 "If a symbol is package-qualified, it is an error if there is no Class named | |
137 by the symbol" | |
138 (is (thrown? Compiler$CompilerException (eval 'java.lang.FooBar)))) | |
139 | |
140 (test-that | |
141 "If a symbol is not qualified, the following applies, in this order: | |
142 | |
143 1. If it names a special form it is considered a special form, and must | |
144 be utilized accordingly. | |
145 | |
146 2. A lookup is done in the current namespace to see if there is a mapping | |
147 from the symbol to a class. If so, the symbol is considered to name a | |
148 Java class object. | |
149 | |
150 3. If in a local scope (i.e. in a function definition), a lookup is done | |
151 to see if it names a local binding (e.g. a function argument or | |
152 let-bound name). If so, the value is the value of the local binding. | |
153 | |
154 4. A lookup is done in the current namespace to see if there is a mapping | |
155 from the symbol to a var. If so, the value is the value of the binding | |
156 of the var referred-to by the symbol. | |
157 | |
158 5. It is an error." | |
159 | |
160 ; First | |
161 (doall (for [form '(def if do let quote var fn loop recur throw try | |
162 monitor-enter monitor-exit)] | |
163 (is (thrown? Compiler$CompilerException (eval form))))) | |
164 (let [if "foo"] | |
165 (is (thrown? Compiler$CompilerException (eval 'if))) | |
166 | |
167 ; Second | |
168 (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean")))) | |
169 (let [Boolean "foo"] | |
170 (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean")))) | |
171 | |
172 ; Third | |
173 (is (= (eval '(let [foo "bar"] foo)) "bar")) | |
174 | |
175 ; Fourth | |
176 (in-test-ns (is (= (eval 'foo) "abc"))) | |
177 (is (thrown? Compiler$CompilerException (eval 'bar))) ; not in this namespace | |
178 | |
179 ; Fifth | |
180 (is (thrown? Compiler$CompilerException (eval 'foobar))))) | |
181 | |
182 ;;; Metadata tests ;;; | |
183 | |
184 (defstruct struct-with-symbols (with-meta 'k {:a "A"})) | |
185 | |
186 (deftest Metadata | |
187 | |
188 (test-that | |
189 "find returns key symbols and their metadata" | |
190 (let [s (struct struct-with-symbols 1)] | |
191 (is (= {:a "A"} (meta (first (find s 'k)))))))) | |
192 | |
193 ;;; Collections tests ;;; | |
194 (def x 1) | |
195 (def y 2) | |
196 | |
197 (deftest Collections | |
198 (in-test-ns | |
199 (test-that | |
200 "Vectors and Maps yield vectors and (hash) maps whose contents are the | |
201 evaluated values of the objects they contain." | |
202 (is (= (eval '[x y 3]) [1 2 3])) | |
203 (is (= (eval '{:x x :y y :z 3}) {:x 1 :y 2 :z 3})) | |
204 (is (instance? clojure.lang.IPersistentMap (eval '{:x x :y y}))))) | |
205 | |
206 (in-test-ns | |
207 (test-that | |
208 "Metadata maps yield maps whose contents are the evaluated values of | |
209 the objects they contain. If a vector or map has metadata, the evaluated | |
210 metadata map will become the metadata of the resulting value." | |
211 (is (= (eval #^{:x x} '[x y]) #^{:x 1} [1 2])))) | |
212 | |
213 (test-that | |
214 "An empty list () evaluates to an empty list." | |
215 (is (= (eval '()) ())) | |
216 (is (empty? (eval ()))) | |
217 (is (= (eval (list)) ()))) | |
218 | |
219 (test-that | |
220 "Non-empty lists are considered calls" | |
221 (is (thrown? Compiler$CompilerException (eval '(1 2 3)))))) | |
222 | |
223 (deftest Macros) | |
224 | |
225 (deftest Loading) |