Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions test/clojure/core_test/eval.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
(ns clojure.core-test.eval
(:require [clojure.test :as t :refer [are deftest is testing]]
[clojure.core-test.portability #?(:cljs :refer-macros :default :refer) [when-var-exists] :as p]
#?(:cljs [cljs.js]))) ; need this for eval support in CLJS

(when-var-exists eval
(def x 42)

(deftest test-eval
#?(:cljs nil
:default (testing "Strings, numbers, characters, true, false, nil and keywords evaluate to themselves."
(are [expected form] (= expected (eval form))
;; lots of Clojure objects just evaluate to themselves
1 1
0 0
-1 -1
1.0 1.0
1N 1N
1.0M 1.0M
1/2 1/2
"a string" "a string"
"(+ 1 2)" "(+ 1 2)" ; strings are just evaluated as strings
\x \x
true true
false false
nil nil
:a-keyword :a-keyword)))
Comment thread
dgr marked this conversation as resolved.
Outdated
#?(:cljs nil
:default (testing "Symbol resolution"
;; namespace qualified
(is (= 42 (eval 'clojure.core-test.eval/x)))))
#?(:cljs nil
:default (testing "Vectors, Maps, Sets"
;; basic literal collections
(is (= [:a :b] (eval [:a :b])))
(is (= {:a :b} (eval {:a :b})))
(is (= #{:a :b} (eval #{:a :b})))
;; collections with embedded symbols
(is (= [:a :b 42] (eval [:a :b 'clojure.core-test.eval/x])))))
#?(:cljs nil
:default (testing "Lists, function application, and macros"
;; empty list evaluates to itself
(is (= '() (eval '())))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about an infinite seq?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you trying to test with that? That it doesn't get realized?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, eval'ing an infinite range returns a clojure.lang.Iterate object. I'm not even sure what that is.

user> (class (eval '(range)))
clojure.lang.Iterate

What are you wanting to test with that?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, eval'ing a fixed range returns a clojure.lang.LongRange:

user> (class (eval '(range 10)))
clojure.lang.LongRange

Copy link
Copy Markdown
Member

@jeaye jeaye Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you trying to test with that? That it doesn't get realized?

Yep.

So, eval'ing an infinite range returns a clojure.lang.Iterate object. I'm not even sure what that is.

That's the type of (range).

Interestingly, eval'ing a fixed range returns a clojure.lang.LongRange:

LongRange was the type that went in. The Long is because each value is a Long (i.e. 10 is a Long).

So, eval clearly doesn't realize the seq, from the behavior. That's a great test case to have.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, how do I test for not being realized, exactly? Is it just that I get something back at all, because if it tried to realize the infinite sequence it would wait until the full sequence was realized and finally throw and OOM exception?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. If we get it back and continue running the test, we can know that it wasn't realized.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll add this.

;; function calls
(is (= 5 (eval '(+ 2 3))))
(is (= 6 (eval '(* 2 3))))
;; macros
(is (= 42 (eval '(or false clojure.core-test.eval/x))))
(is (= 42 (eval '(and (+ 2 3) clojure.core-test.eval/x))))
;; special forms
(is (= 43 (eval '(let [y 43] (or false y)))))
(is (= 43 (eval '(loop [y 0] (if (= y 43) y (recur (inc y)))))))))))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that both of these are macros and not special forms. That's not to say this is wrong, it's just not exactly testing what's commented. let* and loop* are the special forms, which would work just as well here. The macros just add destructuring support.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. I relied on https://clojure.org/reference/special_forms for the list of special forms. And the doc strings for both let and loop say they are special forms. For example:

user> (doc loop)
-------------------------
clojure.core/loop
  (loop [bindings*] exprs*)
([bindings & body])
Special Form
  Evaluates the exprs in a lexical context in which the symbols in
  the binding-forms are bound to their respective init-exprs or parts
  therein. Acts as a recur target.

  Please see http://clojure.org/special_forms#loop

and

user> (doc let)
-------------------------
clojure.core/let
  (let [bindings*] exprs*)
([bindings & body])
Special Form
  binding => binding-form init-expr
  binding-form => name, or destructuring-form
  destructuring-form => map-destructure-form, or seq-destructure-form

  Evaluates the exprs in a lexical context in which the symbols in
  the binding-forms are bound to their respective init-exprs or parts
  therein.

  See https://clojure.org/reference/special_forms#binding-forms for
  more information about destructuring.

  Please see http://clojure.org/special_forms#let
Spec
  args: (cat :bindings :clojure.core.specs.alpha/bindings :body (* any?))
  ret: any?

Loading