open OUnit2 module Option = Tools.Option let u = UTF8.from_utf8string let catalog = Functions.C.compile @@ Functions.built_in Functions.C.empty let _msg ~expected ~result = begin let get_string v = match v with | None -> "Undefined" | Some x -> UTF8.raw_encode @@ ScTypes.Result.show x in Printf.sprintf "Expected %s but got %s" (get_string expected) (get_string result) end let build_num value = ScTypes.Type.number @@ DataType.Num.of_int value (** Test a simple references between two cells *) let test_create_ref_1 ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (3,3) (Expression.load @@ u"=-1") catalog |> snd |> Sheet.Raw.add (0,0) (Expression.load @@ u"=C3") catalog |> snd in let result = (Sheet.Raw.get_value (0, 0) s) in let expected = Some (ScTypes.Result.Ok (build_num (-1))) in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_create_ref_2 ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (2,2) (Expression.load @@ u"=C3") catalog |> snd |> Sheet.Raw.add (3,3) (Expression.load @@ u"=A1") catalog |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"123") catalog |> snd in let result = (Sheet.Raw.get_value (2, 2) s) in let expected = Some (ScTypes.Result.Ok (build_num 123)) in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_create_direct_cycle ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (2,2) (Expression.load @@ u"=B2 + 1") catalog |> snd in let result = (Sheet.Raw.get_value (2, 2) s) in let expected = Some (ScTypes.Result.Error Errors.TypeError) in assert_equal ~msg:(_msg ~expected ~result) expected result end (** Overide the value after a cycle. *) let test_recover_from_cycle ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (2,2) (Expression.load @@ u"=B2 + 1") catalog |> snd |> Sheet.Raw.add (2,2) (Expression.load @@ u"=6") catalog |> snd in let result = (Sheet.Raw.get_value (2, 2) s) in let expected = Some (ScTypes.Result.Ok (build_num (6))) in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_create_indirect_cycle ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (2,2) (Expression.load @@ u"=A1") catalog |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"=2") catalog |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"=B2+1") catalog |> snd |> Sheet.Raw.add (0,0) (Expression.load @@ u"=A1") catalog |> snd in let result = (Sheet.Raw.get_value (0, 0) s) in let expected = Some (ScTypes.Result.Error Errors.Cycle) in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_check_cycle3 ctx = begin let s = Sheet.Raw.empty (* First set A1 to 3 *) |> Sheet.Raw.add (1,1) (Expression.load @@ u"=3") catalog |> snd |> Sheet.Raw.add (1,2) (Expression.load @@ u"=A1") catalog |> snd |> Sheet.Raw.add (2,2) (Expression.load @@ u"=A1") catalog |> snd |> Sheet.Raw.add (5,5) (Expression.load @@ u"=B2") catalog (* A3 = A1 + A1 = 6 *) |> snd |> Sheet.Raw.add (1,3) (Expression.load @@ u"=A2 + E5") catalog (* Then set A1 to 2 *) |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"=2") catalog |> snd in let result = (Sheet.Raw.get_value (1, 3) s) in (* A3 = A1 + A1 = 4 *) let expected = Some (ScTypes.Result.Ok (build_num 4)) in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_delete ctx = begin let s = Sheet.Raw.empty |> Sheet.Raw.add (2,2) (Expression.load @@ u"=C3") catalog |> snd |> Sheet.Raw.add (3,3) (Expression.load @@ u"=A1") catalog |> snd |> Sheet.Raw.remove (2,2) catalog |> snd |> Sheet.Raw.remove (3,3) catalog |> snd in let result = (Sheet.Raw.get_value (3, 3) s) in let expected = None in assert_equal ~msg:(_msg ~expected ~result) expected result end let test_update_succs1 ctx = begin let result = Sheet.Raw.empty |> Sheet.Raw.add (1,1) (Expression.load @@ u" =1") catalog |> snd |> Sheet.Raw.add (2,2) (Expression.load @@ u"=A2") catalog |> snd |> Sheet.Raw.add (1,2) (Expression.load @@ u"=A1/1") catalog |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"=2") catalog |> fst in (* All the cells are updated by the change *) let expected = Cell.Set.of_list [(1,1); (1, 2); (2,2)] in let msg = Printf.sprintf "Expected %s but got %s" (UTF8.raw_encode @@ Tools.String.print_buffer Cell.Set.printb expected) (UTF8.raw_encode @@ Tools.String.print_buffer Cell.Set.printb result) in assert_equal ~msg expected result end let test_update_succs2 ctx = begin let result = Sheet.Raw.empty |> Sheet.Raw.add (1,1) (Expression.load @@ u"=1") catalog |> snd |> Sheet.Raw.add (2,2) (Expression.load @@ u"=A2") catalog |> snd |> Sheet.Raw.add (1,2) (Expression.load @@ u"=A1/0") catalog |> snd |> Sheet.Raw.add (1,1) (Expression.load @@ u"=2") catalog |> fst in (* Only (1, 1) is updated ; (2, 2) does not change, neither (2, 2) *) let expected = Cell.Set.of_list [(1,1)] in assert_equal expected result end let test_paste_undo ctx = begin let empty = Sheet.create catalog Sheet.Raw.empty in (* The expected result for the whole test *) let expected = Some (ScTypes.Result.Ok (ScTypes.Type.number (DataType.Num.of_int 6))) in let sheet = empty |> Tools.Option.test @@ Sheet.move (Actions.Absolute (2, 1)) |> Sheet.add (Expression.load @@ u"=6") |> snd |> Tools.Option.test @@ Sheet.move (Actions.Absolute (1, 1)) |> Sheet.add (Expression.load @@ u"=B1") |> snd in let result = Sheet.Raw.get_value (1, 1) sheet.Sheet.data in (* Ensure the value is correctly evaluated *) assert_equal ~msg:(_msg ~expected ~result) expected result; let sheet2 = (* Copy the cell *) fst @@ Sheet.yank sheet |> Tools.Option.test @@ Sheet.move (Actions.Absolute (2, 1)) (* Paste it on another value *) |> Sheet.paste |> fst (* Undo the paste *) |> Tools.Option.test @@ Sheet.undo in let result = Sheet.Raw.get_value (1, 1) sheet2.Sheet.data in (* The value should be the same as the first evaluation *) assert_equal ~msg:(_msg ~expected ~result) expected result end let tests = "sheet_test">::: [ "test_ref1" >:: test_create_ref_1; "test_ref2" >:: test_create_ref_2; "test_cycle1" >:: test_create_direct_cycle; "test_recover_cycle" >:: test_recover_from_cycle; "test_cycle2" >:: test_create_indirect_cycle; "test_cycle3" >:: test_check_cycle3; "test_delete" >:: test_delete; "test_update_succs1" >:: test_update_succs1; "test_update_succs2" >:: test_update_succs2; "test_paste_undo" >:: test_paste_undo; ]