miniroon

Simplistic macaroon-based authorization for Unix systems
git clone https://ccx.te2000.cz/git/miniroon
Log | Files | Refs | README

commit 87dd2ff6d3d7e9b644c7366a933151c3d240c5d8
parent 0115452a17b566c5810acfeb4bb16e0a353048f9
Author: Jan Pobrislo <ccx@te2000.cz>
Date:   Fri, 25 Apr 2025 20:06:18 +0000

Add tests for spec.pl

Diffstat:
Mdoc/Makefile | 7+++++++
Mdoc/spec.html | 87++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mdoc/spec.pl | 51++++++++++++++++++++++++++++++++-------------------
Mdoc/spec2html.awk | 2+-
Adoc/tests.pl | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 142 insertions(+), 56 deletions(-)

diff --git a/doc/Makefile b/doc/Makefile @@ -1,3 +1,10 @@ +all: spec.html test +.PHONY: all + spec.html: spec.pl spec2html.awk awk -f spec2html.awk spec.pl >'$@.new' mv '$@.new' '$@' + +test: + swipl -g run_tests -t halt tests.pl +.PHONY: test diff --git a/doc/spec.html b/doc/spec.html @@ -9,7 +9,7 @@ <tr><td>7</td><td><pre></pre></td><td rowspan="4"></td></tr> <tr><td>8</td><td><pre>% apply check to value when bound</pre></td></tr> <tr><td>9</td><td><pre>will_be(Value, Goal) :-</pre></td></tr> -<tr><td>10</td><td><pre> freeze(Value, call(Goal, Value)).</pre></td></tr> +<tr><td>10</td><td><pre> freeze(Value, assertion(call(Goal, Value))).</pre></td></tr> <tr><td>11</td><td><pre></pre></td><td rowspan="2"></td></tr> <tr><td>12</td><td><pre>byte(Value) :- must_be(between(0, 255), Value).</pre></td></tr> <tr><td>13</td><td><pre></pre></td><td rowspan="2"></td></tr> @@ -20,41 +20,56 @@ <tr><td>18</td><td><pre> First will_be byte,</pre></td></tr> <tr><td>19</td><td><pre> Rest will_be sequence_of_bytes.</pre></td></tr> <tr><td>20</td><td><pre></pre></td><td rowspan="1"></td></tr> -<tr><td>21</td><td><pre>netstring_encoding(PayloadLength, PayloadBytes) -->gt; %<lt; Netstring is a sequence of bytes.</pre></td><td rowspan="2"></td></tr> -<tr><td>22</td><td><pre> { length(PayloadBytes, PayloadLength) },</pre></td></tr> -<tr><td>23</td><td><pre> netstring_prefix(PayloadLength), %<lt; It consists of prefix,</pre></td><td rowspan="1"></td></tr> -<tr><td>24</td><td><pre> PayloadBytes, %<lt; payload,</pre></td><td rowspan="1"></td></tr> -<tr><td>25</td><td><pre> `,`. %<lt; and terminator. Terminator is single ASCII comma `,`.</pre></td><td rowspan="5"></td></tr> -<tr><td>26</td><td><pre>netstring_encoding(netstring(PayloadLength, PayloadBytes), Bytes) :-</pre></td></tr> +<tr><td>21</td><td><pre>netstring_encoding(PayloadBytes) -->gt; </pre></td><td rowspan="1">Netstring is a sequence of bytes.</td></tr> +<tr><td>22</td><td><pre> netstring_prefix_for_payload(PayloadBytes), </pre></td><td rowspan="1">It consists of prefix,</td></tr> +<tr><td>23</td><td><pre> PayloadBytes, </pre></td><td rowspan="1">payload,</td></tr> +<tr><td>24</td><td><pre> `,`. </pre></td><td rowspan="5">and terminator. Terminator is single ASCII comma `,`.</td></tr> +<tr><td>25</td><td><pre>netstring_encoding(netstring(PayloadBytes), Bytes) :-</pre></td></tr> +<tr><td>26</td><td><pre> assertion(ground(PayloadBytes); ground(Bytes)),</pre></td></tr> <tr><td>27</td><td><pre> Bytes will_be sequence_of_bytes,</pre></td></tr> -<tr><td>28</td><td><pre> PayloadLength will_be nonnegative_integer,</pre></td></tr> -<tr><td>29</td><td><pre> phrase(netstring_encoding(PayloadLength, PayloadBytes), Bytes).</pre></td></tr> -<tr><td>30</td><td><pre></pre></td><td rowspan="4"> -Netstring prefix is the shortest ASCII decimal representation for length of payload in bytes, followed by ASCII colon `:`. That is number starting with non-zero digit unless payload is empty, in which case it's `0`.</td></tr> +<tr><td>28</td><td><pre> phrase(netstring_encoding(PayloadBytes), Bytes).</pre></td></tr> +<tr><td>29</td><td><pre></pre></td><td rowspan="1"></td></tr> +<tr><td>30</td><td><pre></pre></td><td rowspan="19">Netstring prefix is the shortest ASCII decimal representation for length of +payload in bytes, followed by ASCII colon `:`. +That is number starting with non-zero digit unless payload is empty, +in which case it's `0`.</td></tr> <tr><td>31</td><td><pre></pre></td></tr> -<tr><td>32</td><td><pre>netstring_prefix(0) -->gt; `0:`.</pre></td></tr> -<tr><td>33</td><td><pre>netstring_prefix(N) -->gt; positive_decimal(N), `:`.</pre></td></tr> -<tr><td>34</td><td><pre></pre></td><td rowspan="7"></td></tr> -<tr><td>35</td><td><pre>positive_decimal(N) -->gt;</pre></td></tr> -<tr><td>36</td><td><pre> { freeze(N, format(codes([C|Cs]), '~w', N)) },</pre></td></tr> -<tr><td>37</td><td><pre> nonzero_digit(C),</pre></td></tr> -<tr><td>38</td><td><pre> digits(Cs),</pre></td></tr> -<tr><td>39</td><td><pre> { phrase(number(N), [C|Cs]) }.</pre></td></tr> -<tr><td>40</td><td><pre>nonzero_digit(Code) -->gt; [Code], {member(Code, `123456789`)}.</pre></td></tr> -<tr><td>41</td><td><pre></pre></td><td rowspan="6"></td></tr> -<tr><td>42</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr> -<tr><td>43</td><td><pre> ground(Goal),</pre></td></tr> -<tr><td>44</td><td><pre> !,</pre></td></tr> -<tr><td>45</td><td><pre> call(Goal, PayloadBytes),</pre></td></tr> -<tr><td>46</td><td><pre> netstring_encoding(netstring(_, PayloadBytes), Bytes).</pre></td></tr> -<tr><td>47</td><td><pre></pre></td><td rowspan="6"></td></tr> -<tr><td>48</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr> -<tr><td>49</td><td><pre> ground(Bytes),</pre></td></tr> -<tr><td>50</td><td><pre> !,</pre></td></tr> -<tr><td>51</td><td><pre> netstring_encoding(netstring(_, PayloadBytes), Bytes),</pre></td></tr> -<tr><td>52</td><td><pre> call(Goal, PayloadBytes).</pre></td></tr> -<tr><td>53</td><td><pre></pre></td><td rowspan="1"></td></tr> -<tr><td>54</td><td><pre></pre></td><td rowspan="3"></td></tr> -<tr><td>55</td><td><pre>% :- use_module(library(pldoc/doc_files)).</pre></td></tr> -<tr><td>56</td><td><pre>% doc_save('spec.pl', [format(html), doc_root(.)]).</pre></td></tr> +<tr><td>32</td><td><pre></pre></td></tr> +<tr><td>33</td><td><pre></pre></td></tr> +<tr><td>34</td><td><pre>netstring_prefix_for_payload(PayloadBytes, A, B) :-</pre></td></tr> +<tr><td>35</td><td><pre> ( var(PayloadBytes)</pre></td></tr> +<tr><td>36</td><td><pre> ->gt; netstring_prefix_codes(Prefix, A, B),</pre></td></tr> +<tr><td>37</td><td><pre> number_codes(PayloadLength, Prefix),</pre></td></tr> +<tr><td>38</td><td><pre> length(PayloadBytes, PayloadLength)</pre></td></tr> +<tr><td>39</td><td><pre> ; length(PayloadBytes, PayloadLength),</pre></td></tr> +<tr><td>40</td><td><pre> number_codes(PayloadLength, Prefix),</pre></td></tr> +<tr><td>41</td><td><pre> netstring_prefix_codes(Prefix, A, B)</pre></td></tr> +<tr><td>42</td><td><pre> ).</pre></td></tr> +<tr><td>43</td><td><pre>netstring_prefix_codes(`0`) -->gt; `0:`, !.</pre></td></tr> +<tr><td>44</td><td><pre>netstring_prefix_codes([C|Cs]) -->gt;</pre></td></tr> +<tr><td>45</td><td><pre> nonzero_digit(C),</pre></td></tr> +<tr><td>46</td><td><pre> !,</pre></td></tr> +<tr><td>47</td><td><pre> digits(Cs),</pre></td></tr> +<tr><td>48</td><td><pre> `:`.</pre></td></tr> +<tr><td>49</td><td><pre></pre></td><td rowspan="5"></td></tr> +<tr><td>50</td><td><pre>nonzero_digit(Code) -->gt;</pre></td></tr> +<tr><td>51</td><td><pre> [Code],</pre></td></tr> +<tr><td>52</td><td><pre> { assertion(ground(Code)) },</pre></td></tr> +<tr><td>53</td><td><pre> { member(Code, `123456789`) }.</pre></td></tr> +<tr><td>54</td><td><pre></pre></td><td rowspan="6"></td></tr> +<tr><td>55</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr> +<tr><td>56</td><td><pre> ground(Goal),</pre></td></tr> +<tr><td>57</td><td><pre> !,</pre></td></tr> +<tr><td>58</td><td><pre> call(Goal, PayloadBytes),</pre></td></tr> +<tr><td>59</td><td><pre> netstring_encoding(netstring(PayloadBytes), Bytes).</pre></td></tr> +<tr><td>60</td><td><pre></pre></td><td rowspan="6"></td></tr> +<tr><td>61</td><td><pre>netstring_of(Goal, Bytes) :-</pre></td></tr> +<tr><td>62</td><td><pre> ground(Bytes),</pre></td></tr> +<tr><td>63</td><td><pre> !,</pre></td></tr> +<tr><td>64</td><td><pre> netstring_encoding(netstring(PayloadBytes), Bytes),</pre></td></tr> +<tr><td>65</td><td><pre> call(Goal, PayloadBytes).</pre></td></tr> +<tr><td>66</td><td><pre></pre></td><td rowspan="1"></td></tr> +<tr><td>67</td><td><pre></pre></td><td rowspan="3"></td></tr> +<tr><td>68</td><td><pre>% :- use_module(library(pldoc/doc_files)).</pre></td></tr> +<tr><td>69</td><td><pre>% doc_save('spec.pl', [format(html), doc_root(.)]).</pre></td></tr> </table></body></html> diff --git a/doc/spec.pl b/doc/spec.pl @@ -7,7 +7,7 @@ % apply check to value when bound will_be(Value, Goal) :- - freeze(Value, call(Goal, Value)). + freeze(Value, assertion(call(Goal, Value))). byte(Value) :- must_be(between(0, 255), Value). @@ -18,37 +18,50 @@ sequence_of_bytes([First|Rest]) :- First will_be byte, Rest will_be sequence_of_bytes. -netstring_encoding(PayloadLength, PayloadBytes) --> %< Netstring is a sequence of bytes. - { length(PayloadBytes, PayloadLength) }, - netstring_prefix(PayloadLength), %< It consists of prefix, - PayloadBytes, %< payload, - `,`. %< and terminator. Terminator is single ASCII comma `,`. -netstring_encoding(netstring(PayloadLength, PayloadBytes), Bytes) :- +netstring_encoding(PayloadBytes) --> %> Netstring is a sequence of bytes. + netstring_prefix_for_payload(PayloadBytes), %> It consists of prefix, + PayloadBytes, %> payload, + `,`. %> and terminator. Terminator is single ASCII comma `,`. +netstring_encoding(netstring(PayloadBytes), Bytes) :- + assertion(ground(PayloadBytes); ground(Bytes)), Bytes will_be sequence_of_bytes, - PayloadLength will_be nonnegative_integer, - phrase(netstring_encoding(PayloadLength, PayloadBytes), Bytes). + phrase(netstring_encoding(PayloadBytes), Bytes). -%> Netstring prefix is the shortest ASCII decimal representation for length of payload in bytes, followed by ASCII colon `:`. That is number starting with non-zero digit unless payload is empty, in which case it's `0`. -netstring_prefix(0) --> `0:`. -netstring_prefix(N) --> positive_decimal(N), `:`. - -positive_decimal(N) --> - { freeze(N, format(codes([C|Cs]), '~w', N)) }, +%> Netstring prefix is the shortest ASCII decimal representation for length of +%^ payload in bytes, followed by ASCII colon `:`. +%^ That is number starting with non-zero digit unless payload is empty, +%^ in which case it's `0`. +netstring_prefix_for_payload(PayloadBytes, A, B) :- + ( var(PayloadBytes) + -> netstring_prefix_codes(Prefix, A, B), + number_codes(PayloadLength, Prefix), + length(PayloadBytes, PayloadLength) + ; length(PayloadBytes, PayloadLength), + number_codes(PayloadLength, Prefix), + netstring_prefix_codes(Prefix, A, B) + ). +netstring_prefix_codes(`0`) --> `0:`, !. +netstring_prefix_codes([C|Cs]) --> nonzero_digit(C), + !, digits(Cs), - { phrase(number(N), [C|Cs]) }. -nonzero_digit(Code) --> [Code], {member(Code, `123456789`)}. + `:`. + +nonzero_digit(Code) --> + [Code], + { assertion(ground(Code)) }, + { member(Code, `123456789`) }. netstring_of(Goal, Bytes) :- ground(Goal), !, call(Goal, PayloadBytes), - netstring_encoding(netstring(_, PayloadBytes), Bytes). + netstring_encoding(netstring(PayloadBytes), Bytes). netstring_of(Goal, Bytes) :- ground(Bytes), !, - netstring_encoding(netstring(_, PayloadBytes), Bytes), + netstring_encoding(netstring(PayloadBytes), Bytes), call(Goal, PayloadBytes). diff --git a/doc/spec2html.awk b/doc/spec2html.awk @@ -7,7 +7,7 @@ BEGIN { last_comm = 1 } -/%< / || /^$/{ +/%> / || /^$/{ last_comm = NR } diff --git a/doc/tests.pl b/doc/tests.pl @@ -0,0 +1,51 @@ +:- begin_tests(spec_netstring). +:- [spec]. + +test(prefix_encode_empty) :- + PayloadBytes = ``, + phrase(netstring_prefix_for_payload(PayloadBytes), PrefixBytes), + assertion(PrefixBytes =@= `0:`). + +test(prefix_decode_empty) :- + PrefixBytes = `0:`, + phrase(netstring_prefix_for_payload(PayloadBytes), PrefixBytes), + assertion(PayloadBytes =@= ``). + +test(encode_empty) :- + netstring_encoding(netstring(``), Bytes), + assertion(Bytes =@= `0:,`). + +test(decode_empty) :- + netstring_encoding(netstring(PayloadBytes), `0:,`), + assertion(PayloadBytes =@= ``). + +test(encode_single_null) :- + netstring_encoding(netstring(`\0`), Bytes), + assertion(Bytes =@= `1:\0,`). + +test(decode_single_null) :- + netstring_encoding(netstring(PayloadBytes), `1:\0,`), + assertion(PayloadBytes =@= `\0`). + +test(encode_ten_bytes) :- + netstring_encoding(netstring(`1234567890`), Bytes), + assertion(Bytes =@= `10:1234567890,`). + +test(decode_ten_bytes) :- + netstring_encoding(netstring(PayloadBytes), `10:1234567890,`), + assertion(PayloadBytes =@= `1234567890`). + +test(encode_nested) :- + InnerPayload = [0, 255], + PayloadGoal = netstring_encoding(netstring(InnerPayload)), + netstring_of(PayloadGoal, Bytes), + flatten([`5:2:\0`, 255, `,,`], ExpectedBytes), + assertion(Bytes =@= ExpectedBytes). + +test(decode_nested) :- + flatten([`5:2:\0`, 255, `,,`], Bytes), + PayloadGoal = netstring_encoding(netstring(InnerPayload)), + netstring_of(PayloadGoal, Bytes), + assertion(InnerPayload =@= [0, 255]). + +:- end_tests(spec_netstring).