|
19 | 19 | -include_lib("eunit/include/eunit.hrl").
|
20 | 20 | -include("hocon_private.hrl").
|
21 | 21 | -include("hoconsc.hrl").
|
| 22 | +-include("hocon.hrl"). |
22 | 23 |
|
23 | 24 | -export([roots/0, fields/1, validations/0, desc/1, namespace/0]).
|
24 | 25 |
|
@@ -2586,3 +2587,177 @@ map_type_with_alias_test() ->
|
2586 | 2587 | ?assertEqual(NormalRecord, hocon_tconf:check_plain(Sc, NormalRecord)),
|
2587 | 2588 | ?assertEqual(NormalRecord, hocon_tconf:check_plain(Sc, AliasedRecord)),
|
2588 | 2589 | ok.
|
| 2590 | + |
| 2591 | +computed_fields_test() -> |
| 2592 | + Size = 3, |
| 2593 | + Counter = counters:new(Size, []), |
| 2594 | + Reset = fun() -> |
| 2595 | + lists:foreach( |
| 2596 | + fun(Ix) -> |
| 2597 | + counters:put(Counter, Ix, 0) |
| 2598 | + end, |
| 2599 | + lists:seq(1, Size) |
| 2600 | + ) |
| 2601 | + end, |
| 2602 | + ComputedRoot = fun |
| 2603 | + ( |
| 2604 | + #{<<"bag">> := #{?COMPUTED := ComputedBag}, <<"baz">> := #{?COMPUTED := ComputedBaz}}, |
| 2605 | + _HoconOpts |
| 2606 | + ) -> |
| 2607 | + counters:add(Counter, 1, 1), |
| 2608 | + [ComputedBag, ComputedBaz]; |
| 2609 | + (#{bag := #{?COMPUTED := ComputedBag}, baz := #{?COMPUTED := ComputedBaz}}, _HoconOpts) -> |
| 2610 | + counters:add(Counter, 1, 1), |
| 2611 | + [ComputedBaz, ComputedBag] |
| 2612 | + end, |
| 2613 | + ComputedBaz = fun |
| 2614 | + (#{<<"quux">> := Val}, _HoconOpts) -> |
| 2615 | + counters:add(Counter, 2, 1), |
| 2616 | + Val + 333; |
| 2617 | + (#{quux := Val}, _HoconOpts) -> |
| 2618 | + counters:add(Counter, 2, 1), |
| 2619 | + Val - 333 |
| 2620 | + end, |
| 2621 | + %% This one is an open map without schema, so keys are not converted to atoms. |
| 2622 | + ComputedBag = fun(#{<<"key">> := Val}, _HoconOpts) -> |
| 2623 | + counters:add(Counter, 3, 1), |
| 2624 | + <<"computed ", Val/binary>> |
| 2625 | + end, |
| 2626 | + BadComputed = fun(X, _HoconOpts) -> error({shouldnt_be_called, X}) end, |
| 2627 | + QuuxValidator = fun(X) -> X > 300 end, |
| 2628 | + Sc = #{ |
| 2629 | + roots => [ |
| 2630 | + {"root", hoconsc:mk(hoconsc:ref(foo), #{computed => ComputedRoot})} |
| 2631 | + ], |
| 2632 | + fields => |
| 2633 | + #{ |
| 2634 | + foo => [ |
| 2635 | + {bar, hoconsc:mk(integer(), #{computed => BadComputed})}, |
| 2636 | + {baz, hoconsc:mk(hoconsc:ref(qux), #{computed => ComputedBaz})}, |
| 2637 | + {bag, hoconsc:mk(map(), #{computed => ComputedBag})} |
| 2638 | + ], |
| 2639 | + qux => [ |
| 2640 | + {quux, |
| 2641 | + hoconsc:mk(integer(), #{ |
| 2642 | + computed => BadComputed, |
| 2643 | + validator => QuuxValidator |
| 2644 | + })} |
| 2645 | + ] |
| 2646 | + } |
| 2647 | + }, |
| 2648 | + Data = #{ |
| 2649 | + <<"root">> => |
| 2650 | + #{ |
| 2651 | + <<"bar">> => 123, |
| 2652 | + <<"baz">> => |
| 2653 | + #{<<"quux">> => 666}, |
| 2654 | + <<"bag">> => #{<<"key">> => <<"value">>} |
| 2655 | + } |
| 2656 | + }, |
| 2657 | + Res1 = hocon_tconf:check_plain(Sc, Data, #{}), |
| 2658 | + ?assertMatch( |
| 2659 | + #{ |
| 2660 | + <<"root">> := |
| 2661 | + #{ |
| 2662 | + ?COMPUTED := [<<"computed value">>, 999], |
| 2663 | + <<"bar">> := 123, |
| 2664 | + <<"baz">> := |
| 2665 | + #{ |
| 2666 | + ?COMPUTED := 999, |
| 2667 | + <<"quux">> := 666 |
| 2668 | + }, |
| 2669 | + <<"bag">> := |
| 2670 | + #{ |
| 2671 | + ?COMPUTED := <<"computed value">>, |
| 2672 | + <<"key">> := <<"value">> |
| 2673 | + } |
| 2674 | + } |
| 2675 | + }, |
| 2676 | + Res1 |
| 2677 | + ), |
| 2678 | + ?assertEqual(1, counters:get(Counter, 1)), |
| 2679 | + ?assertEqual(1, counters:get(Counter, 2)), |
| 2680 | + ?assertEqual(1, counters:get(Counter, 3)), |
| 2681 | + Reset(), |
| 2682 | + Res2 = hocon_tconf:check_plain(Sc, Data, #{atom_key => true}), |
| 2683 | + ?assertMatch( |
| 2684 | + #{ |
| 2685 | + root := |
| 2686 | + #{ |
| 2687 | + ?COMPUTED := [333, <<"computed value">>], |
| 2688 | + bar := 123, |
| 2689 | + baz := |
| 2690 | + #{ |
| 2691 | + ?COMPUTED := 333, |
| 2692 | + quux := 666 |
| 2693 | + }, |
| 2694 | + bag := |
| 2695 | + #{ |
| 2696 | + ?COMPUTED := <<"computed value">>, |
| 2697 | + <<"key">> := <<"value">> |
| 2698 | + } |
| 2699 | + } |
| 2700 | + }, |
| 2701 | + Res2 |
| 2702 | + ), |
| 2703 | + ?assertEqual(1, counters:get(Counter, 1)), |
| 2704 | + ?assertEqual(1, counters:get(Counter, 2)), |
| 2705 | + ?assertEqual(1, counters:get(Counter, 3)), |
| 2706 | + Reset(), |
| 2707 | + %% Tests that fail validation/type check do not trigger computation |
| 2708 | + BadData1 = #{ |
| 2709 | + <<"root">> => |
| 2710 | + #{ |
| 2711 | + <<"bar">> => 123, |
| 2712 | + <<"baz">> => |
| 2713 | + #{ |
| 2714 | + <<"quux">> => |
| 2715 | + %% bad value: fails validation |
| 2716 | + 200 |
| 2717 | + }, |
| 2718 | + <<"bag">> => #{<<"key">> => <<"value">>} |
| 2719 | + } |
| 2720 | + }, |
| 2721 | + ?assertThrow( |
| 2722 | + {_, [ |
| 2723 | + #{ |
| 2724 | + reason := returned_false, |
| 2725 | + kind := validation_error, |
| 2726 | + path := "root.baz.quux" |
| 2727 | + } |
| 2728 | + ]}, |
| 2729 | + hocon_tconf:check_plain(Sc, BadData1, #{}) |
| 2730 | + ), |
| 2731 | + %% Root is not called |
| 2732 | + ?assertEqual(0, counters:get(Counter, 1)), |
| 2733 | + %% Baz is not called |
| 2734 | + ?assertEqual(0, counters:get(Counter, 2)), |
| 2735 | + %% Bag is called |
| 2736 | + ?assertEqual(1, counters:get(Counter, 3)), |
| 2737 | + Reset(), |
| 2738 | + BadData2 = #{ |
| 2739 | + <<"root">> => |
| 2740 | + #{ |
| 2741 | + <<"bar">> => 123, |
| 2742 | + <<"baz">> => |
| 2743 | + #{<<"quux">> => <<"wrong type">>}, |
| 2744 | + <<"bag">> => #{<<"key">> => <<"value">>} |
| 2745 | + } |
| 2746 | + }, |
| 2747 | + ?assertThrow( |
| 2748 | + {_, [ |
| 2749 | + #{ |
| 2750 | + reason := "Unable to parse integer value", |
| 2751 | + kind := validation_error, |
| 2752 | + path := "root.baz.quux" |
| 2753 | + } |
| 2754 | + ]}, |
| 2755 | + hocon_tconf:check_plain(Sc, BadData2, #{}) |
| 2756 | + ), |
| 2757 | + %% Root is not called |
| 2758 | + ?assertEqual(0, counters:get(Counter, 1)), |
| 2759 | + %% Baz is not called |
| 2760 | + ?assertEqual(0, counters:get(Counter, 2)), |
| 2761 | + %% Bag is called |
| 2762 | + ?assertEqual(1, counters:get(Counter, 3)), |
| 2763 | + ok. |
0 commit comments