From 00b6e4e52c7a204368a218cc29bbabc45dd1d2da Mon Sep 17 00:00:00 2001 From: LoisSotoLopez Date: Wed, 24 Jan 2024 09:52:47 +0100 Subject: [PATCH] feat: Redesign error messages & cleanup code --- src/ndto_generator.erl | 802 +++++++++++++++++++++++++---------------- src/ndto_utils.erl | 79 ++-- src/smthing.erl | 73 ---- test/ndto_SUITE.erl | 69 +++- 4 files changed, 575 insertions(+), 448 deletions(-) delete mode 100644 src/smthing.erl diff --git a/src/ndto_generator.erl b/src/ndto_generator.erl index 3b33322..519070c 100644 --- a/src/ndto_generator.erl +++ b/src/ndto_generator.erl @@ -213,9 +213,7 @@ is_valid(Prefix, #{type := integer} = Schema) -> undefined -> Acc; Value -> - case - is_valid_number(integer, FunName, Keyword, Value, Schema) - of + case is_valid_number(integer, FunName, Keyword, Value, Schema) of undefined -> Acc; NewIsValidFun -> @@ -317,7 +315,7 @@ is_valid(Prefix, #{type := boolean} = Schema) -> type_guard(boolean), [erl_syntax:atom(true)] ), - FalseClause = false_clause(<> , "Value is not a boolean"), + FalseClause = false_clause(<>, "Value is not a boolean"), Clauses = clauses([OptionalClause, NullClause, TrueClause, FalseClause]), Fun = erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), @@ -429,7 +427,7 @@ is_valid(Prefix, #{type := object} = Schema) -> type_guard(object), chain_conditions(FunName, {mfa_call, BodyFunPieces}, 'andalso') ), - FalseClause = false_clause(<> , "Value is not an object"), + FalseClause = false_clause(<>, "Value is not an object"), Clauses = clauses([OptionalClause, NullClause, TrueClause, FalseClause]), Fun = erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), @@ -634,11 +632,11 @@ generate(Name, Schema) -> ExportHeader2 = erl_syntax:comment([?CLINE, ?EXPORTS_HEADER, ?CLINE]), {IsValidFun, ExtraFuns} = is_valid(<<"$">>, Schema), - + Fun = erl_syntax:function( erl_syntax:atom(is_valid), - clauses([ + clauses([ optional_clause(Schema), erl_syntax:clause( [erl_syntax:variable('Val')], @@ -761,7 +759,6 @@ is_valid(Prefix, #{ref := Ref} = Schema) -> ) ] ) - ] ), Clauses = clauses([OptionalClause, NullClause, TrueClause]), @@ -936,9 +933,7 @@ is_valid(Prefix, #{type := float} = Schema) -> undefined -> Acc; Value -> - case - is_valid_number(float, FunName, Keyword, Value, Schema) - of + case is_valid_number(float, FunName, Keyword, Value, Schema) of undefined -> Acc; NewIsValidFun -> @@ -1143,7 +1138,7 @@ is_valid(Prefix, #{one_of := Subschemas} = Schema) when is_list(Subschemas) -> BodyFunCallsCount = length(BodyFunCalls), [{FirstFunCall, FirstIdx} | IndexedFunCalls] = lists:zip( - BodyFunCalls, lists:seq(BodyFunCallsCount-1, 0, -1) + BodyFunCalls, lists:seq(BodyFunCallsCount - 1, 0, -1) ), Acc0 = erl_syntax:list([]), FunCallCase = fun(Index, FunCall, CurrentAcc) -> @@ -1171,42 +1166,64 @@ is_valid(Prefix, #{one_of := Subschemas} = Schema) when is_list(Subschemas) -> PrevAcc, [ erl_syntax:clause( - [erl_syntax:list([ - erl_syntax:variable(list_to_atom("One_"++integer_to_list(Index))), - erl_syntax:variable(list_to_atom("Two_"++integer_to_list(Index))) - ])], + [ + erl_syntax:list([ + erl_syntax:variable(list_to_atom("One_" ++ integer_to_list(Index))), + erl_syntax:variable(list_to_atom("Two_" ++ integer_to_list(Index))) + ]) + ], none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), + [ erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), - erl_syntax:application( - erl_syntax:atom(list_to_binary), - [erl_syntax:application( - erl_syntax:atom('lists'), - erl_syntax:atom('flatten'), + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:atom(binary_to_atom(FunName)), + erl_syntax:application( + erl_syntax:atom(list_to_binary), [ erl_syntax:application( - erl_syntax:atom('io_lib'), - erl_syntax:atom('format'), + erl_syntax:atom('lists'), + erl_syntax:atom('flatten'), [ - erl_syntax:string("Value is not matching exactly one condition. More than one (conditions ~p and ~p) matched."), - erl_syntax:list([ - erl_syntax:variable(list_to_atom("One_"++integer_to_list(Index))), - erl_syntax:variable(list_to_atom("Two_"++integer_to_list(Index))) - ]) + erl_syntax:application( + erl_syntax:atom('io_lib'), + erl_syntax:atom('format'), + [ + erl_syntax:string( + "Value is not matching exactly one condition. More than one (conditions ~p and ~p) matched." + ), + erl_syntax:list([ + erl_syntax:variable( + list_to_atom( + "One_" ++ integer_to_list(Index) + ) + ), + erl_syntax:variable( + list_to_atom( + "Two_" ++ integer_to_list(Index) + ) + ) + ]) + ] + ) ] ) ] - )] - ) + ) + ]) ]) - ])] + ] ), erl_syntax:clause( - [erl_syntax:variable(list_to_atom("Acc_"++integer_to_list(Index)))], + [erl_syntax:variable(list_to_atom("Acc_" ++ integer_to_list(Index)))], none, - [FunCallCase(Index, FunCall, erl_syntax:variable(list_to_atom("Acc_"++integer_to_list(Index))))] + [ + FunCallCase( + Index, + FunCall, + erl_syntax:variable(list_to_atom("Acc_" ++ integer_to_list(Index))) + ) + ] ) ] ) @@ -1221,94 +1238,114 @@ is_valid(Prefix, #{one_of := Subschemas} = Schema) when is_list(Subschemas) -> erl_syntax:match_expr( erl_syntax:tuple([ erl_syntax:atom('continue'), - erl_syntax:variable(list_to_atom("Acc"++integer_to_list(FirstIdx))) + erl_syntax:variable( + list_to_atom("Acc" ++ integer_to_list(FirstIdx)) + ) ]), FunCallCase(FirstIdx, FirstFunCall, Acc0) ) ] ++ - [ - erl_syntax:maybe_match_expr( - erl_syntax:tuple([ - erl_syntax:atom('continue'), - erl_syntax:variable(list_to_atom("Acc" ++ integer_to_list(N))) - ]), - XorMaybeEntry( - N, - erl_syntax:variable(list_to_atom("Acc" ++ integer_to_list(N + 1))), - BodyFunCall + [ + erl_syntax:maybe_match_expr( + erl_syntax:tuple([ + erl_syntax:atom('continue'), + erl_syntax:variable(list_to_atom("Acc" ++ integer_to_list(N))) + ]), + XorMaybeEntry( + N, + erl_syntax:variable( + list_to_atom("Acc" ++ integer_to_list(N + 1)) + ), + BodyFunCall + ) ) - ) - || {BodyFunCall, N} <- IndexedFunCalls - ] ++ - [ - erl_syntax:case_expr( - erl_syntax:variable('Acc0'), - [ - erl_syntax:clause( - [erl_syntax:list([ - erl_syntax:variable('One'), - erl_syntax:variable('Two') - ])], - none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), - erl_syntax:application( - erl_syntax:atom(list_to_binary), - [ + || {BodyFunCall, N} <- IndexedFunCalls + ] ++ + [ + erl_syntax:case_expr( + erl_syntax:variable('Acc0'), + [ + erl_syntax:clause( + [ + erl_syntax:list([ + erl_syntax:variable('One'), + erl_syntax:variable('Two') + ]) + ], + none, + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:atom(binary_to_atom(FunName)), erl_syntax:application( - erl_syntax:atom('lists'), - erl_syntax:atom('flatten'), + erl_syntax:atom(list_to_binary), [ erl_syntax:application( - erl_syntax:atom('io_lib'), - erl_syntax:atom('format'), + erl_syntax:atom('lists'), + erl_syntax:atom('flatten'), [ - erl_syntax:binary([ - erl_syntax:binary_field( - erl_syntax:string( - "Value is not matching exactly one condition. More than one (conditions ~p and ~p) matched.") - )]), - erl_syntax:list([ - erl_syntax:variable('One'), - erl_syntax:variable('Two') - ]) + erl_syntax:application( + erl_syntax:atom('io_lib'), + erl_syntax:atom('format'), + [ + erl_syntax:binary([ + erl_syntax:binary_field( + erl_syntax:string( + "Value is not matching exactly one condition. More than one (conditions ~p and ~p) matched." + ) + ) + ]), + erl_syntax:list([ + erl_syntax:variable( + 'One' + ), + erl_syntax:variable( + 'Two' + ) + ]) + ] + ) ] ) ] ) - ] - ) - ]) - ])] - ), - erl_syntax:clause( - [erl_syntax:list([ - erl_syntax:variable('_One') - ])], - none, - [erl_syntax:atom('true')] - ), - erl_syntax:clause( - [erl_syntax:list([])], - none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), - erl_syntax:binary([ - erl_syntax:binary_field( - erl_syntax:string("Value is not matching exactly one condition. None matched."), - [] - ) + ]) ]) - ]) - ])] - ) - ] - ) - ] + ] + ), + erl_syntax:clause( + [ + erl_syntax:list([ + erl_syntax:variable('_One') + ]) + ], + none, + [erl_syntax:atom('true')] + ), + erl_syntax:clause( + [erl_syntax:list([])], + none, + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:atom(binary_to_atom(FunName)), + erl_syntax:binary([ + erl_syntax:binary_field( + erl_syntax:string( + "Value is not matching exactly one condition. None matched." + ), + [] + ) + ]) + ]) + ]) + ] + ) + ] + ) + ] ) ] ), @@ -1348,34 +1385,38 @@ is_valid(Prefix, #{any_of := Subschemas} = Schema) when is_list(Subschemas) -> erl_syntax:clause( [erl_syntax:variable('Val')], none, - [erl_syntax:case_expr( - lists:nth(1,chain_conditions(FunName, {mfa_call, BodyFunCalls}, 'orelse')), - [ - erl_syntax:clause( - [erl_syntax:atom('true')], - none, - [erl_syntax:atom('true')] - ), - erl_syntax:clause( - [erl_syntax:atom('false')], - none, - [ - erl_syntax:tuple([ - erl_syntax:atom('false'), + [ + erl_syntax:case_expr( + lists:nth(1, chain_conditions(FunName, {mfa_call, BodyFunCalls}, 'orelse')), + [ + erl_syntax:clause( + [erl_syntax:atom('true')], + none, + [erl_syntax:atom('true')] + ), + erl_syntax:clause( + [erl_syntax:atom('false')], + none, + [ erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), - erl_syntax:binary([ - erl_syntax:binary_field( - erl_syntax:string("Value is not matching at least one condition. None matched."), - [] - ) + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:atom(binary_to_atom(FunName)), + erl_syntax:binary([ + erl_syntax:binary_field( + erl_syntax:string( + "Value is not matching at least one condition. None matched." + ), + [] + ) + ]) ]) ]) - ]) - ] - ) - ] - )] + ] + ) + ] + ) + ] ), Clauses = clauses([OptionalClause, NullClause, TrueClause]), Fun = erl_syntax:function( @@ -1410,7 +1451,7 @@ is_valid(Prefix, #{all_of := Subschemas} = Schema) when is_list(Subschemas) -> OptionalClause = optional_clause(Schema), NullClause = null_clause(Schema), BodyFunCallsCount = erlang:length(BodyFunCalls), - BodyFunCallsIndexes = lists:seq(BodyFunCallsCount-1, 0, -1), + BodyFunCallsIndexes = lists:seq(BodyFunCallsCount - 1, 0, -1), IndexedBodyFunCalls = lists:zip(BodyFunCalls, BodyFunCallsIndexes), TrueClause = erl_syntax:clause( @@ -1430,7 +1471,7 @@ is_valid(Prefix, #{all_of := Subschemas} = Schema) when is_list(Subschemas) -> erl_syntax:integer(BodyFunCallsIndex) ]) ) - || {BodyFunCall, BodyFunCallsIndex} <- IndexedBodyFunCalls + || {BodyFunCall, BodyFunCallsIndex} <- IndexedBodyFunCalls ] ++ [erl_syntax:atom('true')] ), [ @@ -1450,41 +1491,49 @@ is_valid(Prefix, #{all_of := Subschemas} = Schema) when is_list(Subschemas) -> ]) ]), erl_syntax:variable('ConditionIndex') - ]) + ]) ], none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), + [ erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), - erl_syntax:application( - erl_syntax:atom(list_to_binary), - [ - erl_syntax:application( - erl_syntax:atom('lists'), - erl_syntax:atom('flatten'), - [ - erl_syntax:application( - erl_syntax:atom('io_lib'), - erl_syntax:atom('format'), - [ - erl_syntax:string("Value is not matching all conditions. Condition ~p failed because of schema path '~ts' : ~s"), - erl_syntax:list([ - erl_syntax:variable('ConditionIndex'), - erl_syntax:variable('ReasonPath'), - erl_syntax:variable('ReasonMsg') - ]) - ] - ) - ] - ) - ] - ) + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:atom(binary_to_atom(FunName)), + erl_syntax:application( + erl_syntax:atom(list_to_binary), + [ + erl_syntax:application( + erl_syntax:atom('lists'), + erl_syntax:atom('flatten'), + [ + erl_syntax:application( + erl_syntax:atom('io_lib'), + erl_syntax:atom('format'), + [ + erl_syntax:string( + "Value is not matching all conditions. Condition ~p failed because of schema path '~ts' : ~s" + ), + erl_syntax:list([ + erl_syntax:variable( + 'ConditionIndex' + ), + erl_syntax:variable( + 'ReasonPath' + ), + erl_syntax:variable('ReasonMsg') + ]) + ] + ) + ] + ) + ] + ) + ]) ]) - ])] + ] ) ] - ) + ) ] ), Clauses = clauses([OptionalClause, NullClause, TrueClause]), @@ -1636,10 +1685,14 @@ is_valid_array(Prefix, items, #{items := Items} = Schema) when is_map(Items) -> erl_syntax:atom('io_lib'), erl_syntax:atom('format'), [ - erl_syntax:string("Item ~p in ~ts is invalid. ~s"), + erl_syntax:string( + "Item ~p in ~ts is invalid. ~s" + ), erl_syntax:list([ erl_syntax:variable('Acc'), - erl_syntax:string(binary_to_list(Prefix)), + erl_syntax:string( + binary_to_list(Prefix) + ), erl_syntax:variable('Reason') ]) ] @@ -1736,29 +1789,54 @@ is_valid_array(Prefix, items, #{items := Items} = Schema) when is_list(Items) -> erl_syntax:clause( [erl_syntax:atom('true')], none, - [erl_syntax:atom('true')]), + [erl_syntax:atom('true')] + ), erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:variable('_FalseReason') - ])], + [ + erl_syntax:tuple([ + erl_syntax:atom( + 'false' + ), + erl_syntax:variable( + '_FalseReason' + ) + ]) + ], none, [ erl_syntax:tuple([ - erl_syntax:atom('false'), + erl_syntax:atom( + 'false' + ), erl_syntax:tuple([ - erl_syntax:atom(binary_to_atom(FunName)), + erl_syntax:atom( + binary_to_atom( + FunName + ) + ), erl_syntax:application( - erl_syntax:atom('list_to_binary'), + erl_syntax:atom( + 'list_to_binary' + ), [ erl_syntax:application( - erl_syntax:atom(io_lib), - erl_syntax:atom(format), + erl_syntax:atom( + io_lib + ), + erl_syntax:atom( + format + ), [ - erl_syntax:string("Value at position ~p does not match the schema"), - erl_syntax:list([ - erl_syntax:variable('FunKey') - ]) + erl_syntax:string( + "Value at position ~p does not match the schema" + ), + erl_syntax:list( + [ + erl_syntax:variable( + 'FunKey' + ) + ] + ) ] ) ] @@ -1768,7 +1846,7 @@ is_valid_array(Prefix, items, #{items := Items} = Schema) when is_list(Items) -> ] ) ] - ) + ) ] ), erl_syntax:clause( @@ -1799,15 +1877,19 @@ is_valid_array(Prefix, items, #{items := Items} = Schema) when is_list(Items) -> [erl_syntax:atom('false')] ), erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:variable('FalseResult') - ])], + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:variable('FalseResult') + ]) + ], none, - [erl_syntax:tuple([ - erl_syntax:atom('true'), - erl_syntax:variable('FalseResult') - ])] + [ + erl_syntax:tuple([ + erl_syntax:atom('true'), + erl_syntax:variable('FalseResult') + ]) + ] ) ] ) @@ -1837,37 +1919,42 @@ is_valid_array(Prefix, items, #{items := Items} = Schema) when is_list(Items) -> ), [ erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:atom('none') - ])], + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:atom('none') + ]) + ], none, [erl_syntax:atom('true')] ), erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('true'), - erl_syntax:tuple([ - erl_syntax:variable('_Item'), - erl_syntax:variable('_FunKey') - ]), + [ erl_syntax:tuple([ - erl_syntax:variable('Prefix'), - erl_syntax:variable('Reason') + erl_syntax:atom('true'), + erl_syntax:tuple([ + erl_syntax:variable('_Item'), + erl_syntax:variable('_FunKey') + ]), + erl_syntax:tuple([ + erl_syntax:variable('Prefix'), + erl_syntax:variable('Reason') + ]) ]) - ])], + ], none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), + [ erl_syntax:tuple([ - erl_syntax:variable('Prefix'), - erl_syntax:variable('Reason') + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:variable('Prefix'), + erl_syntax:variable('Reason') + ]) ]) - ])] + ] ) ] ) - ] ), Fun = erl_syntax:function( @@ -1886,7 +1973,9 @@ is_valid_array(Prefix, min_items, #{min_items := MinItems}) -> ), [erl_syntax:atom(true)] ), - FalseClause = false_clause(FunName, lists:flatten(io_lib:format("Array does not have at least ~p items", [MinItems]))), + FalseClause = false_clause( + FunName, lists:flatten(io_lib:format("Array does not have at least ~p items", [MinItems])) + ), Fun = erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), [TrueClause, FalseClause] @@ -1903,7 +1992,9 @@ is_valid_array(Prefix, max_items, #{max_items := MaxItems}) -> ), [erl_syntax:atom(true)] ), - FalseClause = false_clause(FunName, lists:flatten(io_lib:format("Array does not have at most ~p items", [MaxItems]))), + FalseClause = false_clause( + FunName, lists:flatten(io_lib:format("Array does not have at most ~p items", [MaxItems])) + ), Fun = erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), [TrueClause, FalseClause] @@ -1981,7 +2072,10 @@ is_valid_number(_Type, Prefix, minimum, Minimum, Schema) -> "or equal to" end, FalseClause = false_clause( - FunName, lists:flatten(io_lib:format("Number is not greater ~s ~p", [ComparisonTerm, Minimum])) + FunName, + lists:flatten( + io_lib:format("Value is not a number greater ~s ~p", [ComparisonTerm, Minimum]) + ) ), erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), @@ -2021,7 +2115,8 @@ is_valid_number(_Type, Prefix, maximum, Maximum, Schema) -> "or equal to" end, FalseClause = false_clause( - FunName, lists:flatten(io_lib:format("Number is not lower ~s ~p", [ComparisonTerm, Maximum])) + FunName, + lists:flatten(io_lib:format("Number is not lower ~s ~p", [ComparisonTerm, Maximum])) ), erl_syntax:function( erl_syntax:atom(erlang:binary_to_atom(FunName)), @@ -2049,7 +2144,14 @@ is_valid_number(integer, Prefix, multiple_of, MultipleOf, _Schema) -> erl_syntax:clause( [erl_syntax:variable('_')], none, - [false_return(FunName, lists:flatten(io_lib:format("Value is not multiple of ~p", [MultipleOf])))] + [ + false_return( + FunName, + lists:flatten( + io_lib:format("Value is not multiple of ~p", [MultipleOf]) + ) + ) + ] ) ] ) @@ -2183,12 +2285,14 @@ is_valid_object(Prefix, required, #{required := Required}) -> lists:flatten( io_lib:format( "~ts is missing required property ~~p", - [ndto_utils:remove_all_of_prefix(binary_to_list(Prefix))] + [binary_to_list(Prefix)] ) ) ), erl_syntax:list([ - erl_syntax:variable('MissingProperty') + erl_syntax:variable( + 'MissingProperty' + ) ]) ] ) @@ -2197,8 +2301,8 @@ is_valid_object(Prefix, required, #{required := Required}) -> ] ) ]) - ] - )] + ]) + ] ) ] ) @@ -2230,21 +2334,33 @@ is_valid_object(Prefix, min_properties, #{min_properties := MinProperties}) -> [ erl_syntax:clause( [erl_syntax:variable('N')], - [erl_syntax:infix_expr( - erl_syntax:variable('N'), - erl_syntax:operator('>='), - erl_syntax:integer(MinProperties) - )], + [ + erl_syntax:infix_expr( + erl_syntax:variable('N'), + erl_syntax:operator('>='), + erl_syntax:integer(MinProperties) + ) + ], [erl_syntax:atom('true')] ), erl_syntax:clause( [erl_syntax:variable('_')], none, - [false_return(FunName, lists:flatten(io_lib:format("Object has less properties than required minimum (~p)", [MinProperties])))] + [ + false_return( + FunName, + lists:flatten( + io_lib:format( + "Object has less properties than required minimum (~p)", [ + MinProperties + ] + ) + ) + ) + ] ) ] ) - ] ), Fun = erl_syntax:function( @@ -2273,21 +2389,33 @@ is_valid_object(Prefix, max_properties, #{max_properties := MaxProperties}) -> [ erl_syntax:clause( [erl_syntax:variable('N')], - [erl_syntax:infix_expr( - erl_syntax:variable('N'), - erl_syntax:operator('=<'), - erl_syntax:integer(MaxProperties) - )], + [ + erl_syntax:infix_expr( + erl_syntax:variable('N'), + erl_syntax:operator('=<'), + erl_syntax:integer(MaxProperties) + ) + ], [erl_syntax:atom('true')] ), erl_syntax:clause( [erl_syntax:variable('_')], none, - [false_return(FunName, lists:flatten(io_lib:format("Object has more properties than allowed maximum (~p)", [MaxProperties])))] + [ + false_return( + FunName, + lists:flatten( + io_lib:format( + "Object has more properties than allowed maximum (~p)", [ + MaxProperties + ] + ) + ) + ) + ] ) ] ) - ] ), Fun = erl_syntax:function( @@ -2408,7 +2536,7 @@ is_valid_object(Prefix, pattern_properties, #{pattern_properties := PatternPrope erl_syntax:variable('Prefix'), erl_syntax:variable('Reason') ]) - ]) + ]) ], none, [ @@ -2431,49 +2559,57 @@ is_valid_object(Prefix, pattern_properties, #{pattern_properties := PatternPrope ), [ erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:atom('none') - ])], + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:atom('none') + ]) + ], none, [erl_syntax:atom('true')] ), erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('true'), - erl_syntax:tuple([ - erl_syntax:variable('PropertyName'), - erl_syntax:variable('_PropertyValue') - ]), + [ erl_syntax:tuple([ - erl_syntax:variable('Prefix'), - erl_syntax:variable('Reason') + erl_syntax:atom('true'), + erl_syntax:tuple([ + erl_syntax:variable('PropertyName'), + erl_syntax:variable('_PropertyValue') + ]), + erl_syntax:tuple([ + erl_syntax:variable('Prefix'), + erl_syntax:variable('Reason') + ]) ]) - ])], + ], none, - [erl_syntax:tuple([ - erl_syntax:atom('false'), + [ erl_syntax:tuple([ - erl_syntax:variable('Prefix'), - erl_syntax:application( - erl_syntax:atom(erlang), - erl_syntax:atom(list_to_binary), - [ - erl_syntax:application( - erl_syntax:atom('io_lib'), - erl_syntax:atom('format'), - [ - erl_syntax:string("Property \"~ts\" failed validation: ~ts"), - erl_syntax:list([ - erl_syntax:variable('PropertyName'), - erl_syntax:variable('Reason') - ]) - ] - ) - ] - ) + erl_syntax:atom('false'), + erl_syntax:tuple([ + erl_syntax:variable('Prefix'), + erl_syntax:application( + erl_syntax:atom(erlang), + erl_syntax:atom(list_to_binary), + [ + erl_syntax:application( + erl_syntax:atom('io_lib'), + erl_syntax:atom('format'), + [ + erl_syntax:string( + "Property \"~ts\" failed validation: ~ts" + ), + erl_syntax:list([ + erl_syntax:variable('PropertyName'), + erl_syntax:variable('Reason') + ]) + ] + ) + ] + ) + ]) ]) - ])] + ] ) ] ), @@ -2614,7 +2750,9 @@ is_valid_object( erl_syntax:binary([ erl_syntax:binary_field( erl_syntax:string( - erlang:binary_to_list(PropertyName) + erlang:binary_to_list( + PropertyName + ) ) ) ]) @@ -2653,13 +2791,17 @@ is_valid_object( erl_syntax:atom(io_lib), erl_syntax:atom(format), [ - erl_syntax:string("Object has unsupported keys: ~ts"), + erl_syntax:string( + "Object has unsupported keys: ~ts" + ), erl_syntax:list([ erl_syntax:application( erl_syntax:atom(ndto_utils), erl_syntax:atom(format_properties), [ - erl_syntax:variable('UnsupportedKeys') + erl_syntax:variable( + 'UnsupportedKeys' + ) ] ) ]) @@ -2686,7 +2828,9 @@ is_valid_object( #{additional_properties := AdditionalProperties} = Schema ) -> FunName = <>, - {IsValidFun, ExtraFuns} = is_valid(<>, AdditionalProperties), + {IsValidFun, ExtraFuns} = is_valid( + <>, AdditionalProperties + ), Properties = maps:get(properties, Schema, #{}), PatternProperties = maps:get(pattern_properties, Schema, #{}), PatternPropertiesList = erl_syntax:application( @@ -2781,14 +2925,16 @@ is_valid_object( erl_syntax:variable('Result'), erl_syntax:application( erl_syntax:function_name(IsValidFun), - [erl_syntax:application( - erl_syntax:atom(maps), - erl_syntax:atom(get), - [ - erl_syntax:variable('Property'), - erl_syntax:variable('Val') - ] - )] + [ + erl_syntax:application( + erl_syntax:atom(maps), + erl_syntax:atom(get), + [ + erl_syntax:variable('Property'), + erl_syntax:variable('Val') + ] + ) + ] ) ), erl_syntax:case_expr( @@ -2807,7 +2953,7 @@ is_valid_object( erl_syntax:variable('Prefix'), erl_syntax:variable('Reason') ]) - ]) + ]) ], none, [ @@ -2861,22 +3007,26 @@ is_valid_object( ), [ erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('false'), - erl_syntax:atom('none') - ])], + [ + erl_syntax:tuple([ + erl_syntax:atom('false'), + erl_syntax:atom('none') + ]) + ], none, [erl_syntax:atom(true)] ), erl_syntax:clause( - [erl_syntax:tuple([ - erl_syntax:atom('true'), - erl_syntax:variable('PropertyName'), + [ erl_syntax:tuple([ - erl_syntax:variable('Prefix'), - erl_syntax:variable('Reason') + erl_syntax:atom('true'), + erl_syntax:variable('PropertyName'), + erl_syntax:tuple([ + erl_syntax:variable('Prefix'), + erl_syntax:variable('Reason') + ]) ]) - ])], + ], none, [ erl_syntax:tuple([ @@ -2891,7 +3041,9 @@ is_valid_object( erl_syntax:atom('io_lib'), erl_syntax:atom('format'), [ - erl_syntax:string("Property \"~ts\" failed validation: ~ts"), + erl_syntax:string( + "Property \"~ts\" failed validation: ~ts" + ), erl_syntax:list([ erl_syntax:variable('PropertyName'), erl_syntax:variable('Reason') @@ -2921,7 +3073,7 @@ is_valid_object(_Prefix, additional_properties, _Schema) -> Keyword :: atom(), Value :: term(), Result :: undefined | erl_syntax:syntaxTree(). -is_valid_string(Prefix, min_length, MinLength) -> +is_valid_string(Prefix, min_length, MinLength) -> FunName = <>, TrueClause = erl_syntax:clause( [erl_syntax:variable('Val')], @@ -2934,20 +3086,30 @@ is_valid_string(Prefix, min_length, MinLength) -> [ erl_syntax:clause( [erl_syntax:variable('N')], - [erl_syntax:infix_expr( - erl_syntax:variable('N'), - erl_syntax:operator('>='), - erl_syntax:integer(MinLength) - )], + [ + erl_syntax:infix_expr( + erl_syntax:variable('N'), + erl_syntax:operator('>='), + erl_syntax:integer(MinLength) + ) + ], [erl_syntax:atom('true')] ), erl_syntax:clause( [erl_syntax:variable('_')], none, - [false_return(FunName, lists:flatten(io_lib:format("Value is lower than minimum allowed (~p)", [MinLength])))] + [ + false_return( + FunName, + lists:flatten( + io_lib:format("Value is lower than minimum allowed (~p)", [ + MinLength + ]) + ) + ) + ] ) ] - ) ] ), @@ -2968,20 +3130,30 @@ is_valid_string(Prefix, max_length, MaxLength) -> [ erl_syntax:clause( [erl_syntax:variable('N')], - [erl_syntax:infix_expr( - erl_syntax:variable('N'), - erl_syntax:operator('=<'), - erl_syntax:integer(MaxLength) - )], + [ + erl_syntax:infix_expr( + erl_syntax:variable('N'), + erl_syntax:operator('=<'), + erl_syntax:integer(MaxLength) + ) + ], [erl_syntax:atom('true')] ), erl_syntax:clause( [erl_syntax:variable('_')], none, - [false_return(FunName, lists:flatten(io_lib:format("Value is greater than maximum allowed (~p)", [MaxLength])))] + [ + false_return( + FunName, + lists:flatten( + io_lib:format("Value is greater than maximum allowed (~p)", [ + MaxLength + ]) + ) + ) + ] ) ] - ) ] ), @@ -3160,7 +3332,11 @@ is_valid_string(Prefix, format, base64) -> erl_syntax:clause( [erl_syntax:variable('_Char')], none, - [false_return(FunName, "Value is an invalid base64 string.")] + [ + false_return( + FunName, "Value is an invalid base64 string." + ) + ] ) ]), erl_syntax:application( @@ -3273,7 +3449,7 @@ chain_conditions(_FunName, {mfa_call, BodyFunCalls}, 'orelse') -> ) ]; chain_conditions(_FunName, {fun_call, BodyFunCalls}, 'andalso') -> - IndexedBodyFunCalls = lists:zip(lists:seq(0, length(BodyFunCalls)-1), BodyFunCalls), + IndexedBodyFunCalls = lists:zip(lists:seq(0, length(BodyFunCalls) - 1), BodyFunCalls), FunCallNames = [ {list_to_atom("F" ++ integer_to_list(Index)), BodyFunCall} || {Index, BodyFunCall} <- IndexedBodyFunCalls @@ -3332,7 +3508,7 @@ clauses(Clauses) -> false_clause(FunName, ErrorMessage) -> erl_syntax:clause( - [erl_syntax:variable('Val')], + [erl_syntax:variable('_Val')], none, [false_return(FunName, ErrorMessage)] ). @@ -3342,7 +3518,11 @@ false_return(FunName, ErrorMessage) -> erl_syntax:atom('false'), erl_syntax:tuple([ erl_syntax:atom(binary_to_list(FunName)), - erl_syntax:string(ErrorMessage) + erl_syntax:binary([ + erl_syntax:binary_field( + erl_syntax:string(ErrorMessage) + ) + ]) ]) ]). diff --git a/src/ndto_utils.erl b/src/ndto_utils.erl index 7844d22..fdc548e 100644 --- a/src/ndto_utils.erl +++ b/src/ndto_utils.erl @@ -6,27 +6,9 @@ mfoldl/3, find/2, find_value/2, - remove_all_of_prefix/1, format_properties/1 ]). --export([test/0]). - -test() -> - lists:foreach( - fun({Idx, Schema, Values}) -> - DTO = ndto:generate(schema, Schema), - ok = ndto:load(DTO, [report]), - file:write_file("generated.erl", erl_prettypr:format(DTO)), - io:format("################# ~p~n",[Idx]), - lists:foreach( - fun(Val) -> io:format("~p -> ~n~p~n~n",[Val, schema:is_valid(Val)]) end, - Values - ) - end, - element(2, file:consult("many_schemas.erl")) - ). - %%%----------------------------------------------------------------------------- %%% EXTERNAL EXPORTS %%%----------------------------------------------------------------------------- @@ -44,15 +26,16 @@ evalue_conditions(FunctionName, {_ConditionsType, []}, _EvalueMode, _IsSchemaCom {false, {FunctionName, <<"Value is not matching any of the (0) given conditions">>}}; evalue_conditions(FunctionName, {ConditionsType, Conditions}, 'andalso', true) -> case internal_evalue_conditions(ConditionsType, Conditions, 'andalso') of - true -> true; + true -> + true; {false, {AllOfReasonPath, ReasonMsg}, N} -> - ReasonPath = remove_all_of_prefix(atom_to_list(AllOfReasonPath)), + ReasonPath = atom_to_list(AllOfReasonPath), {false, { - FunctionName, + FunctionName, list_to_binary( lists:flatten( io_lib:format( - "Value is not matching all conditions. Condition ~p failed because of schema path '~ts' : ~ts", + "Value is not matching all conditions. Condition ~p failed because of schema path '~ts' : ~ts", [N, list_to_atom(ReasonPath), ReasonMsg] ) ) @@ -62,14 +45,13 @@ evalue_conditions(FunctionName, {ConditionsType, Conditions}, 'andalso', true) - evalue_conditions(_FunctionName, {ConditionsType, Conditions}, EvalueMode, false) -> case internal_evalue_conditions(ConditionsType, Conditions, EvalueMode) of true -> true; - {false, {ReasonPath, ReasonMsg}, _N} -> - {false, {ReasonPath, ReasonMsg}} + {false, {ReasonPath, ReasonMsg}, _N} -> {false, {ReasonPath, ReasonMsg}} end; evalue_conditions(FunctionName, {ConditionsType, Conditions}, EvalueMode, _IsSchemaComposition) -> case internal_evalue_conditions(ConditionsType, Conditions, EvalueMode) of true -> true; - false -> + false -> {false, { FunctionName, <<"Value is not matching at least one condition. None matched.">> @@ -119,9 +101,9 @@ mfoldl(Fun, Acc, [H | T]) -> List :: list(), Resp :: {true, FoundItem} | {false, none}, FoundItem :: term(). -find(_Fun, []) -> +find(_Fun, []) -> {false, none}; -find(Fun, [H|T]) -> +find(Fun, [H | T]) -> case Fun(H) of false -> find(Fun, T); true -> {true, H} @@ -130,33 +112,30 @@ find(Fun, [H|T]) -> -spec find_value(Fun, List) -> Resp when Fun :: function(), List :: list(), - Resp :: {true, FoundResult} | {false, none}, - FoundResult :: term(). -find_value(_Fun, []) -> + Resp :: {true, ListElement, FunResult} | {false, none}, + ListElement :: term(), + FunResult :: term(). +find_value(_Fun, []) -> {false, none}; -find_value(Fun, [H|T]) -> +find_value(Fun, [H | T]) -> case Fun(H) of false -> find_value(Fun, T); {true, Result} -> {true, H, Result} end. -spec format_properties(List) -> Resp when - List :: list(Property), + List :: nonempty_list(Property), Property :: binary(), Resp :: binary(). format_properties([Head | List]) -> - lists:foldl(fun(Term, Acc) -> + lists:foldl( + fun(Term, Acc) -> <> end, <<"\"", Head/binary, "\"">>, List ). - - -remove_all_of_prefix(ReasonPath) -> - re:replace(ReasonPath, "[\.]?_all_of\[[0-9]*\]", "", [{return, list}]). - %%%----------------------------------------------------------------------------- %%% INTERNAL FUNCTIONS %%%----------------------------------------------------------------------------- @@ -165,19 +144,26 @@ remove_all_of_prefix(ReasonPath) -> CurrentResult :: true | {false, term()}, Conditions :: [Condition], Condition :: {fun_call, fun()} | {mfa_call, {function(), term()}}, - EvalueMode :: 'orelse' | 'andalso' | 'xor' | {'xor', 0 | 1}, - Resp :: boolean() | {false, term()}. + EvalueMode :: + 'orelse' + | 'andalso' + | {'andalso', ConditionIndex} + | 'xor' + | {'xor', ConditionIndex, MatchedIndexes}, + ConditionIndex :: non_neg_integer(), + MatchedIndexes :: [ConditionIndex], + Resp :: boolean() | {false, Reason} | {false, AndalsoReason, ConditionIndex}, + Reason :: none_matched | {many_matched, MatchedIndexes}, + AndalsoReason :: term(). next_evalue_condition(_ConditionsType, true, _Rest, 'orelse') -> true; next_evalue_condition(_ConditionsType, _Result, [], 'orelse') -> false; next_evalue_condition(ConditionsType, {false, _}, Rest, 'orelse') -> internal_evalue_conditions(ConditionsType, Rest, 'orelse'); - next_evalue_condition(ConditionsType, Result, Rest, 'xor') -> ConditionIndex = length(Rest), next_evalue_condition(ConditionsType, Result, Rest, {'xor', ConditionIndex, []}); - next_evalue_condition(_ConditionsType, true, [], {'xor', _N, []}) -> true; next_evalue_condition(_ConditionsType, _Result, [], {'xor', _N, []}) -> @@ -187,12 +173,11 @@ next_evalue_condition(_ConditionsType, true, _Rest, {'xor', N, [One]}) -> next_evalue_condition(_ConditionsType, _Result, [], {'xor', _N, [_One]}) -> true; next_evalue_condition(ConditionsType, true, Rest, {'xor', N, []}) -> - internal_evalue_conditions(ConditionsType, Rest, {'xor', N-1, [N]}); + internal_evalue_conditions(ConditionsType, Rest, {'xor', N - 1, [N]}); next_evalue_condition(ConditionsType, {false, _}, Rest, {'xor', N, []}) -> - internal_evalue_conditions(ConditionsType, Rest, {'xor', N-1, []}); + internal_evalue_conditions(ConditionsType, Rest, {'xor', N - 1, []}); next_evalue_condition(ConditionsType, {false, _}, Rest, {'xor', N, [One]}) -> - internal_evalue_conditions(ConditionsType, Rest, {'xor', N-1, [One]}); - + internal_evalue_conditions(ConditionsType, Rest, {'xor', N - 1, [One]}); next_evalue_condition(_ConditionsType, Result, Rest, 'andalso') -> ConditionIndex = length(Rest), next_evalue_condition(_ConditionsType, Result, Rest, {'andalso', ConditionIndex}); @@ -201,6 +186,6 @@ next_evalue_condition(_ConditionsType, true, [], {'andalso', _N}) -> next_evalue_condition(_ConditionsType, {false, Reason}, [], {'andalso', N}) -> {false, Reason, N}; next_evalue_condition(ConditionsType, true, Rest, {'andalso', N}) -> - internal_evalue_conditions(ConditionsType, Rest, {'andalso', N-11}); + internal_evalue_conditions(ConditionsType, Rest, {'andalso', N - 11}); next_evalue_condition(_ConditionsType, {false, Reason}, _Rest, {'andalso', N}) -> {false, Reason, N}. diff --git a/src/smthing.erl b/src/smthing.erl deleted file mode 100644 index afbce57..0000000 --- a/src/smthing.erl +++ /dev/null @@ -1,73 +0,0 @@ -%%% Copyright 2024 Nomasystems, S.L. http://www.nomasystems.com -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License -%%% NOTE: Module generated by ndto, do not modify this file. --module(smthing). --feature(maybe_expr, enable). -%%% EXTERNAL EXPORTS --export([is_valid/1]). - -%%%----------------------------------------------------------------------------- -%%% EXTERNAL EXPORTS -%%%----------------------------------------------------------------------------- -is_valid(Val) -> '$.'(Val). - -%%%----------------------------------------------------------------------------- -%%% INTERNAL FUNCTIONS -%%%----------------------------------------------------------------------------- -'$.'(Val) -> - maybe - true ?= '$._object'(Val), - true ?= '$._max_properties'(Val), - true ?= '$._min_properties'(Val), - true ?= '$._required'(Val), - true ?= '$.*'(Val), - true - end. - -'$._object'(Val) when is_map(Val) -> true; -'$._object'(Val) -> - {false, - {'$.', - erlang:list_to_binary(io_lib:format("~p is not a object", - [Val]))}}. - -'$._max_properties'(Val) -> - erlang:length(maps:keys(Val)) =< 2. - -'$._min_properties'(Val) -> - erlang:length(maps:keys(Val)) >= 0. - -'$._required'(Val) -> - case ndto_utils:find(fun (Property) -> - not maps:is_key(Property, Val) - end, - [<<"$}N+l">>]) - of - {false, none} -> true; - {true, MissingProperty} -> - {false, - {'$.', - erlang:list_to_binary(lists:flatten(io_lib:format("$. is missing required property ~s", - [MissingProperty])))}} - end. - -'$.*'(Val) -> - maybe - true ?= '$.$}N+lany'(maps:get(<<"$}N+l">>, - Val, - undefined)), - true - end. - -'$.$}N+lany'(_Val) -> true. \ No newline at end of file diff --git a/test/ndto_SUITE.erl b/test/ndto_SUITE.erl index 38b7a04..faf6e25 100644 --- a/test/ndto_SUITE.erl +++ b/test/ndto_SUITE.erl @@ -168,9 +168,17 @@ nullable(_Conf) -> DTO2 = ndto:generate(test_nullable2, Schema2), ok = ndto:load(DTO2), + <> = TypeBin = atom_to_binary(Type), + Article = + case Char of + Vocal when Vocal =:= <<"a">>; Vocal =:= <<"o">>; Vocal =:= <<"i">> -> + <<"an">>; + _ -> + <<"a">> + end, ?assertEqual( - {false, {'$.type', <<"null is not a ", (atom_to_binary(Type))/binary>>}}, + {false, {'$.type', <<"Value is not ", Article/binary, " ", TypeBin/binary>>}}, test_nullable2:is_valid(null) ) end, @@ -186,10 +194,18 @@ one_of(_Conf) -> ] }, DTO = ndto:generate(test_one_of, Schema), - ok = ndto:load(DTO, [report]), + ok = ndto:load(DTO), - ?assertEqual({false, {'$.one_of', <<"Value is not matching exactly one condition. None matched.">>}}, test_one_of:is_valid(<<"0">>)), - ?assertEqual({false, {'$.one_of', <<"Value is not matching exactly one condition. More than one (conditions 0 and 1) matched.">>}}, test_one_of:is_valid(1)), + ?assertEqual( + {false, {'$.one_of', <<"Value is not matching exactly one condition. None matched.">>}}, + test_one_of:is_valid(<<"0">>) + ), + ?assertEqual( + {false, + {'$.one_of', + <<"Value is not matching exactly one condition. More than one (conditions 0 and 1) matched.">>}}, + test_one_of:is_valid(1) + ), ?assertEqual(true, test_one_of:is_valid(0.0)). any_of(_Conf) -> @@ -201,9 +217,12 @@ any_of(_Conf) -> ] }, DTO = ndto:generate(test_any_of, Schema), - ok = ndto:load(DTO, [report]), + ok = ndto:load(DTO), - ?assertEqual({false,{'$.any_of', <<"Value is not matching at least one condition. None matched.">>}}, test_any_of:is_valid(<<"0">>)), + ?assertEqual( + {false, {'$.any_of', <<"Value is not matching at least one condition. None matched.">>}}, + test_any_of:is_valid(<<"0">>) + ), ?assertEqual(true, test_any_of:is_valid(0)), ?assertEqual(true, test_any_of:is_valid(0.0)). @@ -218,14 +237,23 @@ all_of(_Conf) -> ok = ndto:load(DTO), ?assertEqual( - {false, {'$.all_of', <<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].type' : <<\"1\">> is not a integer">>}}, + {false, + {'$.all_of', + <<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].type' : Value is not an integer">>}}, test_all_of:is_valid(<<"1">>) ), ?assertEqual( - {false,{'$.all_of',<<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].minimum' : 0 is not a number greater or equal to 1">>}}, + {false, + {'$.all_of', + <<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].minimum' : Value is not a number greater or equal to 1">>}}, test_all_of:is_valid(0) ), - ?assertEqual({false,{'$.all_of',<<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].type' : 1.0 is not a integer">>}}, test_all_of:is_valid(1.0)), + ?assertEqual( + {false, + {'$.all_of', + <<"Value is not matching all conditions. Condition 1 failed because of schema path '$.all_of[1].type' : Value is not an integer">>}}, + test_all_of:is_valid(1.0) + ), ?assertEqual(true, test_all_of:is_valid(1)). 'not'(_Conf) -> @@ -233,7 +261,7 @@ all_of(_Conf) -> 'not' => #{type => integer, minimum => 0} }, DTO = ndto:generate(test_not, Schema), - ok = ndto:load(DTO, [report]), + ok = ndto:load(DTO), ?assertEqual(false, test_not:is_valid(0)), ?assertEqual(true, test_not:is_valid(<<"0">>)), @@ -260,7 +288,9 @@ pattern_properties(_Conf) -> ok = ndto:load(DTO), ?assertEqual( - {false,{'$.pattern_properties."[a-z]+".type',<<"Property \"foo\" failed validation: 0 is not a string">>}}, + {false, + {'$.pattern_properties."[a-z]+".type', + <<"Property \"foo\" failed validation: Value is not a string">>}}, test_pattern_properties:is_valid(#{<<"foo">> => 0}) ), ?assertEqual(true, test_pattern_properties:is_valid(#{<<"foo">> => <<"bar">>})), @@ -282,7 +312,9 @@ additional_properties(_Conf) -> test_additional_properties1:is_valid(#{<<"foo">> => <<"bar">>, <<"baz">> => <<"qux">>}) ), ?assertEqual( - {false,{'$.pattern_properties.\"[a-z]+\".type',<<"Property \"foobar\" failed validation: 0 is not a string">>}}, + {false, + {'$.pattern_properties.\"[a-z]+\".type', + <<"Property \"foobar\" failed validation: Value is not a string">>}}, test_additional_properties1:is_valid(#{ <<"foo">> => <<"bar">>, <<"baz">> => <<"qux">>, <<"foobar">> => 0 }) @@ -315,11 +347,15 @@ additional_properties(_Conf) -> ok = ndto:load(DTO3, [report]), ?assertEqual( - {false,{'$.pattern_properties.\"[a-z]+\".type',<<"Property \"baz\" failed validation: true is not a string">>}}, + {false, + {'$.pattern_properties.\"[a-z]+\".type', + <<"Property \"baz\" failed validation: Value is not a string">>}}, test_additional_properties3:is_valid(#{<<"foo">> => <<"bar">>, <<"baz">> => true}) ), ?assertEqual( - {false,{'$.additional_properties.type',<<"Property \"1\" failed validation: <<\"baz\">> is not a boolean">>}}, + {false, + {'$.additional_properties.type', + <<"Property \"1\" failed validation: Value is not a boolean">>}}, test_additional_properties3:is_valid(#{<<"foo">> => <<"bar">>, <<"1">> => <<"baz">>}) ), ?assertEqual( @@ -339,7 +375,7 @@ additional_properties(_Conf) -> ), ?assertEqual( - {false,{'$.additional_properties',<<"There are unsupported additional keys: \"Foo\"">>}}, + {false, {'$.additional_properties', <<"Object has unsupported keys: \"Foo\"">>}}, test_additional_properties4:is_valid(#{<<"Foo">> => true, <<"BAR">> => 1}) ). @@ -411,8 +447,7 @@ petstore(_Conf) -> lists:foreach( fun({SchemaName, Schema}) -> DTO = ndto:generate(SchemaName, Schema), - file:write_file("../../../../generated/" ++ atom_to_list(SchemaName)++".erl", erl_prettypr:format(DTO)), - ok = ndto:load(DTO, [report]) + ok = ndto:load(DTO) end, Schemas ),