From 90ce111b01108b8c526c89399750af0ff34162a3 Mon Sep 17 00:00:00 2001 From: Lisa Bevemyr Date: Fri, 30 Jul 2021 14:35:41 +0200 Subject: [PATCH] Add yin plugin This commit adds the yin plugin which generates yin from the input YANG model, along with tests to compare the Pyang YIN plugin. Two different options are available for the plugin: - pretty strings, will print strings on multiple lines - canonical, prints elements in canonical order --- plugins/yanger_yin.erl | 414 +++++++++ test/lux/yin/Makefile | 8 + test/lux/yin/parent.yang | 11 + test/lux/yin/small6.yang | 36 + test/lux/yin/test_good/a.yang | 30 + test/lux/yin/test_good/b.yang | 12 + test/lux/yin/test_good/q.yang | 6 + test/lux/yin/test_good/qs.yang | 20 + test/lux/yin/test_good/w.yang | 42 + test/lux/yin/test_good/xt10.yang | 15 + test/lux/yin/test_good/xt5.yang | 28 + test/lux/yin/test_good/xt6.yang | 18 + test/lux/yin/test_good/xt7.yang | 29 + test/lux/yin/test_good/yt10.yang | 36 + test/lux/yin/test_good/yt5.yang | 203 +++++ test/lux/yin/test_good/yt6.yang | 129 +++ test/lux/yin/test_good/yt7.yang | 44 + test/lux/yin/test_good/yt8.yang | 27 + test/lux/yin/test_good/yt9.yang | 20 + test/lux/yin/yin_plugin_macro.lux | 57 ++ test/lux/yin/yin_plugin_macro_cannoical.lux | 805 ++++++++++++++++++ .../yin/yin_plugin_macro_pretty_strings.lux | 57 ++ 22 files changed, 2047 insertions(+) create mode 100644 plugins/yanger_yin.erl create mode 100644 test/lux/yin/Makefile create mode 100644 test/lux/yin/parent.yang create mode 100644 test/lux/yin/small6.yang create mode 100644 test/lux/yin/test_good/a.yang create mode 100644 test/lux/yin/test_good/b.yang create mode 100644 test/lux/yin/test_good/q.yang create mode 100644 test/lux/yin/test_good/qs.yang create mode 100644 test/lux/yin/test_good/w.yang create mode 100644 test/lux/yin/test_good/xt10.yang create mode 100644 test/lux/yin/test_good/xt5.yang create mode 100644 test/lux/yin/test_good/xt6.yang create mode 100644 test/lux/yin/test_good/xt7.yang create mode 100644 test/lux/yin/test_good/yt10.yang create mode 100644 test/lux/yin/test_good/yt5.yang create mode 100644 test/lux/yin/test_good/yt6.yang create mode 100644 test/lux/yin/test_good/yt7.yang create mode 100644 test/lux/yin/test_good/yt8.yang create mode 100644 test/lux/yin/test_good/yt9.yang create mode 100644 test/lux/yin/yin_plugin_macro.lux create mode 100644 test/lux/yin/yin_plugin_macro_cannoical.lux create mode 100644 test/lux/yin/yin_plugin_macro_pretty_strings.lux diff --git a/plugins/yanger_yin.erl b/plugins/yanger_yin.erl new file mode 100644 index 0000000..cdd91c0 --- /dev/null +++ b/plugins/yanger_yin.erl @@ -0,0 +1,414 @@ +%%%----------------------------------------------------------------%%% +%%% @doc Yanger Yin Plugin %%% +%%% @author Lisa Bevemyr, lbevemyr@cisco.com (summer intern 2021) %%% +%%% Prints YIN from a YANG model according to the rules in RFC %%% +%%% 7950. Inspiration for this plugin came from a the similar %%% +%%% plugin for Pyang and the YANG plugin for Yanger. %%% +%%%----------------------------------------------------------------%%% + +-module(yanger_yin). +-behaviour(yanger_plugin). + +-export([init/1]). + +-include_lib("yanger/include/yang.hrl"). + +-spec help() -> binary(). +help() -> + <<"Translates a YANG module to YIN \n\n" + "The following options can be used to modify the output:\n\n" + " --yin-canonical Will sort the output in canonical order.\n" + " --yin-pretty-strings Texts will be printed on multiple lines.\n" + >>. +init(Ctx0) -> + Ctx1 = yanger_plugin:register_output_format(Ctx0, yin, fun emit/3), + Ctx2 = yanger_plugin:register_hook( + Ctx1, #hooks.post_init_ctx, fun post_init_ctx/1), + Ctx3 = yanger_plugin:register_option_specs(Ctx2, opts()), + Ctx3. + +opts() -> + [{"YANG output specific options:", + [{yin_canonical, undefined, "yin-canonical", {boolean, false}, + "Print in canonical order"}, + {yin_comment, undefined, "yin-pretty-strings", {boolean, false}, + "Pretty print strings"}, + {yin_help, undefined, "yin-help", boolean, + "Prints help on YIN plugin"} + ]}]. + +-record(state, {module, + module_prefixes, + outf, + canonical = false, + pretty_strings = false, + columns = 80, + rps, + yin_map, + ctx, + order_map = #{} + }). + +post_init_ctx(Ctx) -> + case proplists:get_value(yin_help, Ctx#yctx.options, false) of + true -> + io:put_chars(help()), + halt(); + false -> + ok + end, + Ctx. + +-spec emit(Ctx::#yctx{}, [Modules::#module{}], Fd::io:device()) -> []. +emit(Ctx, Modules, Fd) -> + OutF = fun (Str) -> file:write(Fd, Str) end, + State = + #state{ outf = OutF, + canonical = + proplists:get_value(yin_canonical, Ctx#yctx.options), + pretty_strings = + proplists:get_value(yin_comment, Ctx#yctx.options), + rps = [{binary:compile_pattern(RP), RWith} || + {RP, RWith} <- replace_patterns()], + yin_map = get_yin_map(), + ctx = Ctx + }, + lists:foreach( + fun (M) -> + ModuleMap = + yang:map_foldl(fun (Px, '$self', Map0) -> + Mod = M#module.name, + yang:map_insert(Mod, Px, Map0); + (Px, Mod, Map0) -> + yang:map_update(Mod, Px, Map0) + end, + yang:map_new(), + M#module.prefix_map), + State1 = State#state{ + module = M, + module_prefixes = ModuleMap + }, + emit_module(M, State1) + end, Modules), + %% If this format plugin will need to produce warnings or errors + %% in the future, these warnings and errors need to be returned here. + Errors = [], + Errors. + +emit_module(M, State) -> + OutF = State#state.outf, + OutF(["", nl()]), + emit_stmts([M#module.stmt], 0, State). + +emit_stmts([], _Lvl, _S) -> + ok; +emit_stmts([Stmt|Stmts], Lvl, S) -> + OutF = S#state.outf, + Keyword = yang:stmt_keyword(Stmt), + emit_stmt_keyword(Keyword, Lvl, S), + YinElement = emit_stmt_arg(yang:stmt_arg(Stmt), Lvl, S, Keyword), + module_arg(Lvl, S, Keyword), + case yang:stmt_substmts(Stmt) of + [] when not YinElement -> + NewS = S, + OutF([fs(),ct(),nl()]); + SubStmts0 -> + OutF([ct(),nl()]), + {NewS, SubStmts} = + if S#state.canonical -> + sort_canonical(Keyword, SubStmts0, S); + true -> + {S, SubStmts0} + end, + emit_stmts(SubStmts, Lvl+1, NewS), + KeywordStr = make_str(Keyword), + OutF([indent(Lvl),ot(),fs(),KeywordStr,ct(),nl()]) + end, + emit_stmts(Stmts, Lvl, NewS). + +emit_stmt_keyword(Kwd, Lvl, S) -> + OutF = S#state.outf, + OutF(indent(Lvl)), + case Kwd of + {Module, Keyword} -> + Prefix = yang:map_get(Module, S#state.module_prefixes), + OutF([ot(), make_str({Prefix, Keyword})]); + Keyword -> + OutF([ot(), make_str(Keyword)]) + end. + +emit_stmt_arg([], _, _, _) -> + false; +emit_stmt_arg(Arg, Lvl, S, Keyword) -> + OutF = S#state.outf, + ArgStr = make_str(Arg), + Ctx = S#state.ctx, + if is_tuple(Keyword) -> + {Type, YinElement} = search_for_extension(Keyword, Ctx), + if YinElement -> + {Prefix, _} = Keyword, + TypeStr = make_str({Prefix, Type}); + true -> + TypeStr = make_str(Type) + end; + true -> + {Type, YinElement} = maps:get(Keyword, S#state.yin_map), + TypeStr = make_str(Type) + end, + case YinElement of + true -> + Indent = indent(Lvl+1), + Strs = binary:split( + ArgStr, binary:compile_pattern(<<"\n">>), [global]), + Acc = print_yin_element(Indent, TypeStr, Strs, S), + OutF(Acc); + false -> + OutF([s(), TypeStr, $=, qm(), + escape(ArgStr, S#state.rps), qm()]) + end, + YinElement. + +search_for_extension({Mod, Keyword}, Ctx) -> + {_, TargetMod} = yang:get_module(Mod, undefined, Ctx), + ExtensionMap = yang:map_get(Keyword, TargetMod#module.extensions), + {extension, Keyword, _Pos, Substmt} = ExtensionMap#extension.stmt, + case yang:search_one_stmt('argument', Substmt) of + {argument,Type,_,ArgSubstmt} -> + case yang:search_one_stmt('yin-element', ArgSubstmt) of + {'yin-element', Bool,_,_} -> + {Type, Bool}; + false -> + {Type, false} + end; + false -> + {undefined, false} + end. + +print_yin_element(Indent, TypeStr, [Str1|Strs], S) -> + Pretty = S#state.pretty_strings, + case Pretty of + true -> + Acc = [ct(),nl(), Indent, ot(), TypeStr, ct(),nl(), Indent, s(),s(), + escape(Str1, S#state.rps)]; + false -> + Acc = [ct(), nl(), Indent, ot(), TypeStr, ct(), + escape(Str1, S#state.rps)] + end, + print_yin_element1(Indent, TypeStr, Strs, S, Pretty, Acc). + +print_yin_element1(Indent, TypeStr, [], _S, true = _Pretty, Acc) -> + [Acc, nl(), Indent, ot(), fs(), TypeStr]; + +print_yin_element1(_Indent, TypeStr, [], _S, false = _Pretty, Acc) -> + [Acc, ot(), fs(), TypeStr]; + +print_yin_element1(Indent, TypeStr, [Str1|Strs], S, Pretty, Acc) -> + Acc1 = [Acc, nl(), escape(Str1, S#state.rps)], + print_yin_element1(Indent, TypeStr, Strs, S, Pretty, Acc1). + +module_arg(Lvl, S, Module) when Module == module orelse Module == submodule -> + Mod = S#state.module, + Ctx = S#state.ctx, + OutF = S#state.outf, + Indent = case Module of + module -> indent(Lvl+4); + submodule -> indent(Lvl+5,1) + end, + OutF([nl(), Indent, "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""]), + Namespace = search_for_namespace(Mod#module.namespace, Mod, Ctx), + NamespaceStr = make_str(Namespace), + PrefixStr = make_str(Mod#module.prefix), + case Namespace of + undefined -> + skip; + _ -> + OutF([nl(), Indent, "xmlns:", PrefixStr, $=, + qm(), NamespaceStr, qm()]) + end, + Imports = Mod#module.imports, + module_arg_imports(S, Ctx, Imports, Indent); + +module_arg(_Lvl, _S, _) -> skip. + +search_for_namespace(undefined, Mod, Ctx) -> + {_, TargetName} = Mod#module.xpath_ns_map, + Target = yang:search_module(Ctx, TargetName, undefined), + case Target of + {true, _, TargetMod} -> + make_str(TargetMod#module.namespace); + _ -> + undefined + end; + +search_for_namespace(Namespace, _Mod, _Ctx) -> + Namespace. + +module_arg_imports(_S, _Ctx, [], _Indent) -> + skip; +module_arg_imports(S, Ctx, [Import|Imports], Indent) -> + OutF = S#state.outf, + {Namespace, _, Prefix, _} = Import, + PrefixStr = make_str(Prefix), + {_Value, TargetM} = yang:get_module(Namespace, undefined, Ctx), + TargetMNamespaceStr = make_str(TargetM#module.namespace), + OutF([nl(), Indent, "xmlns:", PrefixStr, $=, + qm(), TargetMNamespaceStr, qm()]), + module_arg_imports(S, Ctx, Imports, Indent). + +sort_canonical(Keyword, SubStmts, S) -> + OrderMap = S#state.order_map, + case maps:get(Keyword, OrderMap, undefined) of + undefined -> + case yang_parser:get_statement_spec(Keyword) of + {value, {_, _, Rules, _}} -> + NewOrderMap = maps:put(Keyword, mk_order(Rules), OrderMap), + NewS = S#state{order_map = NewOrderMap}, + sort_canonical(Keyword, SubStmts, NewS); + _ -> + {S, SubStmts} + end; + Order -> + {S, lists:sort( + fun(A, B) -> + ordinal(yang:stmt_keyword(A), Order) =< + ordinal(yang:stmt_keyword(B), Order) + end, SubStmts)} + end. + +mk_order(Rules) -> + mk_order0(Rules, 0, gb_trees:empty()). + +mk_order0([{'$cut', _} | T], N, Tree) -> + mk_order0(T, N+1, Tree); +mk_order0([{Keyword, '?'} | T], N, Tree) -> + mk_order0(T, N+1, gb_trees:enter(Keyword, N, Tree)); +mk_order0([{Keyword, '1'} | T], N, Tree) -> + mk_order0(T, N+1, gb_trees:enter(Keyword, N, Tree)); +mk_order0([{Keyword, '*'} | T], N, Tree) -> + mk_order0(T, N, gb_trees:enter(Keyword, N, Tree)); + +mk_order0([], _, Tree) -> + Tree. + +ordinal(Keyword, Order) -> + case gb_trees:lookup(Keyword, Order) of + {value, N} -> + N; + _ -> + undefined + end. + +s() -> $\ . +nl() -> $\n. +ot() -> $<. +fs() -> $/. +ct() -> $>. +qm() -> $". + +indent(Lvl) -> lists:duplicate(Lvl*2, s()). +indent(Lvl,1) -> C = Lvl*2+1, lists:duplicate(C, s()). + +make_str({Prefix, Name}) -> + iolist_to_binary([make_str(Prefix), ":", make_str(Name)]); +make_str(A) when is_atom(A) -> + atom_to_binary(A, unicode); +make_str(Str) when is_binary(Str) -> + Str; +make_str(Int) when is_integer(Int) -> + integer_to_binary(Int); +make_str(Str) when is_list(Str) -> + iolist_to_binary(Str). + +escape(BStr, RPs) -> + lists:foldl( + fun({RPq, RWith}, BStr1) -> + binary:replace(BStr1, RPq, RWith, [global]) + end, BStr, RPs). + +replace_patterns() -> + [{<<"\\">>, <<"\\\\">>}, + {<<"\"">>, <<"\\\"">>}, + {<<"\t">>, <<"\\t">>}, + {<<"&">>, <<"&">>}, + {<<"<">>, <<"<">>}, + {<<">">>, <<"≷">>}, + {<<"\"">>, <<""">>}, + {<<"'">>, <<"'">>}]. + + + +%% Mapping of statements to the YIN representation of their arguments. +%% The values are pairs whose first component specifies whether the +%% argument is stored in a subelement and the second component is the +%% name of the attribute or subelement carrying the argument. See YANG +%% specification. +get_yin_map() -> + #{'action'=> {'name', false}, + 'anydata'=> {'name', false}, + 'anyxml'=> {'name', false}, + 'argument'=> {'name', false}, + 'augment'=> {'target-node', false}, + 'base'=> {'name', false}, + 'belongs-to'=> {'module', false}, + 'bit'=> {'name', false}, + 'case'=> {'name', false}, + 'choice'=> {'name', false}, + 'config'=> {'value', false}, + 'contact'=> {'text', true}, + 'container'=> {'name', false}, + 'default'=> {'value', false}, + 'description'=> {'text', true}, + 'deviate'=> {'value', false}, + 'deviation'=> {'target-node', false}, + 'enum'=> {'name', false}, + 'error-app-tag'=> {'value', false}, + 'error-message'=> {'value', true}, + 'extension'=> {'name', false}, + 'feature'=> {'name', false}, + 'fraction-digits'=> {'value', false}, + 'grouping'=> {'name', false}, + 'identity'=> {'name', false}, + 'if-feature'=> {'name', false}, + 'import'=> {'module', false}, + 'include'=> {'module', false}, + 'input'=> {undefined, undefined}, + 'key'=> {'value', false}, + 'leaf'=> {'name', false}, + 'leaf-list'=> {'name', false}, + 'length'=> {'value', false}, + 'list'=> {'name', false}, + 'mandatory'=> {'value', false}, + 'max-elements'=> {'value', false}, + 'min-elements'=> {'value', false}, + 'modifier'=> {'value', false}, + 'module'=> {'name', false}, + 'must'=> {'condition', false}, + 'namespace'=> {'uri', false}, + 'notification'=> {'name', false}, + 'ordered-by'=> {'value', false}, + 'organization'=> {'text', true}, + 'output'=> {undefined, undefined}, + 'path'=> {'value', false}, + 'pattern'=> {'value', false}, + 'position'=> {'value', false}, + 'presence'=> {'value', false}, + 'prefix'=> {'value', false}, + 'range'=> {'value', false}, + 'reference'=> {'text', true}, + 'refine'=> {'target-node', false}, + 'require-instance'=>{'value', false}, + 'revision'=> {'date', false}, + 'revision-date'=> {'date', false}, + 'rpc'=> {'name', false}, + 'status'=> {'value', false}, + 'submodule'=> {'name', false}, + 'type'=> {'name', false}, + 'typedef'=> {'name', false}, + 'unique'=> {'tag', false}, + 'units'=> {'name', false}, + 'uses'=> {'name', false}, + 'value'=> {'value', false}, + 'when'=> {'condition', false}, + 'yang-version'=> {'value', false}, + 'yin-element'=> {'value', false} + }. diff --git a/test/lux/yin/Makefile b/test/lux/yin/Makefile new file mode 100644 index 0000000..e106e8a --- /dev/null +++ b/test/lux/yin/Makefile @@ -0,0 +1,8 @@ +include ../../support/*_testcases.mk + +build: + +clean: + rm -rf lux_logs _tmp_* + +.PHONY: build clean diff --git a/test/lux/yin/parent.yang b/test/lux/yin/parent.yang new file mode 100644 index 0000000..0ffdd6f --- /dev/null +++ b/test/lux/yin/parent.yang @@ -0,0 +1,11 @@ +module parent { + namespace urn:parent; + prefix parent; + + container parent-container { + // to be augmented by small6 + } + container parent-container-2 { + // to be augmented by small6 + } +} diff --git a/test/lux/yin/small6.yang b/test/lux/yin/small6.yang new file mode 100644 index 0000000..cc73e68 --- /dev/null +++ b/test/lux/yin/small6.yang @@ -0,0 +1,36 @@ +module small6 { + namespace urn:r; + prefix rprefix; + + import parent { + prefix parentPrefix; + } + + augment "/parentPrefix:parent-container" { + list test-list { + key test-key; + + leaf test-key { + type string; + } + + leaf dummy { + type uint16; + } + } + } + + augment "/parentPrefix:parent-container-2" { + list test-list { + key test-key; + + leaf test-key { + type string; + } + + leaf dummy { + type uint16; + } + } + } +} diff --git a/test/lux/yin/test_good/a.yang b/test/lux/yin/test_good/a.yang new file mode 100644 index 0000000..cc55a8b --- /dev/null +++ b/test/lux/yin/test_good/a.yang @@ -0,0 +1,30 @@ +module a { + namespace "urn:a"; + prefix a; + + grouping a { + leaf a { + type leafref { + path "/a:x/a:y/a:k1"; + } + } + leaf b { + type leafref { + path "deref(../a)/../a:k2"; +// path "/a:x/a:y[a:k1 = current()/../a]/a:k2"; + } + } + } + + container x { + list y { + key "k1 k2"; + leaf k1 { + type string; + } + leaf k2 { + type string; + } + } + } +} diff --git a/test/lux/yin/test_good/b.yang b/test/lux/yin/test_good/b.yang new file mode 100644 index 0000000..418dcea --- /dev/null +++ b/test/lux/yin/test_good/b.yang @@ -0,0 +1,12 @@ +module b { + namespace "urn:b"; + prefix b; + + import a { + prefix a; + } + + container z { + uses a:a; + } +} \ No newline at end of file diff --git a/test/lux/yin/test_good/q.yang b/test/lux/yin/test_good/q.yang new file mode 100644 index 0000000..bb50bad --- /dev/null +++ b/test/lux/yin/test_good/q.yang @@ -0,0 +1,6 @@ +module q { + namespace urn:q; + prefix q; + + include qs; +} diff --git a/test/lux/yin/test_good/qs.yang b/test/lux/yin/test_good/qs.yang new file mode 100644 index 0000000..8fb625b --- /dev/null +++ b/test/lux/yin/test_good/qs.yang @@ -0,0 +1,20 @@ +submodule qs { + belongs-to q { + prefix q; + } + + extension foo { + argument id; + } + + identity foo; + + feature foo; + + grouping g { + leaf x { + type string; + } + } + +} diff --git a/test/lux/yin/test_good/w.yang b/test/lux/yin/test_good/w.yang new file mode 100644 index 0000000..f7baddf --- /dev/null +++ b/test/lux/yin/test_good/w.yang @@ -0,0 +1,42 @@ +module w { + namespace urn:w; + prefix w; + + import q { + prefix qq; + } + + identity g { + base qq:foo; + } + + grouping X { + leaf y { + qq:foo 42; + type uint32; + } + } + + grouping Y { + container z { + if-feature qq:foo; + uses X; + } + } + uses Y { + refine z/y { + default 42; + } + } + + container q { + uses qq:g; + } + leaf t { + type leafref { + path "/q/x"; + } + } + + +} diff --git a/test/lux/yin/test_good/xt10.yang b/test/lux/yin/test_good/xt10.yang new file mode 100644 index 0000000..f183f78 --- /dev/null +++ b/test/lux/yin/test_good/xt10.yang @@ -0,0 +1,15 @@ +module xt10 { + namespace "urn:xt10"; + prefix "xt10"; + + typedef a { + type string; + } + + leaf x { + type decimal64 { + fraction-digits 1; + range "-6.3..0.0"; + } + } +} diff --git a/test/lux/yin/test_good/xt5.yang b/test/lux/yin/test_good/xt5.yang new file mode 100644 index 0000000..72042e4 --- /dev/null +++ b/test/lux/yin/test_good/xt5.yang @@ -0,0 +1,28 @@ +module xt5 { + + namespace "urn:test:xt5"; + prefix xt5; + + grouping x { + leaf foo { type empty; mandatory true; } + } + + typedef xc { + type int32; + } + + extension x { + argument name; + } + + leaf foo { type int16; } + + + extension foo { + argument bar { + yin-element true; + } + } + + +} diff --git a/test/lux/yin/test_good/xt6.yang b/test/lux/yin/test_good/xt6.yang new file mode 100644 index 0000000..07f8ab1 --- /dev/null +++ b/test/lux/yin/test_good/xt6.yang @@ -0,0 +1,18 @@ +module xt6 { + + namespace "urn:test:xt6"; + prefix xt6; + + import xt5 { + prefix xt5; + } + + uses xt5:x; + + xt5:foo "barbar"; + + leaf y { + type xt5:xc; + } + +} diff --git a/test/lux/yin/test_good/xt7.yang b/test/lux/yin/test_good/xt7.yang new file mode 100644 index 0000000..a704959 --- /dev/null +++ b/test/lux/yin/test_good/xt7.yang @@ -0,0 +1,29 @@ +module xt7 { + prefix x; + namespace "urn:test:xt7"; + + leaf foo { + type int16; + x:foo "some string"; + } + + x:foo "another string"; + + extension foo { + argument bar { + yin-element false; + } + } + + grouping baz { + leaf x { + type int32; + } + } + uses baz { + refine x { + default 42; + } + } + +} diff --git a/test/lux/yin/test_good/yt10.yang b/test/lux/yin/test_good/yt10.yang new file mode 100644 index 0000000..c86e1de --- /dev/null +++ b/test/lux/yin/test_good/yt10.yang @@ -0,0 +1,36 @@ +module yt10 { + + namespace "urn:ietf:params:xml:ns:yang:yt10"; + + prefix "yt10"; + + import yt9 { prefix yt9; } + + organization "Netconf Central"; + + contact "Andy Bierman"; + + description "YANG test module 9. augment"; + + revision 2008-04-11 { description "initial version"; } + + augment /yt9:con1 { + leaf b1 { type int32; } + + container con2 { + leaf b2 { type string; } + } + } + + container test { + description "Particular configuration to retrieve."; + // mandatory true; + uses Foo; + } + + grouping Foo { + leaf X { type int32; } + leaf Y { type uint32; } + } + +} diff --git a/test/lux/yin/test_good/yt5.yang b/test/lux/yin/test_good/yt5.yang new file mode 100644 index 0000000..e490356 --- /dev/null +++ b/test/lux/yin/test_good/yt5.yang @@ -0,0 +1,203 @@ +module yt5 { + + namespace "urn:ietf:params:xml:ns:yang:yt5"; + prefix "yt5"; + + organization + "YANG Language Design Team"; + + contact + "ietf@andybierman.com"; + + description + "YANG test module 5."; + + revision 2008-02-12 { + description "Update test cases."; + } + + revision 2007-12-26 { + description "Initial revision."; + } + + grouping G_one { + typedef local_1 { type int32; units meters; default 0; } + leaf G_aaa { type int8; } + uses G_two; + leaf G_bbb { type uint8; } + leaf test_leaf { type local_1; } + } + + grouping G_two { + typedef local_1 { type string; default fred; } + leaf G_ccc { type binary; } + container G_ddd { + leaf G_eee { + type uint8; + mandatory true; + reference "RFC 2021"; + } + } + leaf test_leaf2 { type local_1; } + } + + container con2 { + + grouping AA { + leaf a { type A_typ; } + + container b { + container bb { + uses AAA; + } + grouping AAA { +// typedef B_typ { type instance-identifier; } + uses AAAA { +/* + extend "yt5:e/yt5:f" { + leaf hhh { type binary; } + leaf h { type B_typ; } + } +*/ + } + + leaf d { type int8; } + } + } + + grouping AAAA { + container e { + container f { + typedef con2 { description "duplicate test"; type int16; } + leaf g { type int64; } + leaf h { type con2; } + leaf i { type con2; } + } + } + } + + typedef A_typ { + type int32; + default 3; + units miles; + } + +/* not allowed anymore + augment b { + container c { + leaf cc { type string; } + } + } +*/ + } + + container con3 { + uses AA { +/* + extend "b/bb/e/f" { + container con4 { presence "means something"; } + } +*/ + } + } + } + + container foo { + uses foo; + } + + grouping foo { + leaf foo { type foo; } + } + + grouping bar { + leaf bar { type foo; } + leaf-list yyy { + type binary; + min-elements 2; + max-elements 12; + } + leaf baz { type int16; } + leaf goo { type foo; } + container zzz { + leaf zzzz { type uint32; } + } + } + + container foo2 { + typedef foobar { + type uint32; + } + grouping foobar { + leaf foo { type foo; } + } + container foo3 { + uses foobar; + leaf-list foo4 { type foobar; } + } + container foo4 { + uses yt5:foobar; + leaf-list foo4 { type foobar; } + } + } + + typedef foo { + type int32 { + range "-42 | -2 .. +7 | 8 | 41 | 42"; + } + } + + list foo3 { + uses foo; + key "foo baz bar"; + uses bar { +/* + extend zzz { + container con_zzz { + presence "enables foo3_zzz service"; + } + } +*/ + } + + unique "goo zzz/zzzz"; + } + + rpc rpc-one { + input { + leaf x {type int8; } + uses foo; + } + output { uses bar; } + } + + rpc rpc-two; + + rpc rpc-three { + input { + leaf a { type foo; } + container xx; + } + } + + augment /rpc-two/input { + leaf aa { type uint32; } + } + + augment /rpc-three/input/xx { + leaf aa { type uint32; } + } + + notification notif-one; + + notification notif-two { + leaf one { type string; } + anyxml two; + } + + notification notif-three { + uses foo; + } + +} + diff --git a/test/lux/yin/test_good/yt6.yang b/test/lux/yin/test_good/yt6.yang new file mode 100644 index 0000000..e327001 --- /dev/null +++ b/test/lux/yin/test_good/yt6.yang @@ -0,0 +1,129 @@ +module yt6 { + + namespace "urn:ietf:params:xml:ns:yang:yt6"; + prefix "yt6"; + + import ietf-yang-types { prefix y; } + + organization + "YANG Language Design Team"; + + contact + "Andy Bierman"; + + description + "YANG test module 6. Container, augment"; + + + typedef un-1 { + type union { // 16 + type union { // 17 + type int32; + type binary; + type union { // 20 + type string; + type binary; + type boolean; + } + } + type int64; + } + default 9; + } + + augment /foo/a/z { + leaf xxx { type binary; } + } + + augment /foo/a { + case zz { leaf zzz { type int64; } } + } + + + container foo { + leaf un { + type un-1; + config false; + default forty; + } + leaf bar1 { + type y:counter32; + } + leaf bar2 { + type int32; + default 10; + } + leaf bar3 { + type int32; + mandatory true; + } + leaf bar4 { + type int32; + mandatory false; + } + leaf bar5 { + type int32; + mandatory true; + // default 10; pyang says this is illegal + } + leaf bar6 { + type int32; + mandatory false; + default 10; + } + choice a { + default x; + leaf x { type int32; } + leaf y { type string; } + container z; + } + } + + list bar { + config false; + key bar1; + unique zz2; + leaf zz1 { type un-1; mandatory true; } + leaf zz2 { type y:zero-based-counter32; } + leaf-list zz3 { + description testing-one-two-three; + min-elements 4; + max-elements 14; + type y:date-and-time; + ordered-by user; + } + leaf bar1 { type un-1; } + } + + notification notif1 { + description "notification test"; + reference test-notif-1; + status deprecated; + container x { + list y { + reference "RFC 4741"; + leaf xx { type int32; } + leaf zz { type zz_type; } + + key xx; + + max-elements "77"; + min-elements "15"; + } + + leaf yy { type int32; default -123; } + + typedef zz_type { + type enumeration { + enum x; + enum y; + } + } + } + leaf x2 { type instance-identifier; } + anyxml x3 { description test-any; } + } + + notification notif2; + +} diff --git a/test/lux/yin/test_good/yt7.yang b/test/lux/yin/test_good/yt7.yang new file mode 100644 index 0000000..5eabbca --- /dev/null +++ b/test/lux/yin/test_good/yt7.yang @@ -0,0 +1,44 @@ +module yt7 { + + namespace "urn:ietf:params:xml:ns:yang:yt7"; + prefix "yt7"; + + import ietf-yang-types { prefix y; } + + organization + "YANG Language Design Team"; + + contact + "ietf@andybierman.com"; + + description + "YANG test module 7."; + + revision 2008-02-08 { + description "initial version."; + } + + rpc rpc1 { + description rpc-test; + reference "RFC 4741"; + input { + leaf a { type y:counter32; } + leaf b { type int32; } + container foo { + presence "enable foo service"; + } + } + output { + leaf x { type y:zero-based-counter32; } + container y { + container yy { + leaf yyy { type empty; } + anyxml zzz; + container zz; + } + } + } + } + + +} diff --git a/test/lux/yin/test_good/yt8.yang b/test/lux/yin/test_good/yt8.yang new file mode 100644 index 0000000..e5b6bbf --- /dev/null +++ b/test/lux/yin/test_good/yt8.yang @@ -0,0 +1,27 @@ +module yt8 { + + namespace "urn:ietf:params:xml:ns:yang:yt8"; + prefix "yt8"; + + organization + "YANG Language Design Team"; + + contact + "ietf@andybierman.com"; + + description + "YANG test module 8."; + + revision 2008-02-12 { + description "Initial revision."; + } + + typedef foo { + type int32 { + range "-42 | -2 .. +7 | 8 | 41 | 42" { + } + } + } + +} + diff --git a/test/lux/yin/test_good/yt9.yang b/test/lux/yin/test_good/yt9.yang new file mode 100644 index 0000000..889ab87 --- /dev/null +++ b/test/lux/yin/test_good/yt9.yang @@ -0,0 +1,20 @@ +module yt9 { + + namespace "urn:ietf:params:xml:ns:yang:yt9"; + + prefix "yt9"; + + organization "Netconf Central"; + + contact "Andy Bierman"; + + description "YANG test module 9. augment"; + + revision 2008-04-11 { description "initial version"; } + + leaf a1 { type int32; } + + container con1 { + leaf a2 { type string; } + } +} diff --git a/test/lux/yin/yin_plugin_macro.lux b/test/lux/yin/yin_plugin_macro.lux new file mode 100644 index 0000000..cb98532 --- /dev/null +++ b/test/lux/yin/yin_plugin_macro.lux @@ -0,0 +1,57 @@ +# author: lbevemyr@cisco.com +[doc Test of the yanger yin plugin. Comparing it to the predecessor pyang yin.] + +[macro yin_compare FILE] + ~yanger -f yin -p ${DIR} ${DIR}/${FILE} + ! | sed 's/ *$//' > test.yanger.yin + !echo ==$?== + ?==0== + + ~pyang --ignore-errors -f yin -p ${DIR} ${DIR}/${FILE} + ! | sed 's/ *$//' > test.pyang.yin + !echo ==$?== + ?==0== + + !diff -u test.pyang.yin test.yanger.yin + !echo ==$?== + ?==0== + - +[endmacro] + + +[shell test_yanger_yin] + [timeout 20] + + [global DIR=../tree] + [invoke yin_compare small2.yang] + [invoke yin_compare small3.yang] + [invoke yin_compare small4.yang] + [invoke yin_compare small5.yang] + [invoke yin_compare a.yang] + + # use pyang test modules + [global DIR=./test_good] + [invoke yin_compare yt5.yang] + [invoke yin_compare yt6.yang] + [invoke yin_compare yt7.yang] + [invoke yin_compare yt8.yang] + [invoke yin_compare yt9.yang] + [invoke yin_compare yt10.yang] + [invoke yin_compare qs.yang] + [invoke yin_compare q.yang] + [invoke yin_compare w.yang] + [invoke yin_compare xt5.yang] + [invoke yin_compare xt6.yang] + [invoke yin_compare xt7.yang] + [invoke yin_compare xt10.yang] + [invoke yin_compare a.yang] + [invoke yin_compare b.yang] + + # use some test modules + [global DIR=.] + [invoke yin_compare small6.yang] + +[cleanup] + !rm -f test.yanger.yin + !rm -f test.pyang.yin + diff --git a/test/lux/yin/yin_plugin_macro_cannoical.lux b/test/lux/yin/yin_plugin_macro_cannoical.lux new file mode 100644 index 0000000..d4dec37 --- /dev/null +++ b/test/lux/yin/yin_plugin_macro_cannoical.lux @@ -0,0 +1,805 @@ +# author: lbevemyr@cisco.com +[doc Test of the yanger yin plugin with canonical option.] + +[shell test_yanger_yin] + [timeout 20] + + # use some test modules + [global DIR=.] + !yanger -f yin -p ${DIR} ${DIR}/small6.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [global DIR=../tree] + !yanger -f yin -p ${DIR} ${DIR}/small2.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + Name of variable + + + + + + Default value for variable + + + + + + Variable must be supplied by external server + + + + + + + + + + Name for dynamic profile + + + + + + + + + """ + !yanger -f yin -p ${DIR} ${DIR}/small5.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + + + + + """ + + # use pyang test modules + [global DIR=../yin/test_good] + !yanger -f yin -p ${DIR} ${DIR}/yt5.yang --yin-canonical + """??? + + + + + + YANG Language Design Team + + + ietf@andybierman.com + + + YANG test module 5. + + + + Update test cases. + + + + + Initial revision. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RFC 2021 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + duplicate test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/yt6.yang --yin-canonical + """??? + + + + + + + + + YANG Language Design Team + + + Andy Bierman + + + YANG test module 6. Container, augment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + testing-one-two-three + + + + + + + + + + notification test + + + test-notif-1 + + + + + + + + RFC 4741 + + + + + + + + + + + + + + + + + + + + + + + + + test-any + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/yt7.yang --yin-canonical + """??? + + + + + + + + + YANG Language Design Team + + + ietf@andybierman.com + + + YANG test module 7. + + + + initial version. + + + + + rpc-test + + + RFC 4741 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/yt8.yang --yin-canonical + """??? + + + + + + YANG Language Design Team + + + ietf@andybierman.com + + + YANG test module 8. + + + + Initial revision. + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/yt9.yang --yin-canonical + """??? + + + + + + Netconf Central + + + Andy Bierman + + + YANG test module 9. augment + + + + initial version + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/yt10.yang --yin-canonical + """??? + + + + + + + + + Netconf Central + + + Andy Bierman + + + YANG test module 9. augment + + + + initial version + + + + + + + + + + + + + + + Particular configuration to retrieve. + + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/w.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/xt5.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/xt6.yang --yin-canonical + """??? + + + + + + + + + + + + + barbar + + + """ + + !yanger -f yin -p ${DIR} ${DIR}/xt7.yang --yin-canonical + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + """ \ No newline at end of file diff --git a/test/lux/yin/yin_plugin_macro_pretty_strings.lux b/test/lux/yin/yin_plugin_macro_pretty_strings.lux new file mode 100644 index 0000000..d44e338 --- /dev/null +++ b/test/lux/yin/yin_plugin_macro_pretty_strings.lux @@ -0,0 +1,57 @@ +# author: lbevemyr@cisco.com +[doc Test of the yanger yin plugin with the pretty strings option.] + +[macro yin_compare FILE] + ~yanger -f yin -p ${DIR} ${DIR}/${FILE} --yin-pretty-strings + ! | sed 's/ *$//' > test.yanger.yin + !echo ==$?== + ?==0== + + ~pyang --ignore-errors -f yin -p ${DIR} ${DIR}/${FILE} --yin-pretty-strings + ! | sed 's/ *$//' > test.pyang.yin + !echo ==$?== + ?==0== + + !diff -u test.pyang.yin test.yanger.yin + !echo ==$?== + ?==0== + - +[endmacro] + + +[shell test_yanger_yin] + [timeout 20] + + [global DIR=../tree] + [invoke yin_compare small2.yang] + [invoke yin_compare small3.yang] + [invoke yin_compare small4.yang] + [invoke yin_compare small5.yang] + [invoke yin_compare a.yang] + + # use pyang test modules + [global DIR=./test_good] + [invoke yin_compare yt5.yang] + [invoke yin_compare yt6.yang] + [invoke yin_compare yt7.yang] + [invoke yin_compare yt8.yang] + [invoke yin_compare yt9.yang] + [invoke yin_compare yt10.yang] + [invoke yin_compare qs.yang] + [invoke yin_compare q.yang] + [invoke yin_compare w.yang] + [invoke yin_compare xt5.yang] + [invoke yin_compare xt6.yang] + [invoke yin_compare xt7.yang] + [invoke yin_compare xt10.yang] + [invoke yin_compare a.yang] + [invoke yin_compare b.yang] + + # use some test modules + [global DIR=.] + [invoke yin_compare small6.yang] + +[cleanup] + !rm -f test.yanger.yin + !rm -f test.pyang.yin +