#lang scheme/base
(require "enumeration.ss"
"test-base.ss")
(define-enum vehicle
(car boat plane))
(define-enum number
([one 1 "one"]
[two 2 "two"]
[three 3 "three"]))
(define-enum option
([a 1 "item 1"]
[b 2 "item 2"]
[c 3 "item 3"]))
(define-struct struct (val) #:transparent)
(define-enum structs
([one (make-struct 'a) "one"]
[two (make-struct 'b) "two"]
[three (make-struct 'c) "three"]))
(define-enum underscores
([a _ "one"]
[b _ "two"]
[c _ "three"]))
(define-enum titles
([mr "Mr"]
[mrs "Mrs"]
[miss "Miss"])
#:equality-test equal?)
(define/provide-test-suite enumeration-tests
(test-case "vehicle"
(check-pred enum? vehicle)
(check-equal? (enum-values vehicle) '(car boat plane))
(check-equal? (enum-pretty-values vehicle) '("car" "boat" "plane"))
(check-equal? (enum->string vehicle) "car, boat, plane")
(check-equal? (enum->pretty-string vehicle) "car, boat, plane")
(check-equal? (vehicle car) 'car)
(check-equal? (vehicle boat) 'boat)
(check-equal? (vehicle plane) 'plane)
(check-equal? (enum-list vehicle boat plane) '(boat plane))
(check-equal? (enum-complement vehicle boat plane) '(car))
(check-true (enum-value? vehicle 'car))
(check-true (enum-value? vehicle 'boat))
(check-true (enum-value? vehicle 'plane))
(check-false (enum-value? vehicle 'lemon)))
(test-case "option"
(check-pred enum? option)
(check-equal? (enum-values option) '(1 2 3))
(check-equal? (enum-pretty-values option) '("item 1" "item 2" "item 3"))
(check-equal? (enum->string option) "1, 2, 3")
(check-equal? (enum->pretty-string option) "item 1, item 2, item 3")
(check-equal? (option a) 1)
(check-equal? (option b) 2)
(check-equal? (option c) 3)
(check-true (enum-value? option 1))
(check-true (enum-value? option 2))
(check-true (enum-value? option 3))
(check-false (enum-value? option 'a))
(check-false (enum-value? option 'b))
(check-false (enum-value? option 'c)))
(test-case "title"
(check-pred enum? titles)
(check-equal? (enum-values titles) '("Mr" "Mrs" "Miss"))
(check-equal? (enum-pretty-values titles) '("mr" "mrs" "miss"))
(check-equal? (enum->string titles) "Mr, Mrs, Miss")
(check-equal? (enum->pretty-string titles) "mr, mrs, miss")
(check-equal? (titles mr) "Mr")
(check-equal? (titles mrs) "Mrs")
(check-equal? (titles miss) "Miss")
(check-true (enum-value? titles "Mr"))
(check-true (enum-value? titles "Mrs"))
(check-true (enum-value? titles "Miss"))
(check-false (enum-value? titles 'Mr))
(check-false (enum-value? titles "mrs")))
(test-case "structs"
(check-true (enum-value? structs (structs one)))
(check-false (enum-value? structs (make-struct 'a))))
(test-case "underscores"
(check-equal? (enum-list underscores a b c) '(a b c))
(check-equal? (enum-complement underscores a b c) null)
(check-equal? (enum-prettify underscores (underscores a)) "one"))
(test-case "enum-value+false?"
(check-true (enum-value? vehicle (vehicle car)))
(check-false (enum-value? vehicle #f))
(check-true (enum-value+false? vehicle (vehicle car)))
(check-true (enum-value+false? vehicle #f))
(check-true (enum-value+false? titles "Mr"))
(check-false (enum-value+false? titles 'Mr)))
(test-case "enum->[pretty-]string with separator specified"
(check-equal? (enum->string vehicle ":") "car:boat:plane")
(check-equal? (enum->pretty-string vehicle ":") "car:boat:plane")
(check-equal? (enum->string titles ":") "Mr:Mrs:Miss")
(check-equal? (enum->pretty-string titles ":") "mr:mrs:miss"))
(test-case "enum-case"
(check-equal? (enum-case option 1 [(a) 10 100] [(b) 20 200] [(c) 30 300]) 100)
(check-equal? (enum-case option 2 [(a) 10 100] [(b) 20 200] [(c) 30 300]) 200)
(check-equal? (enum-case option 3 [(a) 10 100] [(b) 20 200] [(c) 30 300]) 300)
(check-exn exn:fail? (cut enum-case option 'a [(a) 100] [(b) 200] [(c) 300]))
(check-equal? (enum-case option 1 [(a) 10 100] [(b) 20 200] [else 30 300]) 100)
(check-equal? (enum-case option 2 [(a) 10 100] [(b) 20 200] [else 30 300]) 200)
(check-equal? (enum-case option 3 [(a) 10 100] [(b) 20 200] [else 30 300]) 300)
(check-equal? (enum-case option 'a [(a) 100] [(b) 200] [else 300]) 300)
(check-equal? (enum-case option 1 [(a) 10 100] [(b c) 20 200]) 100)
(check-equal? (enum-case option 2 [(a) 10 100] [(b c) 20 200]) 200)
(check-equal? (enum-case option 3 [(a) 10 100] [(b c) 20 200]) 200)
(check-exn exn:fail? (cut enum-case option 'a [(a) 100] [(b c) 200]))
(check-equal? (enum-case structs (structs one) [(one) 1] [(two) 2] [(three) 3] [else 4]) 1)
(check-equal? (enum-case structs (make-struct 'a) [(one) 1] [(two) 2] [(three) 3] [else 4]) 4)
(check-equal? (enum-case titles "Mr" [(mr) 1] [(mrs) 2] [(miss) 3]) 1)
(check-equal? (enum-case titles "Mrs" [(mr) 1] [(mrs) 2] [(miss) 3]) 2)
(check-equal? (enum-case titles "Miss" [(mr) 1] [(mrs) 2] [(miss) 3]) 3)
(check-exn exn:fail? (cut enum-case titles 'Mr [(mr) 1] [(mrs) 2] [(miss) 3]))
(check-exn exn:fail? (cut enum-case titles "mr" [(mr) 1] [(mrs) 2] [(miss) 3])))
(test-case "enum-lambda"
(let ([proc (enum-lambda option [(a) 10 100] [(b) 20 200] [(c) 30 300])])
(check-equal? (proc 1) 100)
(check-equal? (proc 2) 200)
(check-equal? (proc 3) 300)
(check-exn exn:fail? (cut proc 'a)))
(let ([proc (enum-lambda titles [(mr) 10 100] [(mrs) 20 200] [(miss) 30 300])])
(check-equal? (proc "Mr") 100)
(check-equal? (proc "Mrs") 200)
(check-equal? (proc "Miss") 300)
(check-exn exn:fail? (cut proc 'Mr))))
(test-case "in-enum"
(check-equal? (for/list ([val (in-enum option)]) val) (list 1 2 3))
(check-equal? (for/list ([val (in-enum option a c)]) val) (list 1 3))
(check-equal? (for/list ([val (in-enum titles)]) val) (list "Mr" "Mrs" "Miss"))
(check-equal? (for/list ([val (in-enum titles mr miss)]) val) (list "Mr" "Miss")))
(test-case "in-enum/pretty"
(check-equal? (for/list ([val (in-enum/pretty option)]) val) (list "item 1" "item 2" "item 3"))
(check-equal? (for/list ([val (in-enum/pretty option a c)]) val) (list "item 1" "item 3"))
(check-equal? (for/list ([val (in-enum/pretty titles)]) val) (list "mr" "mrs" "miss"))
(check-equal? (for/list ([val (in-enum/pretty titles mr miss)]) val) (list "mr" "miss"))))