Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/test_clojure/evaluation.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,225 @@ 1.4 +; Copyright (c) Rich Hickey. All rights reserved. 1.5 +; The use and distribution terms for this software are covered by the 1.6 +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.7 +; which can be found in the file epl-v10.html at the root of this distribution. 1.8 +; By using this software in any fashion, you are agreeing to be bound by 1.9 +; the terms of this license. 1.10 +; You must not remove this notice, or any other, from this software. 1.11 + 1.12 + 1.13 +;; Tests for the Clojure functions documented at the URL: 1.14 +;; 1.15 +;; http://clojure.org/Evaluation 1.16 +;; 1.17 +;; by J. McConnell 1.18 +;; Created 22 October 2008 1.19 + 1.20 +(ns clojure.test-clojure.evaluation 1.21 + (:use clojure.test)) 1.22 + 1.23 +(import '(java.lang Boolean) 1.24 + '(clojure.lang Compiler Compiler$CompilerException)) 1.25 + 1.26 +(defmacro test-that 1.27 + "Provides a useful way for specifying the purpose of tests. If the first-level 1.28 + forms are lists that make a call to a clojure.test function, it supplies the 1.29 + purpose as the msg argument to those functions. Otherwise, the purpose just 1.30 + acts like a comment and the forms are run unchanged." 1.31 + [purpose & test-forms] 1.32 + (let [tests (map 1.33 + #(if (= (:ns (meta (resolve (first %)))) 1.34 + (the-ns 'clojure.test)) 1.35 + (concat % (list purpose)) 1.36 + %) 1.37 + test-forms)] 1.38 + `(do ~@tests))) 1.39 + 1.40 +(deftest Eval 1.41 + (is (= (eval '(+ 1 2 3)) (Compiler/eval '(+ 1 2 3)))) 1.42 + (is (= (eval '(list 1 2 3)) '(1 2 3))) 1.43 + (is (= (eval '(list + 1 2 3)) (list clojure.core/+ 1 2 3))) 1.44 + (test-that "Non-closure fns are supported as code" 1.45 + (is (= (eval (eval '(list + 1 2 3))) 6))) 1.46 + (is (= (eval (list '+ 1 2 3)) 6))) 1.47 + 1.48 +; not using Clojure's RT/classForName since a bug in it could hide a bug in 1.49 +; eval's resolution 1.50 +(defn class-for-name [name] 1.51 + (java.lang.Class/forName name)) 1.52 + 1.53 +(defmacro in-test-ns [& body] 1.54 + `(binding [*ns* *ns*] 1.55 + (in-ns 'clojure.test-clojure.evaluation) 1.56 + ~@body)) 1.57 + 1.58 +;;; Literals tests ;;; 1.59 + 1.60 +(defmacro #^{:private true} evaluates-to-itself? [expr] 1.61 + `(let [v# ~expr 1.62 + q# (quote ~expr)] 1.63 + (is (= (eval q#) q#) (str q# " does not evaluate to itself")))) 1.64 + 1.65 +(deftest Literals 1.66 + ; Strings, numbers, characters, nil and keywords should evaluate to themselves 1.67 + (evaluates-to-itself? "test") 1.68 + (evaluates-to-itself? "test 1.69 + multi-line 1.70 + string") 1.71 + (evaluates-to-itself? 1) 1.72 + (evaluates-to-itself? 1.0) 1.73 + (evaluates-to-itself? 1.123456789) 1.74 + (evaluates-to-itself? 1/2) 1.75 + (evaluates-to-itself? 1M) 1.76 + (evaluates-to-itself? 999999999999999999) 1.77 + (evaluates-to-itself? \a) 1.78 + (evaluates-to-itself? \newline) 1.79 + (evaluates-to-itself? nil) 1.80 + (evaluates-to-itself? :test) 1.81 + ; Boolean literals should evaluate to Boolean.{TRUE|FALSE} 1.82 + (is (identical? (eval true) Boolean/TRUE)) 1.83 + (is (identical? (eval false) Boolean/FALSE))) 1.84 + 1.85 +;;; Symbol resolution tests ;;; 1.86 + 1.87 +(def foo "abc") 1.88 +(in-ns 'resolution-test) 1.89 +(def bar 123) 1.90 +(def #^{:private true} baz 456) 1.91 +(in-ns 'clojure.test-clojure.evaluation) 1.92 + 1.93 +(defn a-match? [re s] (not (nil? (re-matches re s)))) 1.94 + 1.95 +(defmacro throws-with-msg 1.96 + ([re form] `(throws-with-msg ~re ~form Exception)) 1.97 + ([re form x] `(throws-with-msg 1.98 + ~re 1.99 + ~form 1.100 + ~(if (instance? Exception x) x Exception) 1.101 + ~(if (instance? String x) x nil))) 1.102 + ([re form class msg] 1.103 + `(let [ex# (try 1.104 + ~form 1.105 + (catch ~class e# e#) 1.106 + (catch Exception e# 1.107 + (let [cause# (.getCause e#)] 1.108 + (if (= ~class (class cause#)) cause# (throw e#)))))] 1.109 + (is (a-match? ~re (.toString ex#)) 1.110 + (or ~msg 1.111 + (str "Expected exception that matched " (pr-str ~re) 1.112 + ", but got exception with message: \"" ex#)))))) 1.113 + 1.114 +(deftest SymbolResolution 1.115 + (test-that 1.116 + "If a symbol is namespace-qualified, the evaluated value is the value 1.117 + of the binding of the global var named by the symbol" 1.118 + (is (= (eval 'resolution-test/bar) 123))) 1.119 + 1.120 + (test-that 1.121 + "It is an error if there is no global var named by the symbol" 1.122 + (throws-with-msg 1.123 + #".*Unable to resolve symbol: bar.*" (eval 'bar))) 1.124 + 1.125 + (test-that 1.126 + "It is an error if the symbol reference is to a non-public var in a 1.127 + different namespace" 1.128 + (throws-with-msg 1.129 + #".*resolution-test/baz is not public.*" 1.130 + (eval 'resolution-test/baz) 1.131 + Compiler$CompilerException)) 1.132 + 1.133 + (test-that 1.134 + "If a symbol is package-qualified, its value is the Java class named by the 1.135 + symbol" 1.136 + (is (= (eval 'java.lang.Math) (class-for-name "java.lang.Math")))) 1.137 + 1.138 + (test-that 1.139 + "If a symbol is package-qualified, it is an error if there is no Class named 1.140 + by the symbol" 1.141 + (is (thrown? Compiler$CompilerException (eval 'java.lang.FooBar)))) 1.142 + 1.143 + (test-that 1.144 + "If a symbol is not qualified, the following applies, in this order: 1.145 + 1.146 + 1. If it names a special form it is considered a special form, and must 1.147 + be utilized accordingly. 1.148 + 1.149 + 2. A lookup is done in the current namespace to see if there is a mapping 1.150 + from the symbol to a class. If so, the symbol is considered to name a 1.151 + Java class object. 1.152 + 1.153 + 3. If in a local scope (i.e. in a function definition), a lookup is done 1.154 + to see if it names a local binding (e.g. a function argument or 1.155 + let-bound name). If so, the value is the value of the local binding. 1.156 + 1.157 + 4. A lookup is done in the current namespace to see if there is a mapping 1.158 + from the symbol to a var. If so, the value is the value of the binding 1.159 + of the var referred-to by the symbol. 1.160 + 1.161 + 5. It is an error." 1.162 + 1.163 + ; First 1.164 + (doall (for [form '(def if do let quote var fn loop recur throw try 1.165 + monitor-enter monitor-exit)] 1.166 + (is (thrown? Compiler$CompilerException (eval form))))) 1.167 + (let [if "foo"] 1.168 + (is (thrown? Compiler$CompilerException (eval 'if))) 1.169 + 1.170 + ; Second 1.171 + (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean")))) 1.172 + (let [Boolean "foo"] 1.173 + (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean")))) 1.174 + 1.175 + ; Third 1.176 + (is (= (eval '(let [foo "bar"] foo)) "bar")) 1.177 + 1.178 + ; Fourth 1.179 + (in-test-ns (is (= (eval 'foo) "abc"))) 1.180 + (is (thrown? Compiler$CompilerException (eval 'bar))) ; not in this namespace 1.181 + 1.182 + ; Fifth 1.183 + (is (thrown? Compiler$CompilerException (eval 'foobar))))) 1.184 + 1.185 +;;; Metadata tests ;;; 1.186 + 1.187 +(defstruct struct-with-symbols (with-meta 'k {:a "A"})) 1.188 + 1.189 +(deftest Metadata 1.190 + 1.191 + (test-that 1.192 + "find returns key symbols and their metadata" 1.193 + (let [s (struct struct-with-symbols 1)] 1.194 + (is (= {:a "A"} (meta (first (find s 'k)))))))) 1.195 + 1.196 +;;; Collections tests ;;; 1.197 +(def x 1) 1.198 +(def y 2) 1.199 + 1.200 +(deftest Collections 1.201 + (in-test-ns 1.202 + (test-that 1.203 + "Vectors and Maps yield vectors and (hash) maps whose contents are the 1.204 + evaluated values of the objects they contain." 1.205 + (is (= (eval '[x y 3]) [1 2 3])) 1.206 + (is (= (eval '{:x x :y y :z 3}) {:x 1 :y 2 :z 3})) 1.207 + (is (instance? clojure.lang.IPersistentMap (eval '{:x x :y y}))))) 1.208 + 1.209 + (in-test-ns 1.210 + (test-that 1.211 + "Metadata maps yield maps whose contents are the evaluated values of 1.212 + the objects they contain. If a vector or map has metadata, the evaluated 1.213 + metadata map will become the metadata of the resulting value." 1.214 + (is (= (eval #^{:x x} '[x y]) #^{:x 1} [1 2])))) 1.215 + 1.216 + (test-that 1.217 + "An empty list () evaluates to an empty list." 1.218 + (is (= (eval '()) ())) 1.219 + (is (empty? (eval ()))) 1.220 + (is (= (eval (list)) ()))) 1.221 + 1.222 + (test-that 1.223 + "Non-empty lists are considered calls" 1.224 + (is (thrown? Compiler$CompilerException (eval '(1 2 3)))))) 1.225 + 1.226 +(deftest Macros) 1.227 + 1.228 +(deftest Loading)