#lang racket/base

(require typed/rackunit)

(module defs typed/racket/base
  (provide (all-defined-out))

  (: foo0k (case-> ([#:kw Real] -> Real)))
  (define (foo0k #:kw [kw 0])
    kw)

  (: foo01k (case-> ([#:kw Real] -> Real)
                    (Real [#:kw Real] -> Real)))
  (define (foo01k [x 0] #:kw [kw 0])
    (+ x kw))

  (: foo012k (case-> ([#:kw Real] -> Real)
                     (Real [#:kw Real] -> Real)
                     (Real Real [#:kw Real] -> Real)))
  (define (foo012k [x 0] [y 0] #:kw [kw 0])
    (+ x y kw))

  (: foo12k (case-> (Real [#:kw Real] -> Real)
                    (Real Real [#:kw Real] -> Real)))
  (define (foo12k x [y 0] #:kw [kw 0])
    (+ x y kw))

  (: foo123k (case-> (Real [#:kw Real] -> Real)
                     (Real Real [#:kw Real] -> Real)
                     (Real Real Real [#:kw Real] -> Real)))
  (define (foo123k x [y 0] [z 0] #:kw [kw 0])
    (+ x y z kw))

  (: foo23k (case-> (Real Real [#:kw Real] -> Real)
                    (Real Real Real [#:kw Real] -> Real)))
  (define (foo23k x y [z 0] #:kw [kw 0])
    (+ x y z kw))

  (: foo234k (case-> (Real Real [#:kw Real] -> Real)
                     (Real Real Real [#:kw Real] -> Real)
                     (Real Real Real Real [#:kw Real] -> Real)))
  (define (foo234k x y [z 0] [w 0] #:kw [kw 0])
    (+ x y z w kw))
  )

(require 'defs)

(void foo0k)
(void foo01k)
(void foo12k)

(check-equal? (foo0k) 0)
(check-exn exn:fail:contract? (λ () (foo0k 1)))
(check-equal? (foo0k #:kw 10) 10)
(check-exn exn:fail:contract? (λ () (foo0k 1 #:kw 10)))

(check-equal? (foo01k) 0)
(check-equal? (foo01k 1) 1)
(check-exn exn:fail:contract? (λ () (foo01k 1 1)))
(check-equal? (foo01k #:kw 10) 10)
(check-equal? (foo01k 1 #:kw 10) 11)
(check-exn exn:fail:contract? (λ () (foo01k 1 1 #:kw 10)))

(check-exn exn:fail:contract? (λ () (foo12k)))
(check-equal? (foo12k 1) 1)
(check-equal? (foo12k 1 1) 2)
(check-exn exn:fail:contract? (λ () (foo12k 1 1 1)))
(check-exn exn:fail:contract? (λ () (foo12k #:kw 10)))
(check-equal? (foo12k 1 #:kw 10) 11)
(check-equal? (foo12k 1 1 #:kw 10) 12)
(check-exn exn:fail:contract? (λ () (foo12k 1 1 1 #:kw 10)))

(void foo012k)
(void foo123k)
(void foo23k)
(void foo234k)

(check-equal? (foo012k) 0)
(check-equal? (foo012k 1) 1)
(check-equal? (foo012k 1 1) 2)
(check-exn exn:fail:contract? (λ () (foo012k 1 1 1)))
(check-equal? (foo012k #:kw 10) 10)
(check-equal? (foo012k 1 #:kw 10) 11)
(check-equal? (foo012k 1 1 #:kw 10) 12)
(check-exn exn:fail:contract? (λ () (foo012k 1 1 1 #:kw 10)))

(check-exn exn:fail:contract? (λ () (foo123k)))
(check-equal? (foo123k 1) 1)
(check-equal? (foo123k 1 1) 2)
(check-equal? (foo123k 1 1 1) 3)
(check-exn exn:fail:contract? (λ () (foo123k 1 1 1 1)))
(check-exn exn:fail:contract? (λ () (foo123k #:kw 10)))
(check-equal? (foo123k 1 #:kw 10) 11)
(check-equal? (foo123k 1 1 #:kw 10) 12)
(check-equal? (foo123k 1 1 1 #:kw 10) 13)
(check-exn exn:fail:contract? (λ () (foo123k 1 1 1 1 #:kw 10)))

(check-exn exn:fail:contract? (λ () (foo23k)))
(check-exn exn:fail:contract? (λ () (foo23k 1)))
(check-equal? (foo23k 1 1) 2)
(check-equal? (foo23k 1 1 1) 3)
(check-exn exn:fail:contract? (λ () (foo23k 1 1 1 1)))
(check-exn exn:fail:contract? (λ () (foo23k #:kw 10)))
(check-exn exn:fail:contract? (λ () (foo23k 1 #:kw 10)))
(check-equal? (foo23k 1 1 #:kw 10) 12)
(check-equal? (foo23k 1 1 1 #:kw 10) 13)
(check-exn exn:fail:contract? (λ () (foo23k 1 1 1 1 #:kw 10)))

(check-exn exn:fail:contract? (λ () (foo234k)))
(check-exn exn:fail:contract? (λ () (foo234k 1)))
(check-equal? (foo234k 1 1) 2)
(check-equal? (foo234k 1 1 1) 3)
(check-equal? (foo234k 1 1 1 1) 4)
(check-exn exn:fail:contract? (λ () (foo234k 1 1 1 1 1)))
(check-exn exn:fail:contract? (λ () (foo234k #:kw 10)))
(check-exn exn:fail:contract? (λ () (foo234k 1 #:kw 10)))
(check-equal? (foo234k 1 1 #:kw 10) 12)
(check-equal? (foo234k 1 1 1 #:kw 10) 13)
(check-equal? (foo234k 1 1 1 1 #:kw 10) 14)
(check-exn exn:fail:contract? (λ () (foo234k 1 1 1 1 1 #:kw 10)))
