Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CNativeW の static 関数に対するテストを追加する #1542

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sakura_core/CRegexKeyword.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ typedef struct RegexInfo_t {
int nFlag; //色指定のチェックが入っているか? YES=RK_EMPTY, NO=RK_NOMATCH
} REGEX_INFO;

class CStringRef;

//! 正規表現キーワードクラス
/*!
正規表現キーワードを扱う。
Expand Down
4 changes: 1 addition & 3 deletions sakura_core/EditInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@

#include "basis/SakuraBasis.h"
#include "config/maxdata.h"
#include "charset/charcode.h"
#include "mem/CNativeW.h"
#include "types/CType.h"
#include "charset/charset.h"

/*!
* ファイル情報
Expand Down
4 changes: 2 additions & 2 deletions sakura_core/charset/charcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ namespace WCODE
bool CalcHankakuByFont(wchar_t);

//2007.08.30 kobake 追加
bool IsHankaku(wchar_t wc)
bool IsHankaku(wchar_t wc, const CCharWidthCache& cache)
{
//※ほぼ未検証。ロジックが確定したらインライン化すると良い。

Expand Down Expand Up @@ -83,7 +83,7 @@ namespace WCODE
}

//$$ 仮。もう動的に計算しちゃえ。(初回のみ)
return CalcHankakuByFont(wc);
return cache.CalcHankakuByFont(wc);
}

//!制御文字であるかどうか
Expand Down
22 changes: 10 additions & 12 deletions sakura_core/charset/charcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,6 @@ namespace WCODE
return c>=front && c<=back;
}

//!半角文字(縦長長方形)かどうか判定
bool IsHankaku(wchar_t wc);

//!全角文字(正方形)かどうか判定
inline bool IsZenkaku(wchar_t wc)
{
return !IsHankaku(wc);
}

//!使用フォント番号を返す
// (0:半角/1:全角)
int GetFontNo(wchar_t c);
Expand Down Expand Up @@ -262,9 +253,9 @@ class CCharWidthCache {
void Clear();
[[nodiscard]] bool GetMultiFont() const { return m_bMultiFont; }

bool CalcHankakuByFont(wchar_t c) const;
int CalcPxWidthByFont(wchar_t c);
int CalcPxWidthByFont2(const wchar_t* pc2) const;
virtual bool CalcHankakuByFont(wchar_t c) const;
virtual int CalcPxWidthByFont(wchar_t c);
virtual int CalcPxWidthByFont2(const wchar_t* pc2) const;

private:
void DeleteLocalData();
Expand All @@ -290,4 +281,11 @@ void InitCharWidthCache( const LOGFONT &lf, ECharWidthFontMode fMode=CWM_FONT_ED
void InitCharWidthCacheFromDC(const LOGFONT* lfs, ECharWidthFontMode fMode, HDC hdcOrg );
[[nodiscard]] CCharWidthCache& GetCharWidthCache();

namespace WCODE {
//!半角文字(縦長長方形)かどうか判定
bool IsHankaku(wchar_t wc, const CCharWidthCache& cache = GetCharWidthCache());
//!全角文字(正方形)かどうか判定
inline bool IsZenkaku(wchar_t wc) { return !IsHankaku(wc); }
}

#endif /* SAKURA_CHARCODE_4C34C669_0BAB_441A_9B1D_2B9AC1895380_H_ */
2 changes: 2 additions & 0 deletions sakura_core/doc/CBlockComment.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ enum ECommentType{
#define BLOCKCOMMENT_NUM 2
#define BLOCKCOMMENT_BUFFERSIZE 16

class CStringRef;

// 2005.11.10 Moca アクセス関数追加
class CBlockComment{
public:
Expand Down
2 changes: 2 additions & 0 deletions sakura_core/doc/CLineComment.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#define COMMENT_DELIMITER_NUM 3
#define COMMENT_DELIMITER_BUFFERSIZE 16

class CStringRef;

/*! 行コメントデリミタを管理する

@note CLineCommentは、共有メモリSTypeConfigに含まれるので、メンバ変数は常に実体を持っていなければならない。
Expand Down
3 changes: 2 additions & 1 deletion sakura_core/env/CAppNodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
#define SAKURA_CAPPNODEMANAGER_CAE7A323_DEA3_47E4_91DE_C99A88C32683_H_
#pragma once

#include "util/design_template.h"
#include "basis/CMyString.h"
#include "config/maxdata.h"
#include "util/design_template.h"

class CAppNodeGroupHandle;

Expand Down
13 changes: 7 additions & 6 deletions sakura_core/mem/CNativeW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ CLogicInt CNativeW::GetSizeOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//! 指定した位置の文字が半角何個分かを返す
CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx )
CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx, const CCharWidthCache& cache)
{
//文字列範囲外なら 0
if( nIdx >= nDataLen )
Expand All @@ -372,7 +372,7 @@ CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//半角文字なら 1
if(WCODE::IsHankaku(pData[nIdx]) )
if(WCODE::IsHankaku(pData[nIdx], cache))
return CKetaXInt(1);

//全角文字なら 2
Expand All @@ -381,25 +381,26 @@ CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//! 指定した位置の文字の文字幅を返す
CHabaXInt CNativeW::GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx )
CHabaXInt CNativeW::GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
CCharWidthCache& cache, bool bEnableExtEol )
{
//文字列範囲外なら 0
if( nIdx >= nDataLen ){
return CHabaXInt(0);
}
// HACK:改行コードに対して1を返す
if( WCODE::IsLineDelimiter(pData[nIdx], GetDllShareData().m_Common.m_sEdit.m_bEnableExtEol) ){
if( WCODE::IsLineDelimiter(pData[nIdx], bEnableExtEol) ){
return CHabaXInt(1);
}

// サロゲートチェック
if(IsUTF16High(pData[nIdx]) && nIdx + 1 < nDataLen && IsUTF16Low(pData[nIdx + 1])){
return CHabaXInt(WCODE::CalcPxWidthByFont2(pData + nIdx));
return CHabaXInt(cache.CalcPxWidthByFont2(pData + nIdx));
}else if(IsUTF16Low(pData[nIdx]) && 0 < nIdx && IsUTF16High(pData[nIdx - 1])) {
// サロゲートペア(下位)
return CHabaXInt(0); // 不正位置
}
return CHabaXInt(WCODE::CalcPxWidthByFont(pData[nIdx]));
return CHabaXInt(cache.CalcPxWidthByFont(pData[nIdx]));
}

/* ポインタで示した文字の次にある文字の位置を返します */
Expand Down
10 changes: 8 additions & 2 deletions sakura_core/mem/CNativeW.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@

#include "CNative.h"
#include "basis/SakuraBasis.h"
#include "charset/charcode.h"
#include "debug/Debug2.h" //assert
#include "env/DLLSHAREDATA.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CNativeWはDLLSHAREDATAの定義に依存する、という意味の変更なので、若干気になっています。
方向的には逆ですよね。(暗黙的に依存していたのを解消させようとしてる)


//! 文字列への参照を取得するインターフェース
class IStringRef{
Expand Down Expand Up @@ -163,8 +165,12 @@ class CNativeW final : public CNative{
public:
// -- -- staticインターフェース -- -- //
static CLogicInt GetSizeOfChar( const wchar_t* pData, int nDataLen, int nIdx ); //!< 指定した位置の文字がwchar_t何個分かを返す
static CHabaXInt GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx );
static CKetaXInt GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx ); //!< 指定した位置の文字が半角何個分かを返す
static CHabaXInt GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
CCharWidthCache& cache = GetCharWidthCache(),
bool bEnableExtEol = GetDllShareData().m_Common.m_sEdit.m_bEnableExtEol );
Copy link
Contributor

@berryzplus berryzplus Feb 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には cache と bEnableExtEol の定義順を逆にして、
bEnableExtEol のデフォルト指定を外したいっす。

bEnableExtEol のデフォルト指定を外すメリットは、#include "DLLSHAREDATA.h" する必要がなくなる、です。
また、デフォルト指定を外すことにより、共有メモリ(=プロセス間をまたがって有効な超グローバル変数)に依存するコードの特定が容易になるっす。共有メモリに依存するコードは現実的にテスト不能なコードなので、テスト可能にできるようにして行ってる認識です。

もちろん、増やした引数のデフォルト指定をやめるってことは、呼出元を変更する必要が出てくるってことなので無理に対応しなくてよいと思っています。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

共有メモリ依存を明確にしていくのは確かに意義がありそうです。別PRで実施します。

//! 指定した位置の文字が半角何個分かを返す
static CKetaXInt GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
const CCharWidthCache& cache = GetCharWidthCache() );
static const wchar_t* GetCharNext( const wchar_t* pData, int nDataLen, const wchar_t* pDataCurrent ); //!< ポインタで示した文字の次にある文字の位置を返します
static const wchar_t* GetCharPrev( const wchar_t* pData, int nDataLen, const wchar_t* pDataCurrent ); //!< ポインタで示した文字の直前にある文字の位置を返します

Expand Down
1 change: 1 addition & 0 deletions sakura_core/recent/SShare_History.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef SAKURA_SSHARE_HISTORY_9F7E6200_FEE2_4CAC_A5D3_32EEC4130CFC_H_
#define SAKURA_SSHARE_HISTORY_9F7E6200_FEE2_4CAC_A5D3_32EEC4130CFC_H_

#include "EditInfo.h"
#include "config/maxdata.h"

//共有メモリ内構造体
Expand Down
131 changes: 131 additions & 0 deletions tests/unittests/test-cnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
#include <stdexcept>
#include <gtest/gtest.h>
#include "charset/charcode.h"
#include "mem/CNativeW.h"
#include "mem/CNativeA.h"

Expand Down Expand Up @@ -741,3 +742,133 @@ TEST(CNativeW, globalOperatorAdd)
CNativeW v4(L"後半");
EXPECT_STREQ(L"前半後半", (v3 + v4).GetStringPtr());
}

/*!
* @brief GetSizeOfCharの仕様
* @remark 指定した文字の符号単位数を返す。
*/
TEST(CNativeW, GetSizeOfChar)
{
// 基本多言語面の文字ならば1を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"a", 1, 0), 1);
// 範囲外なら0を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"", 0, 0), 0);
// 上位・下位サロゲートの組み合わせであれば2を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"\xd83c\xdf38", 2, 0), 2);
// 指定位置が下位サロゲートならその他の文字と同様に1を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"\xd83c\xdf38", 2, 1), 1);
}

/*!
* @brief GetKetaOfCharの仕様
* @remark 指定した文字の桁数を返す。
*/
TEST(CNativeW, GetKetaOfChar)
{
// 範囲外なら0を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"", 0, 0), 0);
// 上位サロゲートなら2を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xd83c\xdf38", 2, 0), 2);
// 上位サロゲートに続く下位サロゲートであれば0を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xd83c\xdf38", 2, 1), 0);
// 下位サロゲートだけなら2を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdf38", 1, 0), 2);

// サクラエディタでは Unicode で表現できない文字コードの破壊を防ぐため、
// 不明バイトを下位サロゲートにマップして保持している。
// この1バイト文字は半角として扱わなければ不自然なので、
// 上位対を持たない下位サロゲート 0xdc00 ~ 0xdcff の範囲に限り、1を返すことになっている。
//
// https://sourceforge.net/p/sakura-editor/patchunicode/57/
// http://sakura-editor.sourceforge.net/cgi-bin/cyclamen/cyclamen.cgi?log=unicode&v=833
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdbff", 1, 0), 2);
for (wchar_t ch = 0xdc00; ch <= 0xdcff; ++ch)
EXPECT_EQ(CNativeW::GetKetaOfChar(&ch, 1, 0), 1);
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdd00", 1, 0), 2);

// 文字が半角なら1を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"a", 1, 0), 1);

// 文字が全角なら2を返す。
class FakeCache : public CCharWidthCache {
public:
bool CalcHankakuByFont(wchar_t c) const override { return false; }
} cache;
EXPECT_EQ(CNativeW::GetKetaOfChar(L"あ", 1, 0, cache), 2);
}

/*!
* @brief GetKetaOfCharの仕様
* @remark 指定した文字のピクセル単位幅を返す。
*/
TEST(CNativeW, GetHabaOfChar)
{
// 範囲外なら0を返す。
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"", 0, 1, GetCharWidthCache(), false), 0);

// 改行コードなら1を返す。
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\r\n", 2, 0, GetCharWidthCache(), false), 1);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\r\n", 2, 1, GetCharWidthCache(), false), 1);

// CalcPxWidthByFont で計算した結果を返す。
class FakeCache1 : public CCharWidthCache {
public:
int CalcPxWidthByFont(wchar_t ch) override {
if (ch == L'a') return 10000;
else if (ch == L'b') return 20000;
else return 0;
}
} cache1;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"ab", 2, 0, cache1, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"ab", 2, 1, cache1, false), 20000);

// サロゲートペアの幅は CalcPxWidthByFont2 で計算する。
// 指定された位置が下位サロゲートなら0を返す。
class FakeCache2 : public CCharWidthCache {
public:
int CalcPxWidthByFont2(const wchar_t* pc2) const override {
return 20000;
}
} cache2;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83c\xdf38", 2, 0, cache2, false), 20000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83c\xdf38", 2, 1, cache2, false), 0);

// サロゲートペアが片方しかないときは CalcPxWidthByFont で計算している。
class FakeCache3 : public CCharWidthCache {
public:
int CalcPxWidthByFont(wchar_t c) override {
return 10000;
}
} cache3;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83cあ", 2, 0, cache3, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xdf38あ", 2, 0, cache3, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"あ\xdf38", 2, 1, cache3, false), 10000);
}

/*!
* @brief GetCharNextの仕様
*/
TEST(CNativeW, GetCharNext)
{
constexpr wchar_t* text = L"a\xd83c\xdf38";
// 次の文字のアドレスを返す。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text), text + 1);
// 上位サロゲートが渡された場合は下位サロゲートを飛ばす。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text + 1), text + 3);
// ポインタを進めた結果が範囲外なら &pData[nDataLen] を返す。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text + 3), text + 3);
}

/*!
* @brief GetCharPrevの仕様
*/
TEST(CNativeW, GetCharPrev)
{
constexpr wchar_t* text = L"a\xd83c\xdf38" L"d";
// 前の文字のアドレスを返す。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text + 1), text);
// 前の文字が下位サロゲートだった場合は下位サロゲートを飛ばす。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text + 3), text + 1);
// ポインタを戻した結果が範囲外なら pData を返す。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text), text);
}