|
|
|
#lang debug racket/base
|
|
|
|
(require rackunit racket/dict
|
|
|
|
racket/class
|
|
|
|
"../helper.rkt"
|
|
|
|
"../struct.rkt"
|
|
|
|
"../string.rkt"
|
|
|
|
"../pointer.rkt"
|
|
|
|
"../number.rkt"
|
|
|
|
"../generic.rkt"
|
|
|
|
sugar/unstable/dict)
|
|
|
|
|
|
|
|
#|
|
|
|
|
approximates
|
|
|
|
https://github.com/mbutterick/restructure/blob/master/test/Struct.coffee
|
|
|
|
|#
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: decode into an object"
|
|
|
|
(parameterize ([current-input-port (open-input-bytes #"\x05roxyb\x15")])
|
|
|
|
(check-equal?
|
|
|
|
(decode (+xstruct 'name (+xstring #:length uint8) 'age uint8))
|
|
|
|
(mhasheq 'name "roxyb" 'age 21))))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: decode with process hook"
|
|
|
|
(parameterize ([current-input-port (open-input-bytes #"\x05roxyb\x20")])
|
|
|
|
(define struct (+xstruct #:post-decode (λ (o) (dict-set! o 'canDrink (>= (dict-ref o 'age) 21)) o)
|
|
|
|
'name (+xstring #:length uint8) 'age uint8))
|
|
|
|
(check-equal? (decode struct)
|
|
|
|
(mhasheq 'name "roxyb" 'age 32 'canDrink #t))))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: decode supports function keys"
|
|
|
|
(parameterize ([current-input-port (open-input-bytes #"\x05roxyb\x20")])
|
|
|
|
(define struct (+xstruct 'name (+xstring #:length uint8) 'age uint8 'canDrink (λ (o) (>= (dict-ref o 'age) 21))))
|
|
|
|
(check-equal? (decode struct)
|
|
|
|
(mhasheq 'name "roxyb" 'age 32 'canDrink #t))))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: compute the correct size"
|
|
|
|
(check-equal? (size (+xstruct 'name (+xstring #:length uint8) 'age uint8)
|
|
|
|
(hasheq 'name "roxyb" 'age 32)) 7))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: compute the correct size with pointers"
|
|
|
|
(check-equal? (size (+xstruct 'name (+xstring #:length uint8)
|
|
|
|
'age uint8
|
|
|
|
'ptr (+xpointer #:type (+xstring #:length uint8)))
|
|
|
|
(mhash 'name "roxyb" 'age 21 'ptr "hello")) 14))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: get the correct size when no value is given"
|
|
|
|
(check-equal? (size (+xstruct 'name (+xstring 4) 'age uint8)) 5))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: throw when getting non-fixed length size and no value is given"
|
|
|
|
(check-exn exn:fail:contract? (λ () (size (+xstruct 'name (+xstring #:length uint8) 'age uint8)))))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: encode objects to buffers"
|
|
|
|
(parameterize ([current-input-port (open-input-bytes #"\x05roxyb\x15")])
|
|
|
|
(check-equal? (decode (+xstruct 'name (+xstring #:length uint8) 'age uint8))
|
|
|
|
(mhasheq 'name "roxyb" 'age 21))))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: support pre-encode hook"
|
|
|
|
(parameterize ([current-output-port (open-output-bytes)])
|
|
|
|
(define struct (+xstruct #:pre-encode (λ (val)
|
|
|
|
(dict-set! val 'nameLength (string-length (dict-ref val 'name))) val)
|
|
|
|
'nameLength uint8
|
|
|
|
'name (+xstring 'nameLength)
|
|
|
|
'age uint8))
|
|
|
|
(encode struct (mhasheq 'name "roxyb" 'age 21))
|
|
|
|
(check-equal? (get-output-bytes (current-output-port)) #"\x05roxyb\x15")))
|
|
|
|
|
|
|
|
(test-case
|
|
|
|
"struct: encode pointer data after structure"
|
|
|
|
(parameterize ([current-output-port (open-output-bytes)])
|
|
|
|
(define struct (+xstruct 'name (+xstring #:length uint8)
|
|
|
|
'age uint8
|
|
|
|
'ptr (+xpointer #:type (+xstring #:length uint8))))
|
|
|
|
(encode struct (hasheq 'name "roxyb" 'age 21 'ptr "hello"))
|
|
|
|
(check-equal? (get-output-bytes (current-output-port)) #"\x05roxyb\x15\x08\x05hello")))
|