nim-ffi/tests/unit/test_meta.nim
2026-05-19 12:43:34 +02:00

57 lines
2.3 KiB
Nim

## Unit tests for the AST helpers used by the FFI macro.
## The identifier-casing helpers used to live here too; they now have their
## own module and test file (`test_string_helpers.nim`).
import unittest
import std/[macros, strutils]
import ffi/internal/ffi_macro
suite "unpackReqField":
## `unpackReqField` builds AST via `std/macros` helpers (`ident`, `newDotExpr`,
## `newLetStmt`, etc.) which are compile-time magics. The tests therefore run
## as `static:` blocks — a failed `doAssert` becomes a compile-time error, so
## a broken helper aborts the build before the test binary is produced.
## Whitespace in AST repr is normalised so the assertions are layout-stable.
proc normalise(s: string): string {.compileTime.} =
var buf = ""
var prevSpace = true
for c in s:
if c in {' ', '\t', '\n', '\r'}:
if not prevSpace:
buf.add(' ')
prevSpace = true
else:
buf.add(c)
prevSpace = false
return buf.strip()
test "non-cstring field unpacks as plain assignment":
static:
let node = unpackReqField(ident("count"), ident("int"), ident("decoded"))
doAssert normalise(node.repr) == "let count = decoded.count"
test "cstring field unpacks with .cstring cast":
static:
let node = unpackReqField(ident("message"), ident("cstring"), ident("decoded"))
doAssert normalise(node.repr) == "let message: cstring = decoded.message.cstring"
test "non-cstring (string) does NOT add the .cstring cast":
static:
let node = unpackReqField(ident("name"), ident("string"), ident("decoded"))
let r = normalise(node.repr)
doAssert r == "let name = decoded.name"
doAssert ".cstring" notin r
test "non-cstring complex type passes through unchanged":
# Generic / bracket / dot expressions are not nnkIdent, so the cstring
# branch must not fire even if the type's textual repr contains "cstring".
static:
let userType = nnkBracketExpr.newTree(ident("seq"), ident("int"))
let node = unpackReqField(ident("xs"), userType, ident("decoded"))
doAssert normalise(node.repr) == "let xs = decoded.xs"
test "decoded identifier is used verbatim":
static:
let node = unpackReqField(ident("delayMs"), ident("int"), ident("myDecodedReq"))
doAssert normalise(node.repr) == "let delayMs = myDecodedReq.delayMs"