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)