import
  unittest, times, eth/rlp, util/json_testing

type
  Transaction = object
    amount: int
    time: DateTime
    sender: string
    receiver: string

  Foo = object
    x: uint64
    y: string
    z: seq[int]

  Bar = object
    b: string
    f: Foo

  CompressedFoo = object

  CustomSerialized = object
    customFoo {.rlpCustomSerialization.}: Foo
    ignored {.rlpIgnore.}: int

rlpFields Foo,
  x, y, z

rlpFields Transaction,
  sender, receiver, amount

proc default(T: typedesc): T = discard

proc append*(rlpWriter: var RlpWriter, holder: CustomSerialized, f: Foo) =
  rlpWriter.append(f.x)
  rlpWriter.append(f.y.len)
  rlpWriter.append(holder.ignored)

proc read*(rlp: var Rlp, holder: var CustomSerialized, T: type Foo): Foo =
  result.x = rlp.read(uint64)
  result.y = newString(rlp.read(int))
  holder.ignored = rlp.read(int) * 2

test "encoding and decoding an object":
  var originalBar = Bar(b: "abracadabra",
                        f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))

  var bytes = encode(originalBar)
  var r = rlpFromBytes(bytes.toRange)
  var restoredBar = r.read(Bar)

  check:
    originalBar == restoredBar

  var t1 = Transaction(time: now(), amount: 1000, sender: "Alice", receiver: "Bob")
  bytes = encode(t1)
  var t2 = bytes.decode(Transaction)

  check:
    bytes.hexRepr == "cd85416c69636583426f628203e8" # verifies that Alice comes first
    t2.time == default(DateTime)
    t2.sender == "Alice"
    t2.receiver == "Bob"
    t2.amount == 1000

test "custom field serialization":
  var origVal = CustomSerialized(customFoo: Foo(x: 10'u64, y: "y", z: @[]), ignored: 5)
  var bytes = encode(origVal)
  var r = rlpFromBytes(bytes.toRange)
  var restored = r.read(CustomSerialized)

  check:
    origVal.customFoo.x == restored.customFoo.x
    origVal.customFoo.y.len == restored.customFoo.y.len
    restored.ignored == 10

test "RLP fields count":
  check:
    Bar.rlpFieldsCount == 2
    Foo.rlpFieldsCount == 3
    Transaction.rlpFieldsCount == 3