Skip to content

Commit

Permalink
Add tests of IsMailAddress. (sakura-editor#823)
Browse files Browse the repository at this point in the history
* IsMailAddress 関数に追加された offset パラメータに関するテストを追加する。

* IsMailAddress 関数とその呼び出し元である IsURL 関数に doxygen コメントを整備する。
  • Loading branch information
ds14050 authored Apr 20, 2019
1 parent 54cabcf commit 50e1b3a
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 5 deletions.
35 changes: 30 additions & 5 deletions sakura_core/parse/CWordParse.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,40 @@ class CWordParse{
static bool _match_charlist( const WCHAR c, const WCHAR *pszList );
};

BOOL IsURL( const wchar_t* psz, int offset, int length, int* outLength);/* offset 引数の追加により境界判定が行える高速版 */
/** 指定アドレスが URL の先頭ならば TRUE とその長さを返す。
@param[in] pszLine 文字列バッファの先頭アドレス
@param[in] offset URL 判定開始文字を示す、pszLine からの相対位置。
@param[in] nLineLen URL 判定最終文字の次を示す、pszLine からの相対位置。
@param[out] pnMatchLen URL の長さを受け取る変数のアドレス。NULL可。長さとは pszLine + offset からの距離。
境界判定はメールアドレスの先頭でのみ行われ、URL の先頭ではこれまで通り行われません。
*/
BOOL IsURL( const wchar_t* pszLine, int offset, int nLineLen, int* pnMatchLen);

/** @deprecated 互換性のために残されています。offset 引数が追加されたものを使用してください。
*/
inline
BOOL IsURL( const wchar_t* psz, int length, int* outLength) /* 指定アドレスがURLの先頭ならばTRUEとその長さを返す。高速版の追加により obsolete. */
BOOL IsURL( const wchar_t* pszLine, int nLineLen, int* pnMatchLen)
{
return IsURL(psz, 0, length, outLength);
return IsURL(pszLine, 0, nLineLen, pnMatchLen);
}
BOOL IsMailAddress( const wchar_t* pszBuf, int offset, int nBufLen, int* pnAddressLength); /* offset 引数の追加により境界判定が行える高速版 */

/** 指定アドレスがメールアドレスの先頭ならば TRUE とその長さを返す。
@param[in] pszBuf 文字列バッファの先頭アドレス
@param[in] offset メールアドレス判定開始文字を示す、pszBuf からの相対位置。
@param[in] nBufLen メールアドレス判定最終文字の次を示す、pszBuf からの相対位置。
@param[out] pnAddressLength メールアドレスの長さを受け取る変数のアドレス。NULL可。長さとは pszBuf + offset からの距離。
正の offset が与えられた場合は、その場合に限り、判定開始位置直前の文字との間で境界判定を行います。
途中から切り出したメールアドレスの一部をメールアドレスであると誤って判定しないために
pszBuf を固定し offset を0以上の範囲で変化させるのが望ましい使用方法です。
*/
BOOL IsMailAddress( const wchar_t* pszBuf, int offset, int nBufLen, int* pnAddressLength);

/** @deprecated 互換性のために残されています。offset 引数が追加されたものを使用してください。
*/
inline
BOOL IsMailAddress( const wchar_t* pszBuf, int nBufLen, int* pnAddressLength) /* 現在位置がメールアドレスならば、NULL以外と、その長さを返す。高速版の追加により obsolete. */
BOOL IsMailAddress( const wchar_t* pszBuf, int nBufLen, int* pnAddressLength)
{
return IsMailAddress(pszBuf, 0, nBufLen, pnAddressLength);
}
Expand Down
117 changes: 117 additions & 0 deletions tests/unittests/test-is_mailaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

#define NOMINMAX
#include <tchar.h>
#include <wchar.h>
#include <assert.h>
#include <string>
#include <Windows.h>
#include "parse/CWordParse.h"

Expand Down Expand Up @@ -199,6 +202,120 @@ TEST(testIsMailAddress, CheckAwithAtmark)
ASSERT_SAME(FALSE, szTest, _countof(szTest) - 1, NULL);
}

TEST(testIsMailAddress, OffsetParameter)
{
/*
Prepare test cases.
3つの offset値(-1, 0, 1)と、メールアドレスに見える2つの文字列
(Buffer+1=メールアドレスの先頭, Buffer+2=メールアドレスの途中)
の組み合わせにより定義する。
*/
const wchar_t* const Buffer = L" test@example.com";
const wchar_t* const BufferEnd = Buffer + wcslen(Buffer);
const struct {
bool expected;
const wchar_t* address; // to be tested by IsMailAddress.
int offset; // passed to IsMailAddress as 2nd param.
const wchar_t* buffer() const { // passed to IsMailAddress as 1st param.
return this->address - this->offset;
}
} testCases[] = {
{ true, Buffer+1, 0 }, // true is OK. Buffer+1 is a mail address.
{ true, Buffer+1, 1 }, // true is OK. Buffer+1 is a mail address.
{ true, Buffer+1, -1 }, // true is OK. Buffer+1 is a mail address.
{ true, Buffer+2, 0 }, // Limitation: Non positive offset prevents IsMailAddress from looking behind of a possible head of a mail address.
{ false, Buffer+2, 1 }, // false is OK. Buffer+2 is not a head of a mail adderss.
{ true, Buffer+2, -1 } // Limitation: Non positive offset prevents IsMailAddress from looking behind of a possible head of a mail address.
};
for (auto& aCase: testCases) {
assert(Buffer <= aCase.buffer());
}

/*
Apply IsMailAddress to the cases.
*/
for (auto& aCase: testCases) {
EXPECT_EQ(
aCase.expected,
bool(IsMailAddress(aCase.buffer(), aCase.offset, BufferEnd - aCase.buffer(), NULL))
) << "1st param of IsMailAddress: pszBuf is \"" << aCase.buffer() << "\"\n"
<< "2nd param of IsMailAddress: offset is " << aCase.offset;
}
}

TEST(testIsMailAddress, OffsetParameter2)
{
const wchar_t* const Text = L" test@example.com ";
const wchar_t* const Address = Text + 3; // Address is "test@example.com"
const wchar_t* const PseudoAddress = Text + 6; // PseudoAddress is "t@example.c", shortest form recognized by IsMailAddress.
const wchar_t* const PseudoAddressEnd = Text + 17;
const wchar_t* const AddressEnd = Text + 19;
const wchar_t* const TextEnd = Text + 22;

struct Result {
bool is_address;
int length;
};
const Result FalseResult = {false, 0};
auto ExpectedResult = [=](const wchar_t* p1, const wchar_t* p2, const wchar_t* p3) -> Result
{
/*
p2 と p3 が以下の条件を外れたら、TRUE 判定の可能性はゼロ。
* Address <= p2 <= PseudoAddress
* PseudoAddressEnd <= p3
*/
if (p2 < Address || PseudoAddress < p2) {
return FalseResult;
}
if (p3 < PseudoAddressEnd) {
return FalseResult;
}

if (p2 == Address) {
if (AddressEnd <= p3) {
return Result{true, static_cast<int>(AddressEnd - Address)}; // 文句なしの TRUE 判定。
} else {
return Result{true, static_cast<int>(p3 - Address)}; // アドレスの終端が切り詰められているが、IsMailAddress には知る由がない。ゆえに問題なし。
}
} else if (p2 <= p1) {
if (AddressEnd <= p3) {
return Result{true, static_cast<int>(AddressEnd - p2)}; // アドレスの先端が切り詰められているが、IsMailAddress には知る由がない。ゆえに問題なし。
} else {
return Result{true, static_cast<int>(p3 - p2)}; // アドレスの先端と終端が切り詰められているが、IsMailAddress には知る由がない。ゆえに問題なし。
}
} else {
return FalseResult; // アドレスの先端が切り詰められ、IsMailAddress が境界判定によりそれを検知した。文句なしの FALSE 判定。
}
};
auto IsEqualResult = [](const Result& expected, const Result& actual) -> testing::AssertionResult
{
if (expected.is_address != actual.is_address) {
return testing::AssertionFailure() << "IsMailAddress returned " << (actual.is_address?"TRUE":"FALSE") << " but expected " << (expected.is_address?"TRUE":"FALSE") << ".";
}
if (expected.length != actual.length) {
return testing::AssertionFailure() << "IsMailAddress returned the address length " << (actual.length) << " but expected " << (expected.length) << ".";
}
return testing::AssertionSuccess();
};

/*
Text...TextEnd の範囲の文字配列に対して、IsMailAddress の3つの
引数(pszBuf, offset, nBufLen)がとりうるすべての値を総当たりで試す。
*/
for (const wchar_t* p1 = Text; p1 != TextEnd; ++p1) // p1 is a pointer to buffer.
for (const wchar_t* p2 = Text; p2 != TextEnd; ++p2) // p2 is a pointer to address.
for (const wchar_t* p3 = Text; p3 != TextEnd; ++p3) { // p3 is a pointer to the end of buffer.
Result actual = {false, 0};
actual.is_address = IsMailAddress(p1, p2 - p1, p3 - p1, &(actual.length));

EXPECT_TRUE(IsEqualResult(ExpectedResult(p1, p2, p3), actual))
<< "1st param of IsMailAddress: pszBuf is \"" << (p1 <= p3 ? std::string(p1, p3) : "") << "\"\n"
<< "2nd param of IsMailAddress: offset is " << (p2 - p1) << "\n"
<< "pszBuf + offset is \"" << (p2 <= p3 ? std::string(p2, p3) : "") << "\"";
}
}

//////////////////////////////////////////////////////////////////////
// テストマクロの後始末

Expand Down

0 comments on commit 50e1b3a

Please sign in to comment.