diff --git a/tex/UTB.tex b/tex/UTB.tex index 65e055c..d24a3d4 100644 --- a/tex/UTB.tex +++ b/tex/UTB.tex @@ -48,6 +48,38 @@ \usepackage{colorprofiles} % \usepackage[a-2b,mathxmp]{pdfx}[2018/12/22] +\usepackage{fontspec} +\setmonofont{Fira Code}[ + Scale=MatchLowercase, + Contextuals=Alternate % Activate the calt feature +] +\usepackage{lstfiracode} % https://ctan.org/pkg/lstfiracode +% listings settings. +\lstset{ + style=FiraCodeStyle, % Use predefined FiraCodeStyle + basicstyle=\linespread{0.8}\small\ttfamily, % Use \ttfamily for source code listings + captionpos=b, + keepspaces=true, + inputencoding=utf8, + upquote=true, + showlines=true, + emptylines=true, + columns=fullflexible, + showstringspaces=false +} + +% listings +\AtBeginDocument{% + \counterwithin{lstlisting}{section} + \renewcommand{\thelstlisting}{% + \ifnum\value{subsection}=0 + \thesection.\arabic{lstlisting}% + \else + \thesubsection.\arabic{lstlisting}% + \fi + } +} + % for pdflatex only %\pdfminorversion=4 %\pdfobjcompresslevel=0 @@ -91,6 +123,8 @@ \captionsetup[figure]{belowskip=0pt} \captionsetup[table]{aboveskip=0pt} \captionsetup[table]{belowskip=5pt} +\captionsetup[listing]{aboveskip=5pt} +\captionsetup[listing]{belowskip=0pt} % =========================================================================== % @@ -328,6 +362,18 @@ \clearpage } +\def\seznamkodu{ + \clearpage + \phantomsection + \ifczech + \addcontentsline{toc}{section}{Seznam kódů} + \else \ifenglish + \addcontentsline{toc}{section}{List of Listings} + \fi + \lstlistoflistings + \clearpage +} + % Příkaz pro vysázení seznamu tabulek \def\seznamtab{ \clearpage @@ -628,6 +674,7 @@ \def\thefigure{\arabic{figure}} % číslování obrázků typu (y) \def\thetable{\arabic{table}} % číslování tabulek typu (y) +\def\thelstlisting{\arabic{listing}} \captiondelim{. } % změníme dvoutečku za Obr/Tab za tečku % Nastavení číslování obrázků, tabulek i rovnic do formátu <číslo kapitoly>. @@ -640,11 +687,13 @@ %{\renewcommand*\numberline[1]{Fig. \,#1\space}} %\renewcommand*\l@figure{\@dottedtocline{1}{0em}{5.0em}} %\renewcommand*\l@table{\@dottedtocline{1}{0em}{5.0em}} +\def\l@lstlisting#1#2{\@dottedtocline{1}{0em}{5.0em}{\lstlistingname\space#1}{#2}} % Vynulování čítačů \@addtoreset{table}{section} \@addtoreset{figure}{section} \@addtoreset{footnote}{section} +\@addtoreset{lstlisting}{section} \makeatother % a to je ukončení \makeatletter @@ -677,6 +726,8 @@ \cftsetindents{subsubsec}{1cm}{1.5cm} \cftsetindents{fig}{0cm}{1.5cm} \cftsetindents{tab}{0cm}{1.5cm} +\cftsetindents{lstlisting}{0cm}{1.5cm} +\cftsetindents{listing}{0cm}{1.5cm} % nastavení vodící čáry pro styl část, nadpis 1--3, obrázky a tabulky \renewcommand{\cftdot}{\ensuremath{.}} % tímto příkazem lze změnit vodící tečky v obsahu na jiný znak @@ -686,11 +737,14 @@ \renewcommand{\cftsubsubsecleader}{\cftdotfill{0.3}} \renewcommand{\cftfigleader}{\cftdotfill{0.3}} \renewcommand{\cfttableader}{\cftdotfill{0.3}} +\renewcommand{\cftlstlistingleader}{\cftdotfill{0.3}} +\renewcommand{\cftlistingleader}{\cftdotfill{0.3}} % změna fontu pro text "Obsah", "Seznam obrázků" a "Seznam tabulek" \renewcommand{\cfttoctitlefont}{\normalsize\bfseries\thispagestyle{empty}} \renewcommand{\cftloftitlefont}{\normalsize\bfseries\thispagestyle{fancy}} \renewcommand{\cftlottitlefont}{\normalsize\bfseries\thispagestyle{fancy}} +\renewcommand{\cftloltitlefont}{\normalsize\bfseries\thispagestyle{fancy}} \renewcommand{\cfttabpresnum}{Tab. } \renewcommand{\cftfigaftersnum}{.} @@ -810,13 +864,16 @@ \addto\captionsczech{\renewcommand{\refname}{\MakeTextUppercase{Seznam použité literatury}}} \addto\captionsczech{\renewcommand{\listfigurename}{\MakeTextUppercase{Seznam obrázků}}} \addto\captionsczech{\renewcommand{\listtablename}{\MakeTextUppercase{Seznam tabulek}}} + \renewcommand{\lstlistlistingname}{\MakeTextUppercase{Seznam kódů}} %\addto\captionsczech{\renewcommand{\figurename}{Obr.}} %\addto\captionsczech{\renewcommand{\tablename}{Tab.}} \renewcommand{\cftfigpresnum}{Obr. } \else \ifenglish \usepackage[UKenglish]{babel} \selectlanguage{english} - \hyphenpenalty 5000 + % \hyphenpenalty 7000 + \hyphenpenalty 7000 + %\hyphenpenalty 9000 % \hyphenpenalty 10000 % \exhyphenpenalty 10000 % Vlastni definice nazvu @@ -824,6 +881,7 @@ \addto\captionsenglish{\renewcommand{\refname}{\MakeTextUppercase{References}}} \addto\captionsenglish{\renewcommand{\listfigurename}{\MakeTextUppercase{List of Figures}}} \addto\captionsenglish{\renewcommand{\listtablename}{\MakeTextUppercase{List of Tables}}} + \renewcommand{\lstlistlistingname}{List of Listings} %\addto\captionsenglish{\renewcommand{\figurename}{Fig.}} %\addto\captionsenglish{\renewcommand{\tablename}{Tab.}} \renewcommand{\cftfigpresnum}{Fig. } diff --git a/tex/text.tex b/tex/text.tex index 5bf4b98..235ffeb 100644 --- a/tex/text.tex +++ b/tex/text.tex @@ -2,14 +2,6 @@ % Encoding: UTF-8 (žluťoučký kůň úpěl ďábelšké ódy) % =========================================================================== % -\vspace*{\fill} -\begin{center} -\Large -\textit{This is a document draft.} -\end{center} -\vspace*{\fill} -\newpage - % =========================================================================== % \nn{Introduction} Introduce the goals and the methods attempted to achieve the goals. @@ -246,7 +238,7 @@ represents that a password is: \end{itemize} \obr{Short arbitrary password length -limit~\cite{larsklint}}{fig:forbiddencharacters}{.8}{graphics/arbitrarypasswdlengthlimit.jpg} +limit~\cite{larsklint}}{fig:arbitrarypasswdlengthlimit}{.8}{graphics/arbitrarypasswdlengthlimit.jpg} This is wrong for multiple reasons, and it is a classic example of short arbitrary length requirement. It essentially prevents users from using @@ -616,22 +608,17 @@ reference. The validity of a signature on a particular commit can be viewed with git using the following commands (the \% sign denotes the shell prompt): -\begin{figure}[h] - \centering - \begin{varwidth}{\linewidth} - \begin{verbatim} +\vspace{\parskip} +\begin{lstlisting}[language=bash, caption={Verifying signature of a git commit}, +label=gitverif, basicstyle=\linespread{0.9}\footnotesize\ttfamily] % cd % git show --show-signature % # alternatively: % git verify-commit - \end{verbatim} - \end{varwidth} - \caption{Verifying signature of a git commit} - \label{fig:gitverif} -\end{figure} +\end{lstlisting} There is one caveat to this though, git first needs some additional -configuration for the code in Figure~\ref{fig:gitverif} to work as one would +configuration for the code in Listing~\ref{gitverif} to work as one would expect. Namely that the public key used to verify the signature needs to be stored in git's ``allowed signers file'', then git needs to be told where that file is using the configuration value \texttt{gpg.ssh.allowedsignersfile} and @@ -642,26 +629,20 @@ Because git allows the configuration values to be local to each repository, both of the mentioned issues can be solved by running the following commands from inside of the cloned repository: -\begin{figure}[h] - \centering - \begin{varwidth}{\linewidth} - \scriptsize - \begin{verbatim} - % # set the signature format for the local repository. - % git config --local gpg.format ssh - % # save the public key. - % cat >./tmp/.allowed_signers \ - <<<'leo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwshTdBgLzwY4d8N7VainZCngH88OwvPGhZ6bm87rBO' - % # set the allowed signers file path for the local repository. - % git config --local gpg.ssh.allowedsignersfile=./tmp/.allowed_signers - \end{verbatim} - \end{varwidth} - \caption{Prepare allowed signers file and signature format for git} - \label{fig:gitsshprep} -\end{figure} +\vspace{\parskip} +\begin{lstlisting}[language=bash, caption={Prepare allowed signers file and signature format for git}, +label=gitsshprep, basicstyle=\linespread{0.9}\footnotesize\ttfamily] +% # set the signature format for the local repository. +% git config --local gpg.format ssh +% # save the public key. +% cat >./tmp/.allowed_signers \ + <<<'leo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwshTdBgLzwY4d8N7VainZCngH88OwvPGhZ6bm87rBO' +% # set the allowed signers file path for the local repository. +% git config --local gpg.ssh.allowedsignersfile=./tmp/.allowed_signers +\end{lstlisting} -After the code in Figure~\ref{fig:gitsshprep} is run, everything from the -Figure~\ref{fig:gitverif} should remain applicable for the lifetime of the +After the code in Listing~\ref{gitsshprep} is run, everything from the +Listing~\ref{gitverif} should remain applicable for the lifetime of the repository or until git changes implementation of signature verification. The git \texttt{user.name} that can be seen on the commits in the \textbf{Author} field is named after the machine that was used to develop the program, since @@ -725,7 +706,7 @@ and a 400Mbps downlink, software-wise running Arch with an author-flavoured Xanmod kernel version 6.3.x. \obr{Drone CI median build -time}{fig:drone-median-build}{.77}{graphics/drone-median-build} +time}{fig:drone-median-build}{.84}{graphics/drone-median-build} \n{2}{Source code repositories}\label{sec:repos} @@ -946,67 +927,62 @@ Section~\ref{sec:repos} for details). This enabled it to be independently developed and versioned, and only pulled into the main application whenever it is determined the application is ready for it. -The full schema with type annotations can be seen in -Figure~\ref{fig:dhallschema}. The \texttt{let} statement declares a variable -called \texttt{Schema} and assigns it the result of the expression on the right -side of the equals sign, which has for practical reasons been trimmed and is -displayed without the \emph{default} block, which is instead shown in its own -Figure~\ref{fig:dhallschemadefaults}. +The full schema with type annotations can be seen in Listing~\ref{dhallschema}. +The \texttt{let} statement declares a variable called \texttt{Schema} and +assigns it the result of the expression on the right side of the equals sign, +which has for practical reasons been trimmed and is displayed without the +\emph{default} block, which is instead shown in its own +Listing~\ref{dhallschemadefaults}. -\begin{figure}[!h] - \begin{varwidth} - \scriptsize - \begin{verbatim} - let Schema = - { Type = - { Host : Text - , Port : Natural - , HTTP : - { Domain : Text - , Secure : Bool - , AutoTLS : Bool - , TLSKeyPath : Text - , TLSCertKeyPath : Text - , HSTSMaxAge : Natural - , ContentSecurityPolicy : Text - , RateLimit : Natural - , Gzip : Natural - , Timeout : Natural - } - , Mailer : - { Enabled : Bool - , Protocol : Text - , SMTPAddr : Text - , SMTPPort : Natural - , ForceTrustServerCert : Bool - , EnableHELO : Bool - , HELOHostname : Text - , Auth : Text - , From : Text - , User : Text - , Password : Text - , SubjectPrefix : Text - , SendPlainText : Bool - } - , LiveMode : Bool - , DevelMode : Bool - , AppPath : Text - , Session : - { CookieName : Text - , CookieAuthSecret : Text - , CookieEncrSecret : Text - , MaxAge : Natural - } - , Logger : { JSON : Bool, Fmt : Optional Text } - , Init : { CreateAdmin : Bool, AdminPassword : Text } - , Registration : { Allowed : Bool } +\vspace{\parskip} +\begin{lstlisting}[language=Haskell, caption={Dhall configuration schema version 0.0.1-rc.2}, +label=dhallschema, basicstyle=\linespread{0.9}\footnotesize\ttfamily] +let Schema = + { Type = + { Host : Text + , Port : Natural + , HTTP : + { Domain : Text + , Secure : Bool + , AutoTLS : Bool + , TLSKeyPath : Text + , TLSCertKeyPath : Text + , HSTSMaxAge : Natural + , ContentSecurityPolicy : Text + , RateLimit : Natural + , Gzip : Natural + , Timeout : Natural } + , Mailer : + { Enabled : Bool + , Protocol : Text + , SMTPAddr : Text + , SMTPPort : Natural + , ForceTrustServerCert : Bool + , EnableHELO : Bool + , HELOHostname : Text + , Auth : Text + , From : Text + , User : Text + , Password : Text + , SubjectPrefix : Text + , SendPlainText : Bool + } + , LiveMode : Bool + , DevelMode : Bool + , AppPath : Text + , Session : + { CookieName : Text + , CookieAuthSecret : Text + , CookieEncrSecret : Text + , MaxAge : Natural + } + , Logger : { JSON : Bool, Fmt : Optional Text } + , Init : { CreateAdmin : Bool, AdminPassword : Text } + , Registration : { Allowed : Bool } } - \end{verbatim} - \end{varwidth} - \caption{Dhall configuration schema version 0.0.1-rc.2} - \label{fig:dhallschema} -\end{figure} + } +\end{lstlisting} The main configuration is comprised of both raw attributes and child records, which allow for grouping of related functionality. For instance, configuration @@ -1020,6 +996,75 @@ while \textbf{true} is evaluated as an \emph{unbound} variable, that is, a variable \emph{not} defined in the current \emph{scope} and thus not \emph{present} in the current scope. +\vspace{\parskip} +\begin{lstlisting}[language=Haskell, caption={Dhall configuration defaults for +schema version 0.0.1-rc.2}, +label=dhallschemadefaults, basicstyle=\linespread{0.9}\scriptsize\ttfamily] + , default = + -- | have sane defaults. + { Host = "" + , Port = 3000 + , HTTP = + { Domain = "" + , Secure = False + , AutoTLS = False + , TLSKeyPath = "" + , TLSCertKeyPath = "" + , HSTSMaxAge = 0 + , ContentSecurityPolicy = "" + , RateLimit = 0 + , Gzip = 0 + , Timeout = 0 + } + , Mailer = + { Enabled = False + , Protocol = "smtps" + , SMTPAddr = "" + , SMTPPort = 465 + , ForceTrustServerCert = False + , EnableHELO = False + , HELOHostname = "" + , Auth = "" + , From = "" + , User = "" + , Password = "" + , SubjectPrefix = "pcmt - " + , SendPlainText = True + } + , LiveMode = + -- | LiveMode controls whether the application looks for + -- | directories "assets" and "templates" on the filesystem or + -- | in its bundled Embed.FS. + False + , DevelMode = False + , AppPath = + -- | AppPath specifies where the program looks for "assets" and + -- | "templates" in case LiveMode is True. + "." + , Session = + { CookieName = "pcmt_session" + , CookieAuthSecret = "" + , CookieEncrSecret = "" + , MaxAge = 3600 + } + , Logger = { JSON = True, Fmt = None Text } + , Init = + { CreateAdmin = + -- | if this is True, attempt to create a user with admin + -- | privileges with the password specified below (or better - + -- | overriden); it fails if users already exist in the DB. + False + , AdminPassword = + -- | used for the first admin, forced change on first login. + "50ce50fd0e4f5894d74c4caecb450b00c594681d9397de98ffc0c76af5cff5953eb795f7" + } + , Registration.Allowed = True + } + } + +in Schema +\end{lstlisting} + Another one of specialties of Dhall is that $==$ and $!=$ equality operators only work on values of type \texttt{Bool}, which for example means that variables of type \texttt{Natural} (\texttt{uint}) or \texttt{Text} @@ -1040,80 +1085,6 @@ same-origin policy and (optionally) pinning a cryptographic hash of the value of the expression being imported. -\begin{figure}[!h] - \begin{varwidth} - \scriptsize - \begin{verbatim} - , default = - -- | have sane defaults. - { Host = "" - , Port = 3000 - , HTTP = - { Domain = "" - , Secure = False - , AutoTLS = False - , TLSKeyPath = "" - , TLSCertKeyPath = "" - , HSTSMaxAge = 0 - , ContentSecurityPolicy = "" - , RateLimit = 0 - , Gzip = 0 - , Timeout = 0 - } - , Mailer = - { Enabled = False - , Protocol = "smtps" - , SMTPAddr = "" - , SMTPPort = 465 - , ForceTrustServerCert = False - , EnableHELO = False - , HELOHostname = "" - , Auth = "" - , From = "" - , User = "" - , Password = "" - , SubjectPrefix = "pcmt - " - , SendPlainText = True - } - , LiveMode = - -- | LiveMode controls whether the application looks for - -- | directories "assets" and "templates" on the filesystem or - -- | in its bundled Embed.FS. - False - , DevelMode = False - , AppPath = - -- | AppPath specifies where the program looks for "assets" and - -- | "templates" in case LiveMode is True. - "." - , Session = - { CookieName = "pcmt_session" - , CookieAuthSecret = "" - , CookieEncrSecret = "" - , MaxAge = 3600 - } - , Logger = { JSON = True, Fmt = None Text } - , Init = - { CreateAdmin = - -- | if this is True, attempt to create a user with admin - -- | privileges with the password specified below (or better - - -- | overriden); it fails if users already exist in the DB. - False - , AdminPassword = - -- | used for the first admin, forced change on first login. - "50ce50fd0e4f5894d74c4caecb450b00c594681d9397de98ffc0c76af5cff5953eb795f7" - } - , Registration.Allowed = True - } - } - - in Schema - \end{verbatim} - \end{varwidth} - \caption{Dhall configuration defaults for schema version 0.0.1-rc.2} - \label{fig:dhallschemadefaults} -\end{figure} - - \n{3}{Possible alternatives} While developing the program, the author has also @@ -1304,7 +1275,7 @@ user for browsing. \n{3}{Local Dataset Plugin} Breach data from locally available datasets can be imported into the application by first making sure it adheres to the specified schema (have a look at the \emph{breach data schema} in -Figure~\ref{fig:breachDataGoSchema}). If it doesn't (which is very likely with +Listing~\ref{breachDataGoSchema}). If it doesn't (which is very likely with random breach data), it needs to be converted to a form that does before importing it to the application, e.g.\ using a Python script or similar. Attempting to import data that does not follow the outlined schema would result @@ -1313,10 +1284,9 @@ would by default be rejected by the program as a precaution, since marshaling e.g.\ a 1 TiB document would likely result in an OOM situation on the host, assuming regular consumer hardware conditions, not HPC. -\begin{figure}[h] - \centering - \begin{varwidth}{\linewidth} - \begin{verbatim} +\vspace{\parskip} +\begin{lstlisting}[language=Go, caption={Breach Data Schema represented as a Go struct with imports from the standard library are assumed}, +label=breachDataGoSchema] type breachDataSchema struct { Name string Time time.Time @@ -1330,28 +1300,22 @@ assuming regular consumer hardware conditions, not HPC. ContainsEmails bool Data any } - \end{verbatim} - \end{varwidth} +\end{lstlisting} - \caption{Breach Data Schema represented as a Go struct with imports from the - standard library are assumed} - \label{fig:breachDataGoSchema} -\end{figure} - -The Go representation shown in Figure~\ref{fig:breachDataGoSchema} will in +The Go representation shown in Listing~\ref{breachDataGoSchema} will in actuality be written and supplied by the user of the program as a YAML document. YAML was chosen for multiple reasons: relative ease of use (plain text, readable, support for inclusion of comments, its capability to store multiple \emph{documents} inside of a single file with most of the inputs implicitly typed as strings while thanks to being a superset of JSON it sports machine readability. That should allow for documents similar to what can be -seen in Figure~\ref{fig:breachDataYAMLSchema} to be ingested by the program, +seen in Listing~\ref{breachDataYAMLSchema} to be ingested by the program, read and written by humans and programs alike. -\begin{figure}[h] - \centering - \begin{varwidth}{\linewidth} - \begin{verbatim} +\vspace{\parskip} +\begin{lstlisting}[language=YAML, caption={Example Breach Data Schema supplied +to the program as a YAML file, optionally containing multiple documents}, +label=breachDataYAMLSchema] --- name: Horrible breach time: 2022-04-23T00:00:00Z+02:00 @@ -1375,17 +1339,10 @@ read and written by humans and programs alike. # document #2, describing another breach. name: Horrible breach 2 ... - } - \end{verbatim} - \end{varwidth} +\end{lstlisting} - \caption{Example Breach Data Schema supplied to the program as a YAML file, optionally - containing multiple documents} - \label{fig:breachDataYAMLSchema} -\end{figure} - -Notice how the emails list in Figure~\ref{fig:breachDataYAMLSchema} misses one -record, perhaps because it was not supplied or mistakenly ommitted. This is a +Notice how the emails list in Listing~\ref{breachDataYAMLSchema} misses one +record, perhaps because it was not supplied or mistakenly omitted. This is a valid scenario (mistakes happen) and the application needs to be able to handle it. The alternative would be to require the user to prepare the data in such a way that the empty/partial records would be dropped entirely. @@ -1559,9 +1516,9 @@ then after pushing to remote in the CI. \n{3}{func TestUserExists(t *testing.T)} -An example integration test shown in Figure~\ref{fig:integrationtest} can be +An example integration test shown in Listing~\ref{integrationtest} can be seen to declare a helper function \texttt{getCtx() context.Context}, which -takes no arguments and returns a new \texttt{context.Context} initialised with +takes no arguments and returns a new\\ \texttt{context.Context} initialised with a value of the global logger, which is how the logger gets injected into the user module functions. The function \texttt{TestUserExists(t *testing.T)} first declares a database connection string and attempting to open a connection to @@ -1596,10 +1553,84 @@ first argument, with the database pointer and username being passed next, while the \texttt{email} variable is only used at a later stage, but was declared here to give a sense of grouping. The error value returned from this function is again checked and if everything goes well, the value of the -\texttt{usernameFound} boolean is checked next. Since the database has just -been created, there should be no users, which is checked in the next -\texttt{if} statement. The same check is then performed for the -earlier-declared user email that is also expected to fail. +\texttt{usernameFound} boolean is checked next. + +\smallskip +\begin{lstlisting}[language=Go, caption={Example integration test.}, +label=integrationtest,basicstyle=\linespread{0.8}\footnotesize\ttfamily] +// modules/user/user_test.go +package user + +import ( + "context" + "testing" + + "git.dotya.ml/mirre-mt/pcmt/ent/enttest" + "git.dotya.ml/mirre-mt/pcmt/slogging" + _ "github.com/xiaoqidun/entps" +) + +func getCtx() context.Context { + l := slogging.Init(false) + ctx := context.WithValue(context.Background(), CtxKey{}, l) + + return ctx +} + +func TestUserExists(t *testing.T) { + connstr := "file:ent_tests?mode=memory&_fk=1" + db := enttest.Open(t, "sqlite3", connstr) + defer db.Close() + + if err := db.Schema.Create(context.Background()); err != nil { + t.Errorf("failed to create schema resources: %v", err) + t.FailNow() + } + + username := "dude" + email := "dude@b.cc" + ctx := getCtx() + + usernameFound, err := UsernameExists(ctx, db, username) + if err != nil { + t.Errorf("error checking for username {%s} existence: %q", + username, + err, + ) + } + + if usernameFound { + t.Errorf("unexpected: user{%s} should not have been found", + username, + ) + } + + if _, err := EmailExists(ctx, db, email); err != nil { + t.Errorf("unexpected: user email '%s' should not have been found", + email, + ) + } + + usr, err := CreateUser(ctx, db, email, username, "so strong") + if err != nil { + t.Errorf("failed to create user, error: %q", err) + t.FailNow() + } else if usr == nil { + t.Error("got nil usr back") + t.FailNow() + } + + if usr.Username != username { + t.Errorf("got back wrong username, want: %s, got: %s", + username, usr.Username, + ) + } // ...more checks... +} +\end{lstlisting} + +Since the database has just been created, there should be no users, which is +checked in the next \texttt{if} statement. The same check is then performed for +the earlier-declared user email that is also expected to fail. The final statements of the described test attempts a user creation call, which is again checked for both error and \emph{nilability}. The test continues with @@ -1609,85 +1640,6 @@ A neat thing about error handling in Go is that it allows for very easy checking of all paths, not just the \emph{happy path} where there are no issues. -\begin{figure}[!h] - \centering - \scriptsize - \begin{varwidth}{\linewidth} - \begin{verbatim} - // modules/user/user_test.go - package user - - import ( - "context" - "testing" - - "git.dotya.ml/mirre-mt/pcmt/ent/enttest" - "git.dotya.ml/mirre-mt/pcmt/slogging" - _ "github.com/xiaoqidun/entps" - ) - - func getCtx() context.Context { - l := slogging.Init(false) - ctx := context.WithValue(context.Background(), CtxKey{}, l) - - return ctx - } - - func TestUserExists(t *testing.T) { - connstr := "file:ent_tests?mode=memory&_fk=1" - db := enttest.Open(t, "sqlite3", connstr) - defer db.Close() - - if err := db.Schema.Create(context.Background()); err != nil { - t.Errorf("failed to create schema resources: %v", err) - t.FailNow() - } - - username := "dude" - email := "dude@b.cc" - ctx := getCtx() - - usernameFound, err := UsernameExists(ctx, db, username) - if err != nil { - t.Errorf("error checking for username {%s} existence: %q", - username, - err, - ) - } - - if usernameFound { - t.Errorf("unexpected: user{%s} should not have been found", - username, - ) - } - - if _, err := EmailExists(ctx, db, email); err != nil { - t.Errorf("unexpected: user email '%s' should not have been found", - email, - ) - } - - usr, err := CreateUser(ctx, db, email, username, "so strong") - if err != nil { - t.Errorf("failed to create user, error: %q", err) - t.FailNow() - } else if usr == nil { - t.Error("got nil usr back") - t.FailNow() - } - - if usr.Username != username { - t.Errorf("got back wrong username, want: %s, got: %s", - username, usr.Username, - ) - } - // ...more checks... - } - \end{verbatim} - \end{varwidth} - \caption{Example integration test} - \label{fig:integrationtest} -\end{figure} \n{2}{Testing environment} diff --git a/thesis.tex b/thesis.tex index 20baefc..b440827 100644 --- a/thesis.tex +++ b/thesis.tex @@ -118,6 +118,7 @@ % list of tables \seznamtab +\seznamkodu % =========================================================================== % % list of appendices