(use-modules
 ;; SRFI 60: procedures for treating integers as bits
 (srfi srfi-60)
 ;; SRFI 64: unit tests
 (srfi srfi-64)
 ;; the module to test
 (bit-integer-operations))


(test-begin "bit-integer-operations-test")

(test-group
 "make-bit-integer"
 (test-eqv #b00000000
   (make-bit-integer 8 #f))
 (test-eqv #b0000000000000000
   (make-bit-integer 16 #f))
 (test-eqv #b0
   (make-bit-integer 5 0))
 (test-eqv #b1
   (make-bit-integer 1 #t))
 (test-eqv #b1
   (make-bit-integer 1 1))
 (test-eqv #b111111
   (make-bit-integer 6 1))
 (test-eqv #b111111
   (make-bit-integer 6 #t)))

(test-group
 "max-int"
 (test-eqv 2417851639229258349412351 (max-int 81))
 (test-eqv 18446744073709551615 (max-int 64))
 (test-eqv 4294967295 (max-int 32))
 (test-eqv 0 (max-int 0)))

(test-group
 "val-of-bit-pos"
 (test-eq 4294967296 (val-of-bit-pos 32))
 (test-eq 1024 (val-of-bit-pos 10))
 (test-eq 32 (val-of-bit-pos 5))
 (test-eq 1 (val-of-bit-pos 0))
 (test-eqv (/ 1 2) (val-of-bit-pos -1))
 (test-eqv (/ 1 16) (val-of-bit-pos -4)))

(test-group
 "bit-mask-of-pos"
 (test-eq #b00001000 (bit-mask-of-pos 3))
 (test-eq #b00010000 (bit-mask-of-pos 4)))

(test-group
 "get-bit-value-at-pos"
 (test-eq 1 (get-bit-value-at-pos #b10101010 3))
 (test-eq 0 (get-bit-value-at-pos #b11100 1)))

(test-group
 "generic-binary-bit-integer-operation"
 (test-eq 4
   (generic-binary-bit-integer-operation
    12
    4
    (λ (prev-res pos bit1 bit2)
      (+ prev-res
         (* (* bit1 bit2)
            (val-of-bit-pos pos))))))
 (test-eq #b0010100
   (generic-binary-bit-integer-operation
    #b0110000
    #b0101100
    (λ (prev-res pos bit1 bit2)
      (+ prev-res
         (* (if (or (= bit1 1) (= bit2 1)) 1 0)
            (if (= (remainder pos 2) 0)
                (val-of-bit-pos pos)
                0)))))))

(test-group
 "display-bit-integer"
 (test-equal "01101010"
   (call-with-output-string
     (λ (port)
       (display-bit-integer #b1101010
                            port
                            #:newline #f
                            #:padding-length 8
                            #:padding-char #\0))))

 (test-equal "_________1101010\n"
   (call-with-output-string
     (λ (port)
       (display-bit-integer #b1101010
                            port
                            #:newline #t
                            #:padding-length 16
                            #:padding-char #\_)))))

(test-group
 "display-multiple-bit-integers"
 (test-equal (string-append "0001\n"
                            "0010\n"
                            "0100\n"
                            "1000\n"
                            "1011\n")
   (call-with-output-string
     (λ (port)
       (display-multiple-bit-integers '(1 2 4 8 11)
                                      port))))

 (test-equal (string-append "AAA1\n"
                            "AA10\n"
                            "A100\n"
                            "1000\n"
                            "1011\n")
   (call-with-output-string
     (λ (port)
       (display-multiple-bit-integers '(1 2 4 8 11)
                                      port
                                      #:padding-char #\A)))))

(test-group
 "string->bit-integer"
 (test-eq 254
   (string->bit-integer "11111110"))
 (test-eq 246
   (string->bit-integer "11110110"))
 (test-eq 3
   (string->bit-integer "11"))
 (test-eq 55
   (string->bit-integer "00110111")))

(test-end "bit-integer-operations-test")
