When TeX is absorbing the replacement text for a definition, it does no expansion whatsoever (unless you're using \edef or \xdef). In your replacement text you have
\ifx\relax#1
and the end of line counts as a space, because it is converted to a space during tokenization since it doesn't follow a control word. The space will not be ignored during expansion at macro usage time, because TeX isn't looking for <one optional space>, which it does after numeric constants or after the = in assignments where = is optional and some other cases where even entire strings of space tokens are ignored.
The fact that in the “no optional argument” case #1 is replaced by \relax is completely irrelevant, because spaces are ignored after control words only during tokenization: space tokens that creep in after control words are not ignored.
Note also that in the definition you are doing, TeX actually does two \def commands. First it does
\expandafter\def\expandafter\aetest\expandafter{%
\expandafter\@protected@testopt
\expandafter\aetest
\csname\string\aetest\endcsname{\relax}%
}
and then
\expandafter\def\csname\string\aetest\endcsname[#1]#2{%
\def\aejunk{<#2>}%%
\ifx\relax#1
\else
\def\aejunk{(#2:#1)}%%
\fi
\fbox{\aejunk\rule[-0.5ex]{0pt}{2.5ex}}%%
}
In the second definition, there's no trace of #1 being \relax in the “no optional argument” case. But, as I said, this is irrelevant to begin with.
If you want a safe test for the “no optional argument”, use xparse:
\usepackage{xparse}
\NewDocumentCommand{\aetest}{om}{%
\IfNoValueTF{#1}
{\def\aejunk{<#2>}}
{\def\aejunk{(#1:#2)}}%
\fbox{\aejunk\rule[-0.5ex]{0pt}{2.5ex}}%
}
so \aetest{ciao} and \aetest[]{ciao} would give different results.
On the other hand, if you just want to test if the optional argument is not supplied or it is empty, the usual
\if\relax\detokenize{#1}\relax
test is better.
\aetest{ciao}, since\relaxtests true, and the space is then added, prior to the<ciao>fbox. You can test this by replacing the line-ending "space" with a.%and seeing when the dot shows up. When you comment theciaoline, the dot goes away. So that is its source, and indeed, as I said, it makes sense because the\ifx\relax#1test is true in theciaocase. – Steven B. Segletes Jan 22 '15 at 21:07#1in\ifx\relax#1. i'd reverse this:\ifx#1\relax. – barbara beeton Jan 22 '15 at 21:08#1isaa. – A.Ellett Jan 22 '15 at 21:17\aetest{ciao}should expand to\def\aejunk{<ciao>}%%\ifx\relax\relax....and consequently I would expect that the second\relaxwill gobble up the trailing whitespace of that line. – A.Ellett Jan 22 '15 at 21:22%after#1. – barbara beeton Jan 22 '15 at 21:31\ifx\ifx\relaxdoes not gobble up additional white space if true, only if false. Try\ifx\relax\relax This is true\fito see that what follows a true condition is not gobbled. – Steven B. Segletes Jan 22 '15 at 22:13