(* ocamlfind ocamlopt -linkpkg -package react -g -I ../ ../wrapping.cmxa test_wrapping.ml -o test_wrapping *)
let _ = Printexc.record_backtrace true

(*** simple wrap test ***)

type a =
  { a : float;
    a_wrap : a Ocsigen_wrap.wrapper; }

let a_wrap () = Ocsigen_wrap.create_wrapper 
    (fun t -> { a = t.a +. 1.; a_wrap = Ocsigen_wrap.empty_wrapper })

let a i = { a = i; a_wrap = a_wrap () }

let va = a 3.14

let _,v = Ocsigen_wrap.wrap va
let () = assert (v.a -. 4.14 < 0.0001)

(*** deep wrap test ***)

let va = [[[[[[1,[3.1,a 3.14]],a 35.1]]]]]

let _,_ = Ocsigen_wrap.wrap va

(*** multiple wrap test ***)

type b =
  { b : string;
    ba : a;
    b' : string;
    b_wrap : b Ocsigen_wrap.wrapper; }

let b_wrap () = Ocsigen_wrap.create_wrapper 
    (fun t -> t.b, t.ba )

let b s f = { b = s; b' = s; b_wrap = b_wrap (); ba = a f }

let tst_string = "test"

let vb = b tst_string 3.14

let _,vb' = Ocsigen_wrap.wrap vb

let _ = assert (
  let (t,f) = Obj.magic (vb') in
  t == tst_string && ( f -. 4.14 < 0.0001 ))

let _,vb'' = Ocsigen_wrap.wrap [2,[1.,[vb,4,ref 0],ref 42]]

let () =
  match vb'' with
  | [2,[1.,[vb',4,{ contents = 0}],{ contents = 42}]] ->
    assert (
      let (t,f) = Obj.magic (vb') in
      t == tst_string && ( f -. 4.14 < 0.0001 ))
  | _ -> assert false


(*** create wrap during wrap test ***)

let b'_wrap () = Ocsigen_wrap.create_wrapper 
    (fun t -> t.b, a 1.2 )

let b' s f = { b = s; b' = s; b_wrap = b'_wrap (); ba = a f }

let vb' = b' "test" 3.14

let _,vb'' = Ocsigen_wrap.wrap vb'

let () =
  match (Obj.magic vb'') with
  | (x,y) -> 
    assert (x == vb'.b);
    assert (y.a -. 4.14 < 0.0001 )


(*** big value copy ***)

let ( -- ) x y =
  let rec aux y x acc =
    if x > y then acc else aux (y-1) x (y::acc)
  in
  aux y x []
(*
type l =
    | A
    | L of l * int

let ( -- ) x y =
  let rec aux y x acc =
    if x > y then acc else aux (y-1) x (L (acc,y))
  in
  aux y x A

let _ = Marshal.to_string (0--50000000)
*)
let v = (0--80000)
(* it cannot grow much bigger than that, On systems with a small
   stack, it could die with stack overflow *)
let _,v' = Ocsigen_wrap.wrap v

let () = assert (v' = v)

(*** simple wrap weak test ***)

let d = Weak.create 1
let d_val = (Some (ref 0))
let _ = Weak.set d 0 d_val

type d =
  { da : int;
    dw : int Weak.t;
    dm : d Ocsigen_wrap.wrapper; }

let d_wrap () = Ocsigen_wrap.create_wrapper (fun {da;dw} -> Weak.get dw 0,da)

let _,d' = Ocsigen_wrap.wrap (1,d,d_wrap ())

let () = assert (Obj.magic d' = (d_val,1))

(*** simple wrap react test ***)

let r',push = React.E.create ()
let r = React.E.map (fun i -> i+1) r'

let c a r w = (a,r,w)
let c_wrap () = Ocsigen_wrap.create_wrapper (fun (a,r,w) -> a)

let _,c' = Ocsigen_wrap.wrap (c 1 r (c_wrap ()))
let () = assert (Obj.magic c' = 1)

(*** Eliom_react like test ***)

let r',push = React.E.create ()
let r = React.E.map (fun i -> i+1) r'

type toto =
  { a : float;
    mtoto : toto Ocsigen_wrap.wrapper; }

type t =
  { v1 : int;
    v2 : toto;
    v3 : int React.event;
    mt : t Ocsigen_wrap.wrapper; }

let i = ref 0

let mtoto () = Ocsigen_wrap.create_wrapper (fun t -> incr i; string_of_float t.a, !i)
let mt () = Ocsigen_wrap.create_wrapper (fun t -> incr i; t.v2)

let toto i = { a = i; mtoto = mtoto () }
let t i b = { v1 = i; v2 = b; v3 = r; mt = mt () }

let vtoto = toto 3.14
let vt = t 42 vtoto

let _,v' = Ocsigen_wrap.wrap vtoto
let _,v' = Ocsigen_wrap.wrap vt

(*** closure copy test ***)

type t1 =
  { t1a : float;
    t1mark : t1 Ocsigen_wrap.wrapper; }

type t2 =
  { t2t1 : t1;
    t2f : (int ref -> unit) option;
    t2mark : t2 Ocsigen_wrap.wrapper; }

let r1 = ref 13
let r2 = ref 42
let r3 = ref 88

let t1mark () = Ocsigen_wrap.create_wrapper (fun t -> incr r1; { t1a = 3.14; t1mark = Ocsigen_wrap.empty_wrapper } )
let t2mark () = Ocsigen_wrap.create_wrapper (fun t -> 
    (match t.t2f with
     | Some f -> f r2;
     | None -> assert false);
    { t with t2f = None; t2mark = Ocsigen_wrap.empty_wrapper } )

let t1 = { t1a = 1.1; t1mark = t1mark () }
let t2 = { t2t1 = t1; t2f = Some (fun r -> incr r; incr r3); t2mark = t2mark () }

let _,t2' = Ocsigen_wrap.wrap (Obj.repr t2)
let _,t1' = Ocsigen_wrap.wrap (Obj.repr t1)


let _ =
  assert (!r1 = 15);
  assert (!r2 = 43);
  assert (!r3 = 89)
