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 +