|
142 | 142 | -export([integer/2, float/2, atom/0, binary/0, binary/1, bitstring/0, |
143 | 143 | bitstring/1, list/1, vector/2, union/1, weighted_union/1, tuple/1, |
144 | 144 | loose_tuple/1, exactly/1, fixed_list/1, fixed_map/1, function/2, map/0, |
145 | | - map/2, any/0, shrink_list/1, safe_union/1, safe_weighted_union/1]). |
| 145 | + map/1, map/2, any/0, shrink_list/1, safe_union/1, safe_weighted_union/1]). |
146 | 146 | -export([integer/0, non_neg_integer/0, pos_integer/0, neg_integer/0, range/2, |
147 | 147 | float/0, non_neg_float/0, number/0, boolean/0, byte/0, char/0, nil/0, |
148 | 148 | list/0, tuple/0, string/0, wunion/1, term/0, timeout/0, arity/0]). |
149 | 149 | -export([int/0, nat/0, largeint/0, real/0, bool/0, choose/2, elements/1, |
150 | 150 | oneof/1, frequency/1, return/1, default/2, orderedlist/1, function0/1, |
151 | | - function1/1, function2/1, function3/1, function4/1, |
| 151 | + function1/1, function2/1, function3/1, function4/1, map_union/1, |
152 | 152 | weighted_default/2]). |
153 | 153 | -export([resize/2, non_empty/1, noshrink/1]). |
154 | 154 |
|
@@ -1115,28 +1115,49 @@ function_is_instance(Type, X) -> |
1115 | 1115 | %% TODO: what if it's not a function we produced? |
1116 | 1116 | andalso equal_types(RetType, proper_gen:get_ret_type(X)). |
1117 | 1117 |
|
| 1118 | +%% @doc A map whose keys and values are defined by the given `Map'. |
| 1119 | +%% |
| 1120 | +%% Shrinks towards the empty map. That is, all keys are assumed to be optional. |
| 1121 | +%% |
| 1122 | +%% Also written simply as a {@link maps. map}. |
| 1123 | +-spec map(#{Key::raw_type() => Value::raw_type()}) -> proper_types:type(). |
| 1124 | +map(Map) when is_map(Map) -> |
| 1125 | + MapType = maps:map(fun(_Key, Value) -> cook_outer(Value) end, Map), |
| 1126 | + ?CONTAINER([ |
| 1127 | + {generator, {typed, fun map_gen/1}}, |
| 1128 | + {is_instance, {typed, fun map_is_instance/2}}, |
| 1129 | + {internal_types, MapType}, |
| 1130 | + {get_length, fun maps:size/1}, |
| 1131 | + {join, fun maps:merge/2}, |
| 1132 | + {get_indices, fun fixed_map_get_keys/2}, |
| 1133 | + {remove, fun maps:remove/2}, |
| 1134 | + {retrieve, fun maps:get/2}, |
| 1135 | + {update, fun maps:update/3} |
| 1136 | + ]). |
| 1137 | + |
1118 | 1138 | %% @doc A map whose keys are defined by the generator `K' and values |
1119 | 1139 | %% by the generator `V'. |
1120 | 1140 | -spec map(K::raw_type(), V::raw_type()) -> proper_types:type(). |
1121 | 1141 | map(K, V) -> |
1122 | 1142 | ?LET(L, list({K, V}), maps:from_list(L)). |
1123 | 1143 |
|
| 1144 | +%% @doc A map merged from the given map generators. |
| 1145 | +-spec map_union([Map::raw_type()]) -> proper_types:type(). |
| 1146 | +map_union(RawMaps) when is_list(RawMaps) -> |
| 1147 | + ?LET(Maps, RawMaps, lists:foldl(fun maps:merge/2, #{}, Maps)). |
| 1148 | + |
1124 | 1149 | %% @doc A map whose keys and values are defined by the given `Map'. |
1125 | 1150 | %% Also written simply as a {@link maps. map}. |
1126 | 1151 | -spec fixed_map(#{Key::raw_type() => Value::raw_type()}) -> proper_types:type(). |
1127 | | -% fixed_map(Map) when is_map(Map) -> |
1128 | | -% Pairs = maps:to_list(Map), |
1129 | | -% ?LET(L, fixed_list(Pairs), maps:from_list(L)). |
1130 | | - |
1131 | 1152 | fixed_map(Map) when is_map(Map) -> |
| 1153 | + MapType = maps:map(fun(_Key, Value) -> cook_outer(Value) end, Map), |
1132 | 1154 | ?CONTAINER([ |
1133 | 1155 | {generator, {typed, fun map_gen/1}}, |
1134 | 1156 | {is_instance, {typed, fun map_is_instance/2}}, |
1135 | | - {internal_types, Map}, |
| 1157 | + {internal_types, MapType}, |
1136 | 1158 | {get_length, fun maps:size/1}, |
1137 | 1159 | {join, fun maps:merge/2}, |
1138 | | - {get_indices, fun maps:keys/1}, |
1139 | | - {remove, fun maps:remove/2}, |
| 1160 | + {get_indices, fun fixed_map_get_keys/2}, |
1140 | 1161 | {retrieve, fun maps:get/2}, |
1141 | 1162 | {update, fun maps:update/3} |
1142 | 1163 | ]). |
@@ -1179,6 +1200,10 @@ map_all_internal(Fun, none, Result) when is_function(Fun, 2) andalso is_boolean( |
1179 | 1200 | map_all_internal(Fun, {Key, Value, NextIterator}, true) when is_function(Fun, 2) -> |
1180 | 1201 | map_all_internal(Fun, NextIterator, Fun(Key, Value)). |
1181 | 1202 |
|
| 1203 | +fixed_map_get_keys(Type, _X) -> |
| 1204 | + Map = get_prop(internal_types, Type), |
| 1205 | + maps:keys(Map). |
| 1206 | + |
1182 | 1207 | %% @doc All Erlang terms (that PropEr can produce). For reasons of efficiency, |
1183 | 1208 | %% functions are never produced as instances of this type.<br /> |
1184 | 1209 | %% CAUTION: Instances of this type are expensive to produce, shrink and instance- |
|
0 commit comments