diff --git a/Makefile b/Makefile index 7ef8403..f91673c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -# version 20211020 +# version 20211111 bin ?= bin @@ -11,6 +11,8 @@ unit ?= /tmp/lxroot-unit Wextra ?= -Wextra -Wno-unused-parameter gpp_opts ?= -fmax-errors=2 -Wall -Werror $(Wextra) +deps ?= Makefile lxroot.cpp help.cpp str.cpp unit.cpp | $(bin) + help: @ echo "\ @@ -29,13 +31,23 @@ Usage: \n\ make unit-clean # delete the unit test environment \n\ make demo-clean # delete the demo environment \n\ make demo3-clean # delete the demo3 environment \n\ - make static-clean # delete the static build environment " + make static-clean # delete the static build environment \n\ + \n\ + make demo3-root # enter demo3 as (simulated) root " -$(bin)/lxroot: Makefile lxroot.cpp help.cpp str.cpp $(bin) +$(bin)/lxroot: $(deps) $(bin)/lxroot-unit + $(bin)/lxroot-unit g++ -g $(gpp_opts) lxroot.cpp -o $@ +# Note: Lxroot has two sets of unit tests. +# 1) unit.cpp compiles to bin/lxroot-unit and test various C++ functions. +# 2) aux/unit.sh tests the compiled bin/lxroot executable. +$(bin)/lxroot-unit: $(deps) + g++ -g $(gpp_opts) unit.cpp -o $@ + + $(bin) $(unit) $(demo) $(demo)-chromium: mkdir -p $@ @@ -44,7 +56,8 @@ build: $(bin)/lxroot clean: - rm -f bin/lxroot ; true + rm -f $(bin)/lxroot ; true + rm -f $(bin)/lxroot-unit ; true unit: $(bin)/lxroot $(unit) @@ -60,7 +73,17 @@ unit-clean: clean rm -rf /tmp/lxroot-unit -demo: $(bin)/lxroot $(demo) +demo-prepare: $(bin)/lxroot + @ echo + @ echo 'demo-prepare' + mkdir -p $(demo)/bin + @ # note in certain situations, $(bin) may equal $(demo) + - cp $(bin)/lxroot $(demo)/bin/lxroot + cp aux/demo.sh $(demo)/bin/demo.sh + + +# demo: $(bin)/lxroot $(demo) +demo: demo-prepare cp $(bin)/lxroot $(demo)/lxroot bash aux/demo.sh demo1 $(demo) @@ -78,64 +101,14 @@ static: # demo 3 ----------------------------------------------------------- demo 3 -demo3_iso=$(demo)/dist/archlinux-2021.06.01-x86_64.iso -demo3_url=https://mirror.rackspace.com/archlinux/iso/2021.06.01/archlinux-2021.06.01-x86_64.iso -demo3-iso-soft: - if [ ! -f $(demo3_iso) ] ; then \ - wget --continue -O $(demo3_iso) $(demo3_url) ; fi +demo3: demo-prepare + /bin/sh aux/demo.sh demo3 $(demo) -demo3-base: demo3-iso-soft $(bin)/lxroot - - @ echo - @ echo 'demo3 create userland1' - bash aux/demo.sh demo1_extract $(demo) $(demo)/demo3 - cp /etc/resolv.conf $(demo)/demo3/etc/ - mkdir -p $(demo)/demo3/dist - ln -f $(demo3_iso) $(demo)/demo3/dist - - @ echo - cp aux/demo.sh $(demo)/demo3/root/ - $(bin)/lxroot -nw $(demo)/demo3 \ - -- /bin/ash /root/demo.sh demo3_u1_create_u2 - - @ echo - cp aux/demo.sh $(demo)/demo3/userland2/root/ - $(bin)/lxroot -nr $(demo)/demo3/userland2 \ - -- /bin/bash /root/demo.sh demo3_u2_create_u3 - - @ echo - cp aux/demo.sh $(demo)/demo3/userland2/userland3/root/ - $(bin)/lxroot -nr $(demo)/demo3/userland2/userland3 \ - -- /bin/bash /root/demo.sh demo3_u3_finish - - @ echo - mkdir -p $(demo)/demo3/userland2/userland3/$(HOME) - - -demo3: - make demo3-base # This allows overrding of the demo3 recipe. - @ echo - @ echo - @ echo "( The Demo #3 guest userland has been created. )" - @ echo "( )" - @ echo "( Make will now launch an interactive shell in the )" - @ echo "( Demo #3 guest userland. )" - @ echo "( )" - @ echo "( Please run 'chromium' in this shell to attempt to )" - @ echo "( run Chromium. )" - @ echo "( )" - @ echo "( Please press ENTER when you are ready to proceed. )" - @ echo - @ echo - @ read discard - $(bin)/lxroot -nx $(demo)/demo3/userland2/userland3 - - -demo3-root: demo3-base - $(bin)/lxroot -nrx $(demo)/demo3/userland2/userland3 +demo3-root: demo-prepare + /bin/sh aux/demo.sh demo3 $(demo) root demo3-clean: @@ -143,5 +116,3 @@ demo3-clean: mkdir -p /tmp/lxroot-demo/demo3 chmod -R u+w /tmp/lxroot-demo/demo3 rm -rf /tmp/lxroot-demo/demo3 - - diff --git a/aux/demo.sh b/aux/demo.sh index d6bec43..26e71c1 100644 --- a/aux/demo.sh +++ b/aux/demo.sh @@ -1,7 +1,7 @@ -#! /bin/bash +#! /bin/sh -# version 20210610 +# version 20211111 set -o errexit @@ -9,19 +9,46 @@ set -o errexit usage () { # ---------------------------------------------------- usage echo - echo 'usage:' - echo ' bash demo.sh demo1 ' - echo ' bash demo.sh demo3 ' - echo ' bash demo.sh alpine_extract ' + echo 'usage: bash demo.sh [options]' + echo + echo 'options:' + echo ' demo1 # run demo1 in ' + echo ' demo3 # run demo3 in ' + echo ' demo3 root # enter the demo3 environment as root' return ; } +main () { # ------------------------------------------------------ main + case "$1" in + (demo1) "$@" ;; + (demo1_extract) "$@" ;; + (demo3) "$@" ;; + (demo3_u1) "$@" ;; + (demo3_u2) "$@" ;; + (demo3_u3) "$@" ;; + (*) usage ; exit 1 ;; esac + exit ; } + + # These values are used by demo1 and demo1_extract. -url='https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64' -file='alpine-minirootfs-3.13.5-x86_64.tar.gz' +demo1_tgz='alpine-minirootfs-3.13.5-x86_64.tar.gz' +demo1_url='https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64' sha256='a103f4f5560d3ae59d53fcc44fe78a42e32e421c0a2981c03c297f23a3965071' +# These values are used by demo3. +demo3_ver='2021.11.01' +demo3_iso=archlinux-"$demo3_ver"-x86_64.iso +demo3_url=https://mirror.rackspace.com/archlinux/iso/"$demo3_ver" +demo3_md5='e42e562dd005fbe15ade787fe1ddba48' +demo3_sha1='d81bff7f9b05653b048529d741edcce99bc97819' + +# demo3 uses only a single Arch mirror in hopes of avoiding problems +# caused by skew across mirrors. You may specify a different mirror +# below, if you wish. +demo3_mirrorlist='Server = https://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch' + + demo1_run () { # -------------------------------------------- demo1_run local demo="$1" echo @@ -42,7 +69,7 @@ demo1_run () { # -------------------------------------------- demo1_run demo1_verify echo trace mkdir demo1 - trace tar xzf dist/"$file" -C demo1 ; fi + trace tar xzf dist/"$demo1_tgz" -C demo1 ; fi if [ ! -f demo1/etc/resolv.conf ] ; then trace cp /etc/resolv.conf demo1/etc/ ; fi @@ -77,6 +104,26 @@ mute () { >/dev/null 2>/dev/null "$@" ; } # ----------------- mute trace () { echo "+ $@" ; "$@" ; } # --------------------- trace +fetch () { # ---------------------------------------------------- fetch + + local url="$1" path="$2" + + [ -f "$path" ] && { echo "fetch found '$path'" ; return ; } + + echo + echo "fetch $url" + echo + + trace wget --no-clobber -O "$path" "$url" && return + + echo + echo 'fetch fetch appears to have failed' + echo " url $url" + echo " path $( realpath "$path" )" + echo + die 'demo.sh fetch die' ; } + + verify () { # -------------------------------------------------- verify # usage: verify [-v] path algo expect @@ -86,11 +133,13 @@ verify () { # -------------------------------------------------- verify local path="$1" algo="$2" expect="$3" if [ "$verbose" = '1' ] ; then echo "$algo $path" ; fi - local actual=` "$algo" "$path" ` + local actual="$( "$algo" "$path" )" actual="${actual%% *}" if [ ! "$actual" = "$expect" ] || [ "$verbose" = '1' ] ; then echo "verify $algo $path" + echo " path $( realpath "$path" )" + echo " size $( stat --format '%s' "$path" )" echo " expect $expect" echo " actual $actual" fi @@ -102,7 +151,7 @@ verify () { # -------------------------------------------------- verify demo1_verify () { # -------------------------------------- demo1_verify - local path=dist/"$file" + local path=dist/"$demo1_tgz" mkdir -p dist if [ -e "$path" ] ; then echo @@ -110,19 +159,22 @@ demo1_verify () { # -------------------------------------- demo1_verify else echo echo '# ( Alpine Linux minirootfs - downloading file ... )' - wget --quiet --no-clobber -O "$path" "$url"/"$file" ; fi + wget --no-clobber -O "$path" "$demo1_url"/"$demo1_tgz" ; fi verify "$path" sha256sum "$sha256" echo "# ( Alpine Linux minirootfs - file checksum is valid )" ; } demo1_extract () { # ------------------------------------ demo1_extract + local demo="$1" extract="$2" + local url="$demo1_url" + if [ -d "$extract" ] ; then - echo 'demo1_extract already done' ; return ; fi + echo "demo1_extract found '$extract'" ; return ; fi mkdir -p "$demo" ; cd "$demo" ; demo1_verify mkdir -p "$extract" - trace tar xzf dist/"$file" -C "$extract" ; } + trace tar xzf dist/"$demo1_tgz" -C "$extract" ; } demo1 () { # ----------------------------------------------------- demo1 @@ -135,32 +187,43 @@ demo1 () { # ----------------------------------------------------- demo1 # demo 3 ----------------------------------------------------------- demo 3 -# demo3 uses only a single mirror in hopes of avoiding problems -# caused by mirror skew. You may specify a different mirror below, -# if you wish. +demo3_verify () { # -------------------------------------- demo3_verify + [ -f dist/"$iso" ] || fetch "$url"/"$iso" dist/"$iso" + verify -v dist/"$iso" md5sum "$demo3_md5" + verify -v dist/"$iso" sha1sum "$demo3_sha1" + return ; } -demo3_mirrorlist='Server = https://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch' +demo3_host () { # ------------------------------------------ demo3_host -demo3_u1_create_u2 () { # -------------------------- demo3_u1_create_u2 + # demo3_host is run on the host. + # demo3_host creates userland #1 (Alpine). - if [ -d /userland2 ] ; then - echo 'demo3_u1_create_u2 already done' ; return ; fi + echo + echo "demo3 $*" + + trace cd "$demo" + demo1_extract . demo3 + demo3_verify - echo 'demo3_u1_create_u2' + trace mkdir -p demo3/dist/ + trace cp /etc/resolv.conf demo3/etc/ + trace cp bin/demo.sh demo3/dist/ + trace ln -f dist/"$iso" demo3/dist/"$iso" + + return ; } + + +demo3_u1_extract () { # ------------------------------ demo3_u1_extract + + [ -d /userland2 ] && { + echo 'demo3_u1_extract found /userland2' ; return ; } if [ ! -f /root/update ] ; then trace apk update ; touch /root/update ; fi trace apk add p7zip squashfs-tools - local iso='archlinux-2021.06.01-x86_64.iso' - - verify -v /dist/"$iso" md5sum 1bf76d864651cc6454ab273fd3d2226a - verify -v /dist/"$iso" sha1sum 6c41a22fb3c5eabfb7872970a9b5653ec47c3ad5 - verify -v /dist/"$iso" sha256sum \ - bd23f81dfb7a224589ccabed7f690c33fbc243bae3f32d295547a64445ae0245 - trace mkdir -p /iso-extract trace cd /iso-extract trace mute 7z x -aos /dist/"$iso" arch/x86_64/airootfs.sfs @@ -171,7 +234,9 @@ demo3_u1_create_u2 () { # -------------------------- demo3_u1_create_u2 trace sha512sum -c airootfs.sha512 trace cd /iso-extract - trace unsquashfs -no-xattrs /iso-extract/arch/x86_64/airootfs.sfs + [ -d squashfs-root ] \ + || trace unsquashfs -no-xattrs /iso-extract/arch/x86_64/airootfs.sfs \ + || true trace mv squashfs-root userland2 trace rm -f userland2/etc/resolv.conf trace cp /etc/resolv.conf userland2/etc/resolv.conf @@ -190,12 +255,28 @@ demo3_u1_create_u2 () { # -------------------------- demo3_u1_create_u2 return ; } -demo3_u2_create_u3 () { # -------------------------- demo3_u2_create_u3 +demo3_u1 () { # ---------------------------------------------- demo3_u1 + + # demo3_u1 is run in userland #1 (Alpine). + # demo3_u1 creates userland #2 (Arch bootstrap). + + local iso="$demo3_iso" + + echo + echo 'demo3_u1' + + demo3_u1_extract + + trace mkdir -p /userland2/dist/ + trace cp /dist/demo.sh /userland2/dist/ + + return ; } + - if [ -d /userland3 ] ; then - echo 'demo3_u2_create_u3 already done' ; return ; fi +demo3_u2_bootstrap () { # -------------------------- demo3_u2_bootstrap - echo 'demo3_u2_create_u3' + [ -d /userland3 ] && { + echo "demo3_u2_bootstrap found /userland3" ; return ; } trace pacman-key --init trace pacman-key --populate archlinux @@ -215,13 +296,31 @@ demo3_u2_create_u3 () { # -------------------------- demo3_u2_create_u3 return ; } -demo3_u3_finish () { # # --------------------------- demo3_u3_finish +demo3_u2 () { # ---------------------------------------------- demo3_u2 + + # demo3_u2 is run in userland #2 (Arch bootstrap). + # demo3_u2 creates userland #$3 (Arch actual). + + echo + echo 'demo3_u2' + + demo3_u2_bootstrap + + trace mkdir -p /userland3/dist/ + trace cp /dist/demo.sh /userland3/dist/ + + return ; } + + +demo3_u3 () { # ---------------------------------------------- demo3_u3 - if [ -f /usr/bin/chromium ] ; then - echo 'demo3_u3_finish already done' ; return ; fi + # demo3_3 is run in userland #3 (Arch actual). echo - echo 'demo3_u3_finish' + echo 'demo3_u3' + + [ -f /usr/bin/chromium ] && { + echo 'demo3_u3 found /usr/bin/chromium' ; return ; } trace mkdir -p /tmp/.X11-unix trace pacman -Sy --noconfirm chromium @@ -229,15 +328,62 @@ demo3_u3_finish () { # # --------------------------- demo3_u3_finish return ; } -main () { # ------------------------------------------------------ main - case "$1" in - (demo1) "$1" "$2" ;; - (demo1_extract) "$1" "$2" "$3" ;; - (demo3_u1_create_u2) "$1" ;; # run in userland1 - (demo3_u2_create_u3) "$1" ;; # run in userland2 - (demo3_u3_finish) "$1" ;; # run in userland3 - (*) usage ; exit 1 ;; esac - exit ; } +demo3_u3_shell () { # ---------------------------------- demo3_u3_shell + + mkdir -p demo3/userland2/userland3/home/"$USER" || true + + echo + echo + echo "( The Demo #3 guest userland has been created. )" + echo "( )" + echo "( Make will now launch an interactive shell in the )" + echo "( Demo #3 guest userland. )" + echo "( )" + echo "( Please run 'chromium' in this shell to attempt to )" + echo "( run Chromium. )" + echo "( )" + echo "( Please press ENTER when you are ready to proceed. )" + + read discard + bin/lxroot -nx demo3/userland2/userland3 + + return ; } + + +demo3_u3_shell_root () { # ------------------------ demo3_u3_shell_root + trace cd "$demo" + trace bin/lxroot -nr demo3/userland2/userland3 ; } + + +demo3 () { # ---------------------------------------------------- demo3 + + local demo="$1" mode="$2" + local iso="$demo3_iso" + local url="$demo3_url" + + if [ "$root" = 'root' ] ; then + echo + echo 'demo3 root' + return ; fi + + local u1='demo3' + local u2='demo3/userland2' + local u3='demo3/userland2/userland3' + + demo3_host + trace bin/lxroot -nr "$u1" -- /bin/sh /dist/demo.sh demo3_u1 + trace bin/lxroot -nr "$u2" -- /bin/sh /dist/demo.sh demo3_u2 + trace bin/lxroot -nr "$u3" -- /bin/sh /dist/demo.sh demo3_u3 + + case "$mode" in + ('' ) demo3_u3_shell ;; + ('root') demo3_u3_shell_root ;; + (*) die "demo3 bad mode '$mode'" ;; esac + + return ; } + + +# main --------------------------------------------------------------- main main "$@" diff --git a/changelog.txt b/changelog.txt index 2c6c2e8..9e4d256 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,22 @@ +20211115 + +Git log: Created unit.cpp. Updated demo3(#7). Fixed MS_ & ST_ enum bug(#6). +Retired 'master' branch. +Created new 'main' branch. +The above two chanegs were done for copyright/authorship reasons. +They removed a trivial patch from a third party. +Rebuilt demo3. Shifted parts of demo3 from Makefile to aux/demo.sh. +The above demo3 changes fixed Issue #7. +Fixed enum vs. #define MS_ vs ST_ bug. (Fixing issue #6.) + + +20211030 + +Moved C++ unit tests to unit.cpp. + + 20211028 Ipmelmented proper fix of GitHub issue #3, via statfs(). diff --git a/lxroot.cpp b/lxroot.cpp index 66eb8b8..38896a0 100644 --- a/lxroot.cpp +++ b/lxroot.cpp @@ -728,8 +728,9 @@ struct Syscall { // xxsy ----------------------------- struct Syscall // the below verbose yet simple implementation should optimize well. - #define if_equal( a, b ) ( a == b ? b : 0 ) - #define if_not_equal( a, b ) ( ( a != b ) && ( n & a ) ? b : 0 ) + #define c(a) ( (flags_t) (a) ) + #define if_equal( a, b ) ( c(a) == c(b) ? b : 0 ) + #define if_not_equal( a, b ) ( ( c(a) != c(b) ) && ( n & a ) ? b : 0 ) constexpr flags_t copy_these_bits = if_equal ( ST_RDONLY, MS_RDONLY ) @@ -753,25 +754,13 @@ struct Syscall { // xxsy ----------------------------- struct Syscall | if_not_equal ( ST_NODIRATIME, MS_NODIRATIME ) | if_not_equal ( ST_RELATIME, MS_RELATIME ); + #undef c #undef if_equal #undef if_not_equal return ( n & copy_these_bits ) | shifted_bits; } - static void st_to_ms_unit_test () { // ---------- st_to_ms_unit_test - assert ( st_to_ms ( ST_RDONLY ) == MS_RDONLY ); - assert ( st_to_ms ( ST_NOSUID ) == MS_NOSUID ); - assert ( st_to_ms ( ST_NODEV ) == MS_NODEV ); - assert ( st_to_ms ( ST_NOEXEC ) == MS_NOEXEC ); - assert ( st_to_ms ( ST_SYNCHRONOUS ) == MS_SYNCHRONOUS ); - assert ( st_to_ms ( ST_MANDLOCK ) == MS_MANDLOCK ); - assert ( st_to_ms ( ST_NOATIME ) == MS_NOATIME ); - assert ( st_to_ms ( ST_NODIRATIME ) == MS_NODIRATIME ); - assert ( st_to_ms ( ST_RELATIME ) == MS_RELATIME ); - return; } - - void umount2 ( Str target, int flags ) { // -------- Syscall umount2 try1( :: umount2, " umount2 %s 0x%x", target.s, flags ); } @@ -796,10 +785,6 @@ struct Syscall { // xxsy ----------------------------- struct Syscall die_pe ( "write %d %ld", fd, (long int) count ); } - static void unit_test () { // ------------------- Syscall unit_test - st_to_ms_unit_test(); } - - }; // end struct Syscall ------------------------ end struct Syscall @@ -811,6 +796,7 @@ Syscall sys; // xxsy -------------------------------------- global sys struct Option_Reader // xxop -------------------- struct Option_Reader : private Option { + const Option & o; // const access to the Option base class @@ -1230,6 +1216,7 @@ struct Env_Tool : Lib { // xxen --------------------- struct Env_Tool static void ps1 () { // ------------------------------ Env_Tool ps1 // 20200626 todo? add custom prompts for other shells + // 20211030 probably not. use selective env var passthru instead. if ( st.command[0] == "/bin/bash" || is_busybox ( st.command[0] ) ) { ps1_bash(); } } @@ -1496,18 +1483,12 @@ class Lxroot : Lib { // xxlx ------------------------- class Lxroot -void unit_test () { // ------------------------------------- unit_test - mStr :: unit_test(); - oStr :: unit_test(); - Argv :: unit_test(); - Syscall :: unit_test(); } - - +#ifndef LXROOT_MAIN_SKIP int main ( const int argc, str argv[] ) { // -------------------- main - unit_test(); if ( argc < 2 ) { Lib :: help_print(); } mut .argv = argv; return Lxroot() .main(); } +#endif diff --git a/str.cpp b/str.cpp index 3a36a04..6e08d56 100644 --- a/str.cpp +++ b/str.cpp @@ -4,7 +4,7 @@ // Copyright (c) 2021 Parke Bostrom, parke.nexus at gmail.com // Distributed under GPLv3 (see end of file) WITHOUT ANY WARRANTY. -// version 20211019 +// version 20211030 @@ -83,6 +83,7 @@ struct mFrag { // xxmf --------------------------------- struct mFrag struct mStr { // xxms ----------------------------------- struct mStr + // mStr is a convenience wrapper around a mstr (i.e. 'const char *'). // s points to either (a) nullptr or (b) a null-terminated string. // an mStr does not own s. (But see also derived class oStr.) @@ -148,9 +149,6 @@ struct mStr { // xxms ----------------------------------- struct mStr a = c; } } - static void basename_test ( Str s, Str expect ); // ------------------ - - Frag capture_until ( char c ) const { // ------ mStr capture_until mStr p = s; while ( p && * p && * p != c ) { p ++; } return Frag ( s, p.s - s ); } @@ -235,28 +233,6 @@ struct mStr { // xxms ----------------------------------- struct mStr return skip_all('/') .capture_until('/'); } - static void unit_test () { // ---------------------- mStr unit_test - - basename_test ( "", "" ); - basename_test ( "/", "/" ); - basename_test ( "//", "/" ); - basename_test ( "///", "/" ); - basename_test ( "a", "a" ); - basename_test ( "/b", "b" ); - basename_test ( "c/", "c" ); - basename_test ( "/d/", "d" ); - basename_test ( "e/f", "f" ); - basename_test ( "/g/h", "h" ); - basename_test ( "abc", "abc" ); - basename_test ( "/def", "def" ); - basename_test ( "ghi/", "ghi" ); - basename_test ( "/jkl/", "jkl" ); - basename_test ( "mno/pqr", "pqr" ); - basename_test ( "/stu/vwx", "vwx" ); - basename_test ( "./xyz", "xyz" ); - - return; } - }; // end struct mStr ------------------------------ end struct mStr @@ -293,7 +269,6 @@ Concat_2 s ( Str a, Str b = 0, Str c = 0 ) { // xxs ------- global s - struct oStr : mStr { // xxos ------------------------- struct oStr @@ -339,9 +314,6 @@ struct oStr : mStr { // xxos ------------------------- struct oStr oStr rv; rv.s=s.s; rv.n=s.n(); return rv; } - static void unit_test (); // ------------------------ oStr unit_test - - }; // end struct oStr ------------------------------ end struct oStr @@ -390,32 +362,6 @@ Concat operator + ( str a, Str b ) { // --------------------- :: op + return Frag(a) + b; } -void mStr :: basename_test ( Str s, Str expect ) { // -- basename_test - if ( s.basename() == expect ) { return; } - oStr actual = s.basename(); - printe ( "basename_test failed\n" ); - printe ( " s %s\n", s.s ); - printe ( " expect %s\n", expect.s ); - printe ( " actual %s\n", actual.s ); - abort(); } - - -void oStr :: unit_test () { // ----------------------- oStr unit_test - Str a = "a"; - Str b = "b"; - oStr ab = a + b; - assert ( ab == "ab" ); - assert ( ab == a+b ); - Frag c = "c"; - Frag d = "d"; - oStr cd = c + "=" + d; - assert ( cd == "c=d" ); - oStr ef = cd + "ef" + "gh"; - assert ( ef == "c=defgh" ); - assert ( cd == "c=d" ); - ;;; } - - // end struct Concat -------------------------------- end struct Concat @@ -488,29 +434,6 @@ struct Argv { // xxar ----------------------------------- struct Argv printe ( "%s%s\n", s.s, o[0].s ); } } - static void unit_test () { // ---------------------- Argv unit_test - - str p[] = { "a=1", "b=2", "c=3", nullptr }; - Argv a(p); - - assert ( a[0] == p[0] ); - assert ( a[1] == p[1] ); - assert ( a[2] == p[2] ); - assert ( a[3] == p[3] ); - - assert ( a[0] == a.p[0] ); - assert ( a[1] == a.p[1] ); - assert ( a[2] == a.p[2] ); - assert ( a[3] == a.p[3] ); - assert ( a.concat() == "a=1 b=2 c=3" ); - - assert ( a.env_get("a") == p[0] ); - assert ( a.env_get("b") == p[1] ); - assert ( a.env_get("c") == p[2] ); - - ;;; } - - }; // end struct Argv ------------------------------ end struct Argv diff --git a/unit.cpp b/unit.cpp new file mode 100644 index 0000000..6181e62 --- /dev/null +++ b/unit.cpp @@ -0,0 +1,143 @@ + + +// unit.cpp - Lxroot's C++ unit tests. +// Copyright (c) 2021 Parke Bostrom, parke.nexus at gmail.com +// Distributed under GPLv3 (see end of file) WITHOUT ANY WARRANTY. + +// version 20211030 + + +#define LXROOT_MAIN_SKIP 1 +#include "lxroot.cpp" + + +struct Unit { // ----------------------------------------- struct Unit + + + void t_basename ( Str s, Str expect ) { // -------- Unit t_basename + if ( s.basename() == expect ) { return; } + oStr actual = s.basename(); + printe ( "basename_test failed\n" ); + printe ( " s %s\n", s.s ); + printe ( " expect %s\n", expect.s ); + printe ( " actual %s\n", actual.s ); + abort(); } + + + void t_basename_all () { // ------------------- Unit t_basename_all + + t_basename ( "", "" ); + t_basename ( "/", "/" ); + t_basename ( "//", "/" ); + t_basename ( "///", "/" ); + t_basename ( "a", "a" ); + t_basename ( "/b", "b" ); + t_basename ( "c/", "c" ); + t_basename ( "/d/", "d" ); + t_basename ( "e/f", "f" ); + t_basename ( "/g/h", "h" ); + t_basename ( "abc", "abc" ); + t_basename ( "/def", "def" ); + t_basename ( "ghi/", "ghi" ); + t_basename ( "/jkl/", "jkl" ); + t_basename ( "mno/pqr", "pqr" ); + t_basename ( "/stu/vwx", "vwx" ); + t_basename ( "./xyz", "xyz" ); + + return; } + + + void t_oStr () { // ----------------------------------- Unit t_oStr + + Str a = "a"; + Str b = "b"; + oStr ab = a + b; + assert ( ab == "ab" ); + assert ( ab == a+b ); + Frag c = "c"; + Frag d = "d"; + oStr cd = c + "=" + d; + assert ( cd == "c=d" ); + oStr ef = cd + "ef" + "gh"; + assert ( ef == "c=defgh" ); + assert ( cd == "c=d" ); + + return; } + + + static void t_Argv () { // ---------------------------- Unit t_Argv + + str p[] = { "a=1", "b=2", "c=3", nullptr }; + Argv a(p); + + assert ( a[0] == p[0] ); + assert ( a[1] == p[1] ); + assert ( a[2] == p[2] ); + assert ( a[3] == p[3] ); + + assert ( a[0] == a.p[0] ); + assert ( a[1] == a.p[1] ); + assert ( a[2] == a.p[2] ); + assert ( a[3] == a.p[3] ); + assert ( a.concat() == "a=1 b=2 c=3" ); + + assert ( a.env_get("a") == p[0] ); + assert ( a.env_get("b") == p[1] ); + assert ( a.env_get("c") == p[2] ); + + return; } + + + void t_st_to_ms () { // --------------------------- Unit t_st_to_ms + + const auto st_to_ms = Syscall :: st_to_ms; + + assert( st_to_ms ( ST_RDONLY ) == MS_RDONLY ); + assert( st_to_ms ( ST_NOSUID ) == MS_NOSUID ); + assert( st_to_ms ( ST_NODEV ) == MS_NODEV ); + assert( st_to_ms ( ST_NOEXEC ) == MS_NOEXEC ); + assert( st_to_ms ( ST_SYNCHRONOUS ) == MS_SYNCHRONOUS ); + assert( st_to_ms ( ST_MANDLOCK ) == MS_MANDLOCK ); + assert( st_to_ms ( ST_NOATIME ) == MS_NOATIME ); + assert( st_to_ms ( ST_NODIRATIME ) == MS_NODIRATIME ); + assert( st_to_ms ( ST_RELATIME ) == MS_RELATIME ); + + return; } + + + void main () { // ------------------------------------- Unit main + t_basename_all(); + t_oStr(); + t_Argv(); + t_st_to_ms(); + printf ( "unit.cpp done all tests passed\n" ); } + + +}; // end struct Unit ------------------------------ end struct Unit + + + + +int main () { // -------------------------------------------- :: main + Unit() .main(); + return 0; } + + + + +// unit.cpp - Lxroot's C++ unit tests. +// +// Copyright (c) 2021 Parke Bostrom, parke.nexus at gmail.com +// +// This program is free software: you can redistribute it and/or +// modify it under the terms of version 3 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See version +// 3 of the GNU General Public License for more details. +// +// You should have received a copy of version 3 of the GNU General +// Public License along with this program. If not, see +// .