2019-02-07 14:57:35 +01:00
|
|
|
;; Copyright 2019 the authors.
|
2017-04-27 23:16:57 +02:00
|
|
|
;; This file is part of Hy, which is free software licensed under the Expat
|
|
|
|
;; license. See the LICENSE.
|
|
|
|
|
2017-04-14 02:42:01 +02:00
|
|
|
(defmacro op-and-shadow-test [op &rest body]
|
|
|
|
; Creates two tests with the given `body`, one where all occurrences
|
|
|
|
; of the symbol `f` are syntactically replaced with `op` (a test of
|
|
|
|
; the real operator), and one where the body is preceded by an
|
|
|
|
; assignment of `op` to `f` (a test of the shadow operator).
|
|
|
|
;
|
|
|
|
; `op` can also be a list of operators, in which case two tests are
|
|
|
|
; created for each operator.
|
|
|
|
(import [hy [HySymbol HyString]] [hy.contrib.walk [prewalk]])
|
|
|
|
(setv defns [])
|
|
|
|
(for [o (if (coll? op) op [op])]
|
|
|
|
(.append defns `(defn ~(HySymbol (+ "test_operator_" o "_real")) []
|
|
|
|
(setv f-name ~(HyString o))
|
|
|
|
~@(prewalk :form body :f (fn [x]
|
|
|
|
(if (and (symbol? x) (= x "f")) o x)))))
|
|
|
|
(.append defns `(defn ~(HySymbol (+ "test_operator_" o "_shadow")) []
|
|
|
|
(setv f-name ~(HyString o))
|
|
|
|
(setv f ~o)
|
|
|
|
~@body)))
|
|
|
|
`(do ~@defns))
|
|
|
|
|
|
|
|
(defmacro forbid [expr]
|
|
|
|
`(assert (try
|
|
|
|
(eval '~expr)
|
2018-10-13 06:25:43 +02:00
|
|
|
(except [[TypeError SyntaxError]] True)
|
2017-04-14 02:42:01 +02:00
|
|
|
(else (raise AssertionError)))))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test +
|
|
|
|
|
|
|
|
(assert (= (f) 0))
|
|
|
|
|
2019-07-02 18:02:03 +02:00
|
|
|
(defclass C [object] (defn __pos__ [self] "called __pos__"))
|
2017-04-14 02:42:01 +02:00
|
|
|
(assert (= (f (C)) "called __pos__"))
|
|
|
|
|
|
|
|
(assert (= (f 1 2) 3))
|
|
|
|
(assert (= (f 1 2 3 4) 10))
|
|
|
|
(assert (= (f 1 2 3 4 5) 15))
|
|
|
|
|
|
|
|
; with strings
|
|
|
|
(assert (= (f "a" "b" "c")
|
|
|
|
"abc"))
|
|
|
|
; with lists
|
|
|
|
(assert (= (f ["a"] ["b"] ["c"])
|
|
|
|
["a" "b" "c"])))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test -
|
|
|
|
(forbid (f))
|
|
|
|
(assert (= (f 1) -1))
|
|
|
|
(assert (= (f 2 1) 1))
|
|
|
|
(assert (= (f 2 1 1) 0)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test *
|
|
|
|
(assert (= (f) 1))
|
|
|
|
(assert (= (f 3) 3))
|
|
|
|
(assert (= (f 3 3) 9))
|
|
|
|
(assert (= (f 2 3 4) 24))
|
|
|
|
(assert (= (f "ke" 4) "kekekeke"))
|
|
|
|
(assert (= (f [1 2 3] 2) [1 2 3 1 2 3])))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test **
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 1))
|
|
|
|
(assert (= (f 3 2) 9))
|
|
|
|
(assert (= (f 5 4 3 2) (** 5 (** 4 (** 3 2))))))
|
|
|
|
; Exponentiation is right-associative.
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test /
|
|
|
|
(forbid (f))
|
|
|
|
(assert (= (f 2) .5))
|
|
|
|
(assert (= (f 3 2) 1.5))
|
|
|
|
(assert (= (f 8 2) 4))
|
|
|
|
(assert (= (f 8 2 2) 2))
|
|
|
|
(assert (= (f 8 2 2 2) 1)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test //
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 1))
|
|
|
|
(assert (= (f 16 5) 3))
|
|
|
|
(assert (= (f 8 2) 4))
|
|
|
|
(assert (= (f 8 2 2) 2)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test %
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 1))
|
|
|
|
(assert (= (f 16 5) 1))
|
|
|
|
(assert (= (f 8 2) 0))
|
|
|
|
(assert (= (f "aa %s bb" 15) "aa 15 bb"))
|
|
|
|
(assert (= (f "aa %s bb %s cc" (, "X" "Y")) "aa X bb Y cc"))
|
|
|
|
(forbid (f 1 2 3)))
|
|
|
|
|
|
|
|
|
2019-05-20 20:46:52 +02:00
|
|
|
(op-and-shadow-test @
|
2019-07-02 18:02:03 +02:00
|
|
|
(defclass C [object]
|
|
|
|
(defn __init__ [self content] (setv self.content content))
|
|
|
|
(defn __matmul__ [self other] (C (+ self.content other.content))))
|
2017-04-14 02:42:01 +02:00
|
|
|
(forbid (f))
|
|
|
|
(assert (do (setv c (C "a")) (is (f c) c)))
|
|
|
|
(assert (= (. (f (C "b") (C "c")) content) "bc"))
|
2019-05-20 20:46:52 +02:00
|
|
|
(assert (= (. (f (C "d") (C "e") (C "f")) content) "def")))
|
2017-04-14 02:42:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test <<
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 1))
|
|
|
|
(assert (= (f 0b101 2) 0b10100))
|
|
|
|
(assert (= (f 0b101 2 3) 0b10100000)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test >>
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 1))
|
|
|
|
(assert (= (f 0b101 2) 0b1))
|
|
|
|
(assert (= (f 0b101000010 2 3) 0b1010)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test &
|
|
|
|
(forbid (f))
|
|
|
|
; Binary AND has no identity element for the set of all
|
|
|
|
; nonnegative integers, because we can't have a 1 in every bit
|
|
|
|
; when there are infinitely many bits.
|
|
|
|
(assert (= (f 17) 17))
|
|
|
|
(assert (= (f 0b0011 0b0101) 0b0001))
|
|
|
|
(assert (= (f 0b111 0b110 0b100) 0b100)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test |
|
|
|
|
(assert (= (f) 0))
|
|
|
|
(assert (= (f 17) 17))
|
|
|
|
(assert (= (f 0b0011 0b0101) 0b0111))
|
|
|
|
(assert (= (f 0b11100 0b11000 0b10010) 0b11110)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test ^
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 17))
|
|
|
|
(assert (= (f 0b0011 0b0101) 0b0110))
|
|
|
|
(forbid (f 0b111 0b110 0b100)))
|
|
|
|
; `xor` with 3 arguments is kill (https://github.com/hylang/hy/pull/1102),
|
|
|
|
; so we don't allow `^` with 3 arguments, either.
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test ~
|
|
|
|
(forbid (f))
|
2018-02-28 01:21:42 +01:00
|
|
|
(assert (= (& (f 0b00101111) 0xFF)
|
|
|
|
0b11010000))
|
|
|
|
(forbid (f 0b00101111 0b11010000)))
|
2017-04-14 02:42:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test <
|
|
|
|
|
|
|
|
(forbid (f))
|
|
|
|
(assert (is (f "hello") True))
|
|
|
|
(assert (is (f 1 2) True))
|
|
|
|
(assert (is (f 2 1) False))
|
|
|
|
(assert (is (f 1 1) False))
|
|
|
|
(assert (is (f 1 2 3) True))
|
|
|
|
(assert (is (f 3 2 1) False))
|
|
|
|
(assert (is (f 1 3 2) False))
|
|
|
|
(assert (is (f 1 2 2) False))
|
|
|
|
|
|
|
|
; Make sure chained comparisons use `and`, not `&`.
|
|
|
|
; https://github.com/hylang/hy/issues/1191
|
2019-07-02 18:02:03 +02:00
|
|
|
(defclass C [object]
|
|
|
|
(defn __init__ [self x]
|
2017-04-14 02:42:01 +02:00
|
|
|
(setv self.x x))
|
2019-07-02 18:02:03 +02:00
|
|
|
(defn __lt__ [self other]
|
|
|
|
self.x))
|
2017-04-14 02:42:01 +02:00
|
|
|
(assert (= (f (C "a") (C "b") (C "c")) "b")))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test >
|
|
|
|
(forbid (f))
|
|
|
|
(assert (is (f "hello") True))
|
|
|
|
(assert (is (f 1 2) False))
|
|
|
|
(assert (is (f 2 1) True))
|
|
|
|
(assert (is (f 1 1) False))
|
|
|
|
(assert (is (f 1 2 3) False))
|
|
|
|
(assert (is (f 3 2 1) True))
|
|
|
|
(assert (is (f 1 3 2) False))
|
|
|
|
(assert (is (f 2 1 1) False)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test <=
|
|
|
|
(forbid (f))
|
|
|
|
(assert (is (f "hello") True))
|
|
|
|
(assert (is (f 1 2) True))
|
|
|
|
(assert (is (f 2 1) False))
|
|
|
|
(assert (is (f 1 1) True))
|
|
|
|
(assert (is (f 1 2 3) True))
|
|
|
|
(assert (is (f 3 2 1) False))
|
|
|
|
(assert (is (f 1 3 2) False))
|
|
|
|
(assert (is (f 1 2 2) True)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test >=
|
|
|
|
(forbid (f))
|
|
|
|
(assert (is (f "hello") True))
|
|
|
|
(assert (is (f 1 2) False))
|
|
|
|
(assert (is (f 2 1) True))
|
|
|
|
(assert (is (f 1 1) True))
|
|
|
|
(assert (is (f 1 2 3) False))
|
|
|
|
(assert (is (f 3 2 1) True))
|
|
|
|
(assert (is (f 1 3 2) False))
|
|
|
|
(assert (is (f 2 1 1) True)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test [= is]
|
|
|
|
(forbid (f))
|
2018-02-28 01:33:21 +01:00
|
|
|
|
2017-04-14 02:42:01 +02:00
|
|
|
(assert (is (f "hello") True))
|
2018-02-28 01:33:21 +01:00
|
|
|
|
|
|
|
; Unary comparison operators, despite always returning True,
|
|
|
|
; should evaluate their argument.
|
|
|
|
(setv p "a")
|
|
|
|
(assert (is (f (do (setv p "b") "hello")) True))
|
|
|
|
(assert (= p "b"))
|
|
|
|
|
2017-04-14 02:42:01 +02:00
|
|
|
(defclass C)
|
|
|
|
(setv x (get {"is" (C) "=" 0} f-name))
|
|
|
|
(setv y (get {"is" (C) "=" 1} f-name))
|
|
|
|
(assert (is (f x x) True))
|
|
|
|
(assert (is (f y y) True))
|
|
|
|
(assert (is (f x y) False))
|
|
|
|
(assert (is (f y x) False))
|
|
|
|
(assert (is (f x x x x x) True))
|
|
|
|
(assert (is (f x x x y x) False))
|
2018-02-28 01:33:21 +01:00
|
|
|
|
2017-04-14 02:42:01 +02:00
|
|
|
(setv n None)
|
|
|
|
(assert (is (f n None) True))
|
|
|
|
(assert (is (f n "b") False)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test [!= is-not]
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f "hello"))
|
|
|
|
(defclass C)
|
2018-02-26 01:44:20 +01:00
|
|
|
(setv x (get {"is-not" (C) "!=" 0} f-name))
|
|
|
|
(setv y (get {"is-not" (C) "!=" 1} f-name))
|
|
|
|
(setv z (get {"is-not" (C) "!=" 2} f-name))
|
2017-04-14 02:42:01 +02:00
|
|
|
(assert (is (f x x) False))
|
|
|
|
(assert (is (f y y) False))
|
|
|
|
(assert (is (f x y) True))
|
|
|
|
(assert (is (f y x) True))
|
|
|
|
(assert (is (f x y z) True))
|
|
|
|
(assert (is (f x x x) False))
|
|
|
|
(assert (is (f x y x) True))
|
|
|
|
(assert (is (f x x y) False)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test and
|
|
|
|
(assert (is (f) True))
|
|
|
|
(assert (= (f 17) 17))
|
|
|
|
(assert (= (f 1 2) 2))
|
|
|
|
(assert (= (f 1 0) 0))
|
|
|
|
(assert (= (f 0 2) 0))
|
|
|
|
(assert (= (f 0 0) 0))
|
|
|
|
(assert (= (f 1 2 3) 3))
|
|
|
|
(assert (= (f 1 0 3) 0))
|
|
|
|
(assert (= (f "a" 1 True [1]) [1])))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test or
|
|
|
|
(assert (is (f) None))
|
|
|
|
(assert (= (f 17) 17))
|
|
|
|
(assert (= (f 1 2) 1))
|
|
|
|
(assert (= (f 1 0) 1))
|
|
|
|
(assert (= (f 0 2) 2))
|
|
|
|
(assert (= (f 0 0) 0))
|
|
|
|
(assert (= (f 1 2 3) 1))
|
|
|
|
(assert (= (f 0 0 3) 3))
|
|
|
|
(assert (= (f "" None 0 False []) [])))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test not
|
|
|
|
(forbid (f))
|
|
|
|
(assert (is (f "hello") False))
|
|
|
|
(assert (is (f 0) True))
|
|
|
|
(assert (is (f None) True)))
|
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test [in not-in]
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f 3))
|
|
|
|
(assert (is (f 3 [1 2]) (!= f-name "in")))
|
|
|
|
(assert (is (f 2 [1 2]) (= f-name "in")))
|
2019-12-27 15:32:14 +01:00
|
|
|
(assert (is (f 2 [1 2] [[1 2] 3]) (= f-name "in")))
|
|
|
|
(assert (is (f 3 [1 2] [[2 2] 3]) (!= f-name "in"))))
|
2017-07-27 04:10:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
(op-and-shadow-test [get]
|
|
|
|
(forbid (f))
|
|
|
|
(forbid (f "hello"))
|
|
|
|
(assert (= (f "hello" 1) "e"))
|
|
|
|
(assert (= (f [[1 2 3] [4 5 6] [7 8 9]] 1 2) 6))
|
|
|
|
(assert (= (f {"x" {"y" {"z" 12}}} "x" "y" "z") 12)))
|
2019-07-24 19:32:05 +02:00
|
|
|
|
|
|
|
|
2019-12-26 18:25:25 +01:00
|
|
|
(defn test-chained-comparison []
|
|
|
|
(assert (cmp 2 = (+ 1 1) = (- 3 1)))
|
|
|
|
(assert (not (cmp 2 = (+ 1 1) = (+ 3 1))))
|
|
|
|
|
|
|
|
(assert (cmp 2 = 2 > 1))
|
|
|
|
(assert (cmp 2 = (+ 1 1) > 1))
|
|
|
|
(setv x 2)
|
|
|
|
(assert (cmp 2 = x > 1))
|
|
|
|
(assert (cmp 2 = x > (> 4 3)))
|
|
|
|
(assert (not (cmp (> 4 3) = x > 1)))
|
|
|
|
|
|
|
|
(assert (cmp 1 in [1] in [[1] [2 3]] not-in [5]))
|
|
|
|
(assert (not (cmp 1 in [1] not-in [[1] [2 3]] not-in [5]))))
|
|
|
|
|
|
|
|
|
2019-07-24 19:32:05 +02:00
|
|
|
(defn test-augassign []
|
2019-12-26 15:14:02 +01:00
|
|
|
(setv b 2 c 3 d 4)
|
|
|
|
(defmacro same-as [expr1 expr2 expected-value]
|
|
|
|
`(do
|
|
|
|
(setv a 4)
|
|
|
|
~expr1
|
|
|
|
(setv expr1-value a)
|
|
|
|
(setv a 4)
|
|
|
|
~expr2
|
|
|
|
(assert (= expr1-value a ~expected-value))))
|
|
|
|
(same-as (+= a b c d) (+= a (+ b c d)) 13)
|
|
|
|
(same-as (-= a b c d) (-= a (+ b c d)) -5)
|
|
|
|
(same-as (*= a b c d) (*= a (* b c d)) 96)
|
|
|
|
(same-as (**= a b c) (**= a (** b c)) 65,536)
|
|
|
|
(same-as (/= a b c d) (/= a (* b c d)) (/ 1 6))
|
|
|
|
(same-as (//= a b c d) (//= a (* b c d)) 0)
|
|
|
|
(same-as (<<= a b c d) (<<= a (+ b c d)) 0b10_00000_00000)
|
|
|
|
(same-as (>>= a b c d) (>>= a (+ b c d)) 0)
|
|
|
|
(same-as (&= a b c d) (&= a (& b c d)) 0)
|
|
|
|
(same-as (|= a b c d) (|= a (| b c d)) 0b111)
|
|
|
|
|
|
|
|
(defclass C [object]
|
|
|
|
(defn __init__ [self content] (setv self.content content))
|
|
|
|
(defn __matmul__ [self other] (C (+ self.content other.content))))
|
|
|
|
(setv a (C "a") b (C "b") c (C "c") d (C "d"))
|
|
|
|
(@= a b c d)
|
|
|
|
(assert (= a.content "abcd"))
|
|
|
|
(setv a (C "a"))
|
|
|
|
(@= a (@ b c d))
|
|
|
|
(assert (= a.content "abcd"))
|
|
|
|
|
|
|
|
(setv a 15)
|
|
|
|
(%= a 9)
|
|
|
|
(assert (= a 6))
|
|
|
|
|
|
|
|
(setv a 0b1100)
|
|
|
|
(^= a 0b1010)
|
|
|
|
(assert (= a 0b0110)))
|