Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file test_legacy_bonsai.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674open!Coreopen!Import(* We need to fake the source-code position because this test is run in
two files with different names
In particular, we can't just use [print_s ~hide_positions:true] because that
only hides line and column numbers, but includes the file name. *)letdummy_source_code_position=Source_code_position.{pos_fname="file_name.ml";pos_lnum=0;pos_bol=0;pos_cnum=0};;letrun_test~(component:_Bonsai.Arrow_deprecated.t)~initial_input~f=letdrivercomponent=Driver.createcomponent~initial_input~clock:Incr.clockinf(drivercomponent);;moduleHelpers=structincludeHelpersletmake~driver=Helpers.make~driverletmake_string~driver=Helpers.make_string~driverletmake_string_with_inject~driver=Helpers.make_string_with_inject~driverletmake_with_inject~driver=Helpers.make_with_inject~driverendmoduleCounter_component=structmoduleInput=UnitmoduleModel=IntmoduleAction=structtypet=|Increment|Decrement[@@derivingsexp_of]endmoduleResult=structtypet=string*(Action.t->unitEffect.t)endletapply_action~inject:_~schedule_event:_()model:Action.t->Model.t=function|Increment->model+1|Decrement->model-1;;letcompute~inject()m=Int.to_stringm,injectletname="counter-component"endlet%expect_test"enum"=letopenBonsai.Arrow_deprecated.Infixinletcomponent=Bonsai.Arrow_deprecated.enum(moduleBool)~which:Tuple2.get1~handle:(function|true->Tuple2.get2@>>Bonsai.Arrow_deprecated.pure~f:(sprintf"true %d")|false->Tuple2.get2@>>Bonsai.Arrow_deprecated.pure~f:(sprintf"false %d"))inrun_test~component~initial_input:(true,5)~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string~driverinH.show();[%expect{| true 5 |}];H.set_input(true,10);[%expect{| true 10 |}];H.set_input(false,10);[%expect{| false 10 |}];H.set_input(false,5);[%expect{| false 5 |}]);;let%expect_test"enum with action handling `Warn"=letopenBonsai.Arrow_deprecated.InfixinletmoduleAction=structtypet=|OuterofCounter_component.Action.t|InnerofCounter_component.Action.tendinletcomponent=let%map.Bonsai.Arrow_deprecated(result,inject_inner),inject_outer=Bonsai.Arrow_deprecated.of_module(moduleCounter_component)~default_model:1>>>Bonsai.Arrow_deprecated.first(Bonsai.Arrow_deprecated.enum(moduleBool)~which:(fundigit->Int.of_stringdigitmod3=0)~handle:(function|false->Fn.ignore@>>Bonsai.Arrow_deprecated.of_module(moduleCounter_component)~default_model:0>>|Tuple2.map_fst~f:(sprintf"counter %s")|true->Bonsai.Arrow_deprecated.pure~f:(funs->letview=sprintf"pure %s"sinletinj_=failwith"can't raise actions out of this one"inview,inj)))in(result,function|Action.Outera->inject_outera|Innera->inject_innera)inrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect"counter 0"];H.do_actions[InnerIncrement];[%expect"counter 1"];H.do_actions[InnerIncrement];[%expect"counter 2"];H.do_actions[OuterIncrement];[%expect"counter 2"];H.do_actions[OuterIncrement(* The inner action is ignored. You can see this because it prints "counter 2"
when it gets focus again. *);InnerIncrement];[%expect{|
("an action inside of Bonsai.switch as been dropped because the computation is no longer active"
(index 1) (action Increment))
pure 3|}];H.do_actions[OuterIncrement];[%expect"counter 2"]);;let%expect_test"constant component"=run_test~component:(Bonsai.Arrow_deprecated.const"some constant value")~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string~driverinH.show();[%expect{| some constant value |}]);;let%expect_test"module component"=run_test~component:(Bonsai.Arrow_deprecated.of_module(moduleCounter_component)~default_model:0)~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect"0"];H.do_actions[Increment];[%expect"1"];H.do_actions[Decrement];[%expect"0"];(* Increment and decrement in the same cycle should cancel out *)H.do_actions[Increment;Decrement];[%expect"0"]);;let%expect_test"state-machine counter-component"=letcomponent=let%map.Bonsai.Arrow_deprecatedmodel,inject=Bonsai.Arrow_deprecated.state_machine(moduleCounter_component.Model)(moduleCounter_component.Action)dummy_source_code_position~default_model:0~apply_action:(fun~inject:_~schedule_event:_()model->function|Increment->model+1|Decrement->model-1)inInt.to_stringmodel,injectinrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect"0"];H.do_actions[Increment];[%expect"1"];H.do_actions[Decrement];[%expect"0"];(* Increment and decrement in the same cycle should cancel out *)H.do_actions[Increment;Decrement];[%expect"0"]);;let%expect_test"basic Same_model let syntax"=letopenBonsai.Arrow_deprecated.Let_syntaxinletcounter_component=Bonsai.Arrow_deprecated.of_module(moduleCounter_component)~default_model:0inletcomponent=let%mapa_side=Bonsai.Arrow_deprecated.const5andb_side,inject_b=counter_componentinsprintf"%d | %s"a_sideb_side,inject_binrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect{| 5 | 0 |}];H.do_actions[Increment];[%expect{| 5 | 1 |}];H.do_actions[Decrement];[%expect{| 5 | 0 |}]);;let%expect_test"module project field"=letopenBonsai.Arrow_deprecated.Let_syntaxinletmodule_=structtypet={a:int;b:int}[@@derivingfields]endinletcounter_component=Bonsai.Arrow_deprecated.of_module(moduleCounter_component)~default_model:0inletcomponent=let%mapa_side,inject_a=counter_componentandb_side,inject_b=counter_componentin(sprintf"%s | %s"a_sideb_side,function|Firsta->inject_aa|Secondb->inject_bb)inrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect{| 0 | 0 |}];H.do_actions[FirstIncrement];[%expect{| 1 | 0 |}];H.do_actions[SecondDecrement];[%expect{| 1 | -1 |}]);;let%expect_test"incremental fn constructor"=letcomponent=Bonsai.Arrow_deprecated.With_incr.pure~f:(Incr_map.mapi~f:(fun~key:_~data->print_endline"doing math";data+1))inletinitial_input=[0,0;1,1;2,2]|>Int.Map.of_alist_exninrun_test~component~initial_input~f:(fundriver->[%expect{|
doing math
doing math
doing math |}];let(moduleH)=Helpers.make~driver~sexp_of_result:[%sexp_of:intInt.Map.t]inH.show();[%expect{|
((0 1)
(1 2)
(2 3)) |}];H.set_input(Int.Map.add_exninitial_input~key:3~data:3);[%expect{|
doing math
((0 1)
(1 2)
(2 3)
(3 4)) |}]);;let%expect_test"schedule event from outside of the component"=letmoduleRaises_something_from_without=structmoduleInput=UnitmoduleModel=UnitmoduleAction=structtypet=Trigger[@@derivingsexp_of]endmoduleResult=structtypet=unit*(Action.t->unitEffect.t)endletapply_action~inject:_~schedule_event()()Action.Trigger=schedule_event(Effect.external_"hello world");;letcompute~inject()()=(),injectletname="raises-something-from-without"endinletcomponent=Bonsai.Arrow_deprecated.of_module(moduleRaises_something_from_without)~default_model:()inrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];[%expect{||}];let(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:[%sexp_of:unit]inH.do_actions[Trigger];[%expect{|
External event: hello world
() |}]);;let%expect_test"schedule many events from outside of the component"=letmoduleRaises_something_from_without=structmoduleInput=UnitmoduleAction=structtypet=Trigger[@@derivingsexp_of]endmoduleModel=UnitmoduleResult=structtypet=unit*(Action.t->unitEffect.t)endletapply_action~inject:_~schedule_event()()Action.Trigger=schedule_event(Effect.sequence[Effect.external_"hello world";Effect.no_op;Effect.external_"goodbye world"]);;letcompute~inject()()=(),injectletname="raises-something-from-without"endinletcomponent=Bonsai.Arrow_deprecated.of_module(moduleRaises_something_from_without)~default_model:()inrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:[%sexp_of:unit]inH.do_actions[Trigger];[%expect{|
External event: hello world
External event: goodbye world
() |}]);;let%expect_test"model cutoff"=letmoduleT=structletname="incremental of_module"moduleInput=UnitmoduleModel=structincludeIntletequalab=ifa>2thentrueelseInt.equalabendmoduleAction=UnitmoduleResult=structtypet=string*(unit->unitEffect.t)endletapply_action_input~inject:_=Incr.return(fun~schedule_event:_model()->model+1);;letcompute_inputmodel~inject=let%map.Incrmodel=modelinInt.to_stringmodel,inject;;endinletcomponent=Bonsai.Arrow_deprecated.With_incr.of_module(moduleT)~default_model:0|>Bonsai.Arrow_deprecated.With_incr.model_cutoffinrun_test~component~initial_input:()~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string_with_inject~driverinH.show();[%expect"0"];H.do_actions[()];[%expect"1"];H.do_actions[()];[%expect"2"];H.do_actions[()];[%expect"3"];H.do_actions[()];[%expect"3"]);;let%expect_test"value cutoff"=letopenBonsai.Arrow_deprecated.Infixinletcutoff=Incr.Cutoff.create(fun~old_value~new_value->old_value%2=new_value%2)inletcomponent=Bonsai.Arrow_deprecated.With_incr.value_cutoff~cutoff>>>Bonsai.Arrow_deprecated.pure~f:Int.to_stringinrun_test~component~initial_input:1~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string~driverinH.show();[%expect"1"];H.set_input5;[%expect"1"];H.set_input6;[%expect"6"];H.set_input2;[%expect"6"]);;let%expect_test"input"=letmoduleWords_counter_component=structmoduleInput=structtypet=stringlistendmoduleModel=IntmoduleAction=structtypet=Increment[@@derivingsexp_of]endmoduleResult=structtypet=(int*stringlist)*(Action.t->unitEffect.t)endletapply_action~inject:_~schedule_event:__wordsmodel:Action.t->Model.t=function|Increment->model+1;;letcompute~injectwordsm=letres=m,List.filterwords~f:(funs->String.lengths=m)inres,inject;;letname="words-counter-component"endinletcomponent=Bonsai.Arrow_deprecated.of_module(moduleWords_counter_component)~default_model:0inletinitial_input=[]inrun_test~component~initial_input~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:[%sexp_of:int*stringlist]inH.show();[%expect{| (0 ()) |}];H.set_input["a";"b";"c";"aa";"bbb";"cccc"];[%expect{| (0 ()) |}];H.do_actions[Words_counter_component.Action.Increment];[%expect{| (1 (a b c)) |}];H.do_actions[Words_counter_component.Action.Increment];[%expect{| (2 (aa)) |}];H.do_actions[Words_counter_component.Action.Increment];[%expect{| (3 (bbb)) |}];H.do_actions[Words_counter_component.Action.Increment];[%expect{| (4 (cccc)) |}];H.set_input["aaaa";"bbbb"];[%expect{| (4 (aaaa bbbb)) |}]);;let%expect_test"compose, pure"=letopenBonsai.Arrow_deprecated.Infixinletcomponent_a=Bonsai.Arrow_deprecated.pure~f:(funmodel->modelmod5)inletcomponent_b=Bonsai.Arrow_deprecated.pure~f:(funinput->input+2)inletcomponent=component_a>>>component_binrun_test~component~initial_input:0~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make~driver~sexp_of_result:[%sexp_of:int]inH.show();[%expect"2"];H.set_input11;[%expect"3"]);;let%expect_test"pure_incr"=letopenBonsai.Arrow_deprecated.Infixinletcomponent_a=Bonsai.Arrow_deprecated.pure~f:(funmodel->modelmod5)inletcomponent_b=Bonsai.Arrow_deprecated.With_incr.pure~f:(funinput->Incr.mapinput~f:(funi->i+2))inletcomponent=component_a>>>component_binrun_test~component~initial_input:0~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make~driver~sexp_of_result:[%sexp_of:int]inH.show();[%expect"2"];H.set_input11;[%expect"3"]);;let%expect_test"input projection"=letopenBonsai.Arrow_deprecated.Infixinletcomponent=String.length@>>Bonsai.Arrow_deprecated.pure~f:(funinput->input+1)inrun_test~component~initial_input:"hi"~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make~driver~sexp_of_result:[%sexp_of:int]inH.show();[%expect"3"];H.set_input"hello";[%expect"6"]);;let%expect_test"assoc on input"=letcomponent=Bonsai.Arrow_deprecated.pure~f:(funx->x+1)|>Bonsai.Arrow_deprecated.Map.assoc_input(moduleString)inrun_test~component~initial_input:(String.Map.of_alist_exn["a",0;"b",2])~f:(fundriver->let(moduleH)=Helpers.make~driver~sexp_of_result:[%sexp_of:intString.Map.t]inH.show();[%expect{|
((a 1)
(b 3)) |}];H.set_input(String.Map.of_alist_exn["a",1;"b",2]);[%expect{|
((a 2)
(b 3)) |}]);;let%expect_test"Incremental.of_incr"=letvar=Incr.Var.create"hello"inletincr=Incr.Var.watchvarinletcomponent=Bonsai.Arrow_deprecated.With_incr.of_incrincrinrun_test~component~initial_input:(String.Map.of_alist_exn["a",0;"b",2])~f:(fundriver->[%expect{| |}];let(moduleH)=Helpers.make_string~driverinH.show();[%expect{| hello |}];Incr.Var.setvar"world";Driver.flushdriver;H.show();[%expect{| world |}];(* reset for next test *)Incr.Var.setvar"hello");;module_=structopenBonsai.Arrow_deprecated.Let_syntaxletdummy(typet)(moduleM:Bonsai.Arrow_deprecated.Modelwithtypet=t)~default=Bonsai.Arrow_deprecated.state_machine(moduleM)(moduleM)[%here]~default_model:default~apply_action:(fun~inject:_~schedule_event:_()_model->Fn.id)>>|Tuple2.map_fst~f:M.sexp_of_t;;let%expect_test"normal operation"=letdriver=Driver.create~initial_input:()~clock:Incr.clock(dummy(moduleInt)~default:5)inlet(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:Fn.idinH.show();[%expect{| 5 |}];;let%expect_test"with of_sexp"=letdriver=Driver.create~initial_model_sexp:[%sexp2]~initial_input:()~clock:Incr.clock(dummy(moduleInt)~default:5)inlet(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:Fn.idinH.show();[%expect{| 2 |}];;let%expect_test"multiple components"=letcomponent=let%map(a,_),(b,_)=Bonsai.Arrow_deprecated.both(dummy(moduleInt)~default:5)(dummy(moduleInt)~default:5)inSexp.List[a;b],Nothing.unreachable_codeinletdriver=Driver.create~initial_model_sexp:[%sexp["2";"3"]]~initial_input:()~clock:Incr.clockcomponentinlet(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:Fn.idinH.show();[%expect{| (2 3) |}];;let%expect_test"enum"=letmoduleAction=structtypet=|Outerofbool|Innerofstringendinletcomponent=let%map.Bonsai.Arrow_deprecated(inner,change_inner),change_outer=dummy(moduleBool)~default:true>>>Bonsai.Arrow_deprecated.first(Bonsai.Arrow_deprecated.if_[%of_sexp:bool]~then_:(Fn.ignore@>>dummy(moduleInt)~default:0>>|Tuple2.map_snd~f:(funinjects->s|>int_of_string|>inject))~else_:(Fn.ignore@>>dummy(moduleString)~default:"world"))inletinject=function|Action.Outerb->change_outerb|Inners->change_innersininner,injectinletdriver=Driver.create~initial_input:()~clock:Incr.clockcomponentinlet(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:Fn.idinH.show();[%expect{| 0 |}];H.do_actions[Action.Inner"23"];[%expect{| 23 |}];H.do_actions[Action.Outerfalse];[%expect{| world |}];H.do_actions[Action.Inner"bonsai!"];[%expect{| bonsai! |}];letinitial_model_sexp=Driver.sexp_of_modeldriverinprint_sinitial_model_sexp;[%expect{|
(false (
(0 23)
(1 bonsai!))) |}];letdriver=Driver.create~initial_model_sexp~initial_input:()~clock:Incr.clockcomponentinlet(moduleH)=Helpers.make_with_inject~driver~sexp_of_result:Fn.idinH.show();[%expect{| bonsai! |}];H.do_actions[Action.Outertrue];[%expect{| 23 |}];;end