refactor: start to refactor project
This commit is contained in:
parent
bec36b4b3c
commit
df3b602110
314
.clang-format
Normal file
314
.clang-format
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
# yaml-language-server: $schema=https://json.schemastore.org/clang-format.json
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveShortCaseStatements:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCaseArrows: false
|
||||||
|
AlignCaseColons: false
|
||||||
|
AlignConsecutiveTableGenBreakingDAGArgColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveTableGenCondOperatorColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveTableGenDefinitionColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments:
|
||||||
|
Kind: Always
|
||||||
|
OverEmptyLines: 0
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowBreakBeforeNoexceptSpecifier: Never
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseExpressionOnASingleLine: true
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortCompoundRequirementOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakAdjacentStringLiterals: true
|
||||||
|
BreakAfterAttributes: Leave
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakAfterReturnType: None
|
||||||
|
BreakArrays: true
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
BreakFunctionDefinitionParameters: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakStringLiterals: false
|
||||||
|
BreakTemplateDeclarations: Yes
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: true
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- forever
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<Q.*'
|
||||||
|
Priority: 200
|
||||||
|
SortPriority: 200
|
||||||
|
CaseSensitive: true
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: false
|
||||||
|
InsertNewlineAtEOF: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
IntegerLiteralSeparator:
|
||||||
|
Binary: 0
|
||||||
|
BinaryMinDigits: 0
|
||||||
|
Decimal: 0
|
||||||
|
DecimalMinDigits: 0
|
||||||
|
Hex: 0
|
||||||
|
HexMinDigits: 0
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLines:
|
||||||
|
AtEndOfFile: false
|
||||||
|
AtStartOfBlock: false
|
||||||
|
AtStartOfFile: false
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
LineEnding: DeriveLF
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MainIncludeChar: Quote
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
PenaltyBreakAssignment: 150
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 300
|
||||||
|
PenaltyBreakComment: 500
|
||||||
|
PenaltyBreakFirstLessLess: 400
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakScopeResolution: 500
|
||||||
|
PenaltyBreakString: 600
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 50
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 300
|
||||||
|
PointerAlignment: Right
|
||||||
|
PPIndentWidth: -1
|
||||||
|
QualifierAlignment: Leave
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: false
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RemoveParentheses: Leave
|
||||||
|
RemoveSemicolon: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
RequiresExpressionIndentation: OuterScope
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SkipMacroDefinitionBody: false
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: Lexicographic
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeJsonColon: false
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: true
|
||||||
|
AfterForeachMacros: true
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterIfMacros: true
|
||||||
|
AfterOverloadedOperator: false
|
||||||
|
AfterPlacementOperator: true
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParens: Never
|
||||||
|
SpacesInParensOptions:
|
||||||
|
ExceptDoubleParentheses: false
|
||||||
|
InCStyleCasts: false
|
||||||
|
InConditionalStatements: false
|
||||||
|
InEmptyParentheses: false
|
||||||
|
Other: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
- emit
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
- Q_CLASSINFO
|
||||||
|
- Q_ENUM
|
||||||
|
- Q_ENUM_NS
|
||||||
|
- Q_FLAG
|
||||||
|
- Q_FLAG_NS
|
||||||
|
- Q_GADGET
|
||||||
|
- Q_GADGET_EXPORT
|
||||||
|
- Q_INTERFACES
|
||||||
|
- Q_LOGGING_CATEGORY
|
||||||
|
- Q_MOC_INCLUDE
|
||||||
|
- Q_NAMESPACE
|
||||||
|
- Q_NAMESPACE_EXPORT
|
||||||
|
- Q_OBJECT
|
||||||
|
- Q_PROPERTY
|
||||||
|
- Q_REVISION
|
||||||
|
- Q_DISABLE_COPY
|
||||||
|
- Q_DISABLE_COPY_MOVE
|
||||||
|
- Q_SET_OBJECT_NAME
|
||||||
|
- QT_BEGIN_NAMESPACE
|
||||||
|
- QT_END_NAMESPACE
|
||||||
|
- QML_ADDED_IN_MINOR_VERSION
|
||||||
|
- QML_ANONYMOUS
|
||||||
|
- QML_ATTACHED
|
||||||
|
- QML_DECLARE_TYPE
|
||||||
|
- QML_DECLARE_TYPEINFO
|
||||||
|
- QML_ELEMENT
|
||||||
|
- QML_EXTENDED
|
||||||
|
- QML_EXTENDED_NAMESPACE
|
||||||
|
- QML_EXTRA_VERSION
|
||||||
|
- QML_FOREIGN
|
||||||
|
- QML_FOREIGN_NAMESPACE
|
||||||
|
- QML_IMPLEMENTS_INTERFACES
|
||||||
|
- QML_INTERFACE
|
||||||
|
- QML_NAMED_ELEMENT
|
||||||
|
- QML_REMOVED_IN_MINOR_VERSION
|
||||||
|
- QML_SINGLETON
|
||||||
|
- QML_UNAVAILABLE
|
||||||
|
- QML_UNCREATABLE
|
||||||
|
- QML_VALUE_TYPE
|
||||||
|
- YYCC_DELETE_COPY
|
||||||
|
- YYCC_DELETE_MOVE
|
||||||
|
- YYCC_DELETE_COPY_MOVE
|
||||||
|
- YYCC_DEFAULT_COPY
|
||||||
|
- YYCC_DEFAULT_MOVE
|
||||||
|
- YYCC_DEFAULT_COPY_MOVE
|
||||||
|
TableGenBreakInsideDAGArg: DontBreak
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
VerilogBreakBetweenInstancePorts: true
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- STRINGIZE
|
||||||
|
...
|
||||||
|
|
3
.editorconfig
Normal file
3
.editorconfig
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[*.{cpp,hpp}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.23)
|
cmake_minimum_required(VERSION 3.23)
|
||||||
project(YYCC
|
project(YYCC
|
||||||
VERSION 1.3.0
|
VERSION 2.0.0
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,6 +20,14 @@ set(YYCC_INSTALL_BIN_PATH ${CMAKE_INSTALL_BINDIR} CACHE PATH
|
|||||||
set(YYCC_INSTALL_DOC_PATH ${CMAKE_INSTALL_DOCDIR} CACHE PATH
|
set(YYCC_INSTALL_DOC_PATH ${CMAKE_INSTALL_DOCDIR} CACHE PATH
|
||||||
"Non-arch doc install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
|
"Non-arch doc install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
|
||||||
|
|
||||||
|
# Include dependency.
|
||||||
|
# GTest is required if we build testbench
|
||||||
|
if (YYCC_BUILD_TESTBENCH)
|
||||||
|
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Import 3 build targets
|
# Import 3 build targets
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
if (YYCC_BUILD_TESTBENCH)
|
if (YYCC_BUILD_TESTBENCH)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Configure version file
|
# Configure version file
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../cmake/YYCCVersion.hpp.in
|
${CMAKE_CURRENT_LIST_DIR}/yycc/version.hpp.in
|
||||||
${CMAKE_CURRENT_LIST_DIR}/YYCC/YYCCVersion.hpp
|
${CMAKE_CURRENT_LIST_DIR}/yycc/version.hpp
|
||||||
@ONLY
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,48 +11,68 @@ add_library(YYCCommonplace STATIC "")
|
|||||||
target_sources(YYCCommonplace
|
target_sources(YYCCommonplace
|
||||||
PRIVATE
|
PRIVATE
|
||||||
# Sources
|
# Sources
|
||||||
YYCC/COMHelper.cpp
|
yycc/string/reinterpret.cpp
|
||||||
YYCC/ArgParser.cpp
|
yycc/string/op.cpp
|
||||||
YYCC/ConfigManager.cpp
|
# YYCC/COMHelper.cpp
|
||||||
YYCC/ConsoleHelper.cpp
|
# YYCC/ArgParser.cpp
|
||||||
YYCC/DialogHelper.cpp
|
# YYCC/ConfigManager.cpp
|
||||||
YYCC/EncodingHelper.cpp
|
# YYCC/ConsoleHelper.cpp
|
||||||
YYCC/ExceptionHelper.cpp
|
# YYCC/DialogHelper.cpp
|
||||||
YYCC/StdPatch.cpp
|
# YYCC/EncodingHelper.cpp
|
||||||
YYCC/IOHelper.cpp
|
# YYCC/ExceptionHelper.cpp
|
||||||
YYCC/StringHelper.cpp
|
# YYCC/StdPatch.cpp
|
||||||
YYCC/WinFctHelper.cpp
|
# YYCC/IOHelper.cpp
|
||||||
# Natvis (only for MSVC)
|
# YYCC/StringHelper.cpp
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:YYCC.natvis>
|
# YYCC/WinFctHelper.cpp
|
||||||
|
# # Natvis (only for MSVC)
|
||||||
|
# $<$<CXX_COMPILER_ID:MSVC>:YYCC.natvis>
|
||||||
)
|
)
|
||||||
target_sources(YYCCommonplace
|
target_sources(YYCCommonplace
|
||||||
PUBLIC
|
PUBLIC
|
||||||
FILE_SET HEADERS
|
FILE_SET HEADERS
|
||||||
FILES
|
FILES
|
||||||
# Headers
|
# Headers
|
||||||
# Common headers
|
yycc.hpp
|
||||||
YYCC/Constraints.hpp
|
yycc/version.hpp
|
||||||
YYCC/COMHelper.hpp
|
yycc/prelude/core.hpp
|
||||||
YYCC/ArgParser.hpp
|
yycc/prelude/rust.hpp
|
||||||
YYCC/ConfigManager.hpp
|
yycc/macro/version_cmp.hpp
|
||||||
YYCC/ConsoleHelper.hpp
|
yycc/macro/os_detector.hpp
|
||||||
YYCC/DialogHelper.hpp
|
yycc/macro/class_copy_move.hpp
|
||||||
YYCC/EncodingHelper.hpp
|
yycc/string.hpp
|
||||||
YYCC/EnumHelper.hpp
|
yycc/string/reinterpret.hpp
|
||||||
YYCC/ExceptionHelper.hpp
|
yycc/string/op.hpp
|
||||||
YYCC/StdPatch.hpp
|
yycc/rust/primitive.hpp
|
||||||
YYCC/IOHelper.hpp
|
yycc/windows/unsafe_suppressor.hpp
|
||||||
YYCC/ParserHelper.hpp
|
yycc/windows/import_guard_head.hpp
|
||||||
YYCC/StringHelper.hpp
|
yycc/windows/import_guard_tail.hpp
|
||||||
YYCC/WinFctHelper.hpp
|
yycc/constraint.hpp
|
||||||
# Windows including guard pair
|
yycc/constraint/builder.hpp
|
||||||
YYCC/WinImportPrefix.hpp
|
|
||||||
YYCC/WinImportSuffix.hpp
|
# # Headers
|
||||||
# Internal
|
# # Common headers
|
||||||
YYCC/YYCCVersion.hpp
|
# YYCC/Constraints.hpp
|
||||||
YYCC/YYCCInternal.hpp
|
# YYCC/COMHelper.hpp
|
||||||
# Exposed
|
# YYCC/ArgParser.hpp
|
||||||
YYCCommonplace.hpp
|
# YYCC/ConfigManager.hpp
|
||||||
|
# YYCC/ConsoleHelper.hpp
|
||||||
|
# YYCC/DialogHelper.hpp
|
||||||
|
# YYCC/EncodingHelper.hpp
|
||||||
|
# YYCC/EnumHelper.hpp
|
||||||
|
# YYCC/ExceptionHelper.hpp
|
||||||
|
# YYCC/StdPatch.hpp
|
||||||
|
# YYCC/IOHelper.hpp
|
||||||
|
# YYCC/ParserHelper.hpp
|
||||||
|
# YYCC/StringHelper.hpp
|
||||||
|
# YYCC/WinFctHelper.hpp
|
||||||
|
# # Windows including guard pair
|
||||||
|
# YYCC/WinImportPrefix.hpp
|
||||||
|
# YYCC/WinImportSuffix.hpp
|
||||||
|
# # Internal
|
||||||
|
# YYCC/YYCCVersion.hpp
|
||||||
|
# YYCC/YYCCInternal.hpp
|
||||||
|
# # Exposed
|
||||||
|
# YYCCommonplace.hpp
|
||||||
)
|
)
|
||||||
# Setup header infomations
|
# Setup header infomations
|
||||||
target_include_directories(YYCCommonplace
|
target_include_directories(YYCCommonplace
|
||||||
|
16
src/yycc.hpp
Normal file
16
src/yycc.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Library Version and Comparison Macros
|
||||||
|
#include "yycc/version.hpp"
|
||||||
|
#include "yycc/macro/version_cmp.hpp"
|
||||||
|
|
||||||
|
// Operating System Identifier Macros
|
||||||
|
#include "yycc/macro/os_detector.hpp"
|
||||||
|
|
||||||
|
// Windows Shitty Behavior Disable Macros
|
||||||
|
#include "yycc/windows/unsafe_suppressor.hpp"
|
||||||
|
|
||||||
|
// Batch Class Move / Copy Function Macros
|
||||||
|
#include "yycc/macro/class_copy_move.hpp"
|
||||||
|
|
||||||
|
namespace yycc {}
|
0
src/yycc/binstore/kernel.hpp
Normal file
0
src/yycc/binstore/kernel.hpp
Normal file
0
src/yycc/clap/kernel.hpp
Normal file
0
src/yycc/clap/kernel.hpp
Normal file
78
src/yycc/constraint.hpp
Normal file
78
src/yycc/constraint.hpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "macro/class_copy_move.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/// @brief The namespace containing generic constraint concept used varied in other modules.
|
||||||
|
namespace yycc::constraint {
|
||||||
|
|
||||||
|
/// @brief Function prototype used in Constraint for checking whether given value is valid.
|
||||||
|
/// @details Analyze given value, and return true if value is legal, otherwise false.
|
||||||
|
template<typename T>
|
||||||
|
using FnCheck = std::function<bool(const T&)>;
|
||||||
|
/// @brief Function prototype used in Constraint for clamping given value into a valid value.
|
||||||
|
/// @details Analyze given value, return clamped value.
|
||||||
|
template<typename T>
|
||||||
|
using FnClamp = std::function<T(const T&)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The constraint applied to settings to limit its stored value.
|
||||||
|
* @tparam T The data type this constraint need to be processed with.
|
||||||
|
* @details
|
||||||
|
* Constraint class contains various features:
|
||||||
|
* \li Check: Check whether given value is in range.
|
||||||
|
* \li Clamp: Clamp given value into valid value.
|
||||||
|
* Every instances of Constraint can have some, or none of these features.
|
||||||
|
* So it is essential to check whether instance has corresponding features before using it.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
class Constraint {
|
||||||
|
public:
|
||||||
|
Constraint(FnCheck<T>&& fn_check, FnClamp<T>&& fn_clamp) :
|
||||||
|
fn_check(std::move(fn_check)), fn_clamp(std::move(fn_clamp)) {}
|
||||||
|
YYCC_DELETE_COPY(Constraint)
|
||||||
|
YYCC_DEFAULT_MOVE(Constraint)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform Check feature.
|
||||||
|
* @param[in] value The valid for checking.
|
||||||
|
* @return True if valid is okey, otherwise false.
|
||||||
|
* @exception std::logic_error Raised if this feature is not supported.
|
||||||
|
*/
|
||||||
|
bool check(const T& value) const {
|
||||||
|
if (!support_check()) {
|
||||||
|
throw std::logic_error("this Constraint do not support check operation");
|
||||||
|
} else {
|
||||||
|
return fn_check(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Perform Clamp feature.
|
||||||
|
* @param[in] value The valid for clamping.
|
||||||
|
* @return The result after clamping.
|
||||||
|
* @exception std::logic_error Raised if this feature is not supported.
|
||||||
|
*/
|
||||||
|
T clamp(const T& value) const {
|
||||||
|
if (!support_clamp()) {
|
||||||
|
throw std::logic_error("this Constraint do not support clamp operation");
|
||||||
|
} else {
|
||||||
|
return fn_clamp(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Check whether this Constraint support Check feature.
|
||||||
|
/// @return True if it support, otherwise false.
|
||||||
|
bool support_check() const noexcept { return this->fn_check != nullptr; }
|
||||||
|
/// @brief Check whether this Constraint support Clamp feature.
|
||||||
|
/// @return True if it support, otherwise false.
|
||||||
|
bool support_clamp() const noexcept { return this->fn_clamp != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief Pointer to Check feature function.
|
||||||
|
FnCheck<T> fn_check;
|
||||||
|
/// @brief Pointer to Clamp feature function.
|
||||||
|
FnClamp<T> fn_clamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace yycc::core::constraint
|
67
src/yycc/constraint/builder.hpp
Normal file
67
src/yycc/constraint/builder.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../constraint.hpp"
|
||||||
|
#include "../string.hpp"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
|
||||||
|
/// @brief The namespace containing convenient function building common used Constraint instance.
|
||||||
|
namespace yycc::constraint::builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Build Constraint for arithmetic values by minimum and maximum value range.
|
||||||
|
* @tparam T An arithmetic or enum type (except bool) of underlying stored value.
|
||||||
|
* @param[in] min_value The minimum value of range (inclusive).
|
||||||
|
* @param[in] max_value The maximum value of range (inclusive).
|
||||||
|
* @return The generated constraint instance which can be directly applied.
|
||||||
|
*/
|
||||||
|
template<typename T,
|
||||||
|
std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||||
|
Constraint<T> min_max_constraint(T min_value, T max_value) {
|
||||||
|
if (min_value > max_value)
|
||||||
|
throw std::invalid_argument("the max value must be equal or greater than min value");
|
||||||
|
|
||||||
|
auto fn_check = [min_value, max_value](const T& val) -> bool {
|
||||||
|
return (val <= max_value) && (val >= min_value);
|
||||||
|
};
|
||||||
|
auto fn_clamp = [min_value, max_value](const T& val) -> T {
|
||||||
|
return std::clamp(val, min_value, max_value);
|
||||||
|
};
|
||||||
|
return Constraint<T>(std::move(fn_check), std::move(fn_clamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get constraint for enum values by enumerating all possible values.
|
||||||
|
* @tparam T An enum type (except bool) of underlying stored value.
|
||||||
|
* @param[in] il An initializer list storing all possible values.
|
||||||
|
* @return The generated constraint instance which can be directly applied.
|
||||||
|
*/
|
||||||
|
template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
|
||||||
|
Constraint<T> enum_constraint(const std::initializer_list<T>& il) {
|
||||||
|
std::set<T> data(il);
|
||||||
|
|
||||||
|
auto fn_check = [data](const T& val) -> bool { return data.find(val) != data.end(); };
|
||||||
|
return Constraint<T>(std::move(fn_check), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get constraint for string values by enumerating all possible values.
|
||||||
|
* @param[in] il An initializer list storing all possible values.
|
||||||
|
* @return The generated constraint instance which can be directly applied.
|
||||||
|
* @remarks
|
||||||
|
* Caller must make sure that the string view passed in initializer list is valid until this Constraint life time gone.
|
||||||
|
* Becasue this generator will not copy your given string view into string.
|
||||||
|
*/
|
||||||
|
inline Constraint<NS_YYCC_STRING::u8string> GetStringEnumerationConstraint(
|
||||||
|
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il) {
|
||||||
|
std::set<NS_YYCC_STRING::u8string_view> data(il);
|
||||||
|
|
||||||
|
auto fn_check = [data](const NS_YYCC_STRING::u8string& val) -> bool {
|
||||||
|
return data.find(NS_YYCC_STRING::u8string_view(val)) != data.end();
|
||||||
|
};
|
||||||
|
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yycc::constraint::builder
|
||||||
|
|
||||||
|
#undef NS_YYCC_STRING
|
31
src/yycc/macro/class_copy_move.hpp
Normal file
31
src/yycc/macro/class_copy_move.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Explicitly remove copy (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DELETE_COPY(CLSNAME) \
|
||||||
|
CLSNAME(const CLSNAME&) = delete; \
|
||||||
|
CLSNAME& operator=(const CLSNAME&) = delete;
|
||||||
|
|
||||||
|
/// @brief Explicitly remove move (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DELETE_MOVE(CLSNAME) \
|
||||||
|
CLSNAME(CLSNAME&&) = delete; \
|
||||||
|
CLSNAME& operator=(CLSNAME&&) = delete;
|
||||||
|
|
||||||
|
/// @brief Explicitly remove (copy and move) (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DELETE_COPY_MOVE(CLSNAME) \
|
||||||
|
YYCC_DELETE_COPY(CLSNAME) \
|
||||||
|
YYCC_DELETE_MOVE(CLSNAME)
|
||||||
|
|
||||||
|
/// @brief Explicitly set default copy (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DEFAULT_COPY(CLSNAME) \
|
||||||
|
CLSNAME(const CLSNAME&) = default; \
|
||||||
|
CLSNAME& operator=(const CLSNAME&) = default;
|
||||||
|
|
||||||
|
/// @brief Explicitly set default move (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DEFAULT_MOVE(CLSNAME) \
|
||||||
|
CLSNAME(CLSNAME&&) = default; \
|
||||||
|
CLSNAME& operator=(CLSNAME&&) = default;
|
||||||
|
|
||||||
|
/// @brief Explicitly set default (copy and move) (\c constructor and \c operator\=) for given class.
|
||||||
|
#define YYCC_DEFAULT_COPY_MOVE(CLSNAME) \
|
||||||
|
YYCC_DEFAULT_COPY(CLSNAME) \
|
||||||
|
YYCC_DEFAULT_MOVE(CLSNAME)
|
11
src/yycc/macro/os_detector.hpp
Normal file
11
src/yycc/macro/os_detector.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Define operating system macros
|
||||||
|
#define YYCC_OS_WINDOWS 2
|
||||||
|
#define YYCC_OS_LINUX 3
|
||||||
|
// Check current operating system.
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define YYCC_OS YYCC_OS_WINDOWS
|
||||||
|
#else
|
||||||
|
#define YYCC_OS YYCC_OS_LINUX
|
||||||
|
#endif
|
26
src/yycc/macro/version_cmp.hpp
Normal file
26
src/yycc/macro/version_cmp.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Return true if left version number is equal to right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3) ((av1) == (bv1) && (av2) == (bv2) && (av3) == (bv3))
|
||||||
|
/// @brief Return true if left version number is not equal to right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_NE(av1, av2, av3, bv1, bv2, bv3) (!YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
|
||||||
|
/// @brief Return true if left version number is greater than right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_G(av1, av2, av3, bv1, bv2, bv3) ( \
|
||||||
|
((av1) > (bv1)) || \
|
||||||
|
((av1) == (bv1) && (av2) > (bv2)) || \
|
||||||
|
((av1) == (bv1) && (av2) == (bv2) && (av3) > (bv3)) \
|
||||||
|
)
|
||||||
|
/// @brief Return true if left version number is greater than or equal to right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_GE(av1, av2, av3, bv1, bv2, bv3) (YYCC_VERCMP_G(av1, av2, av3, bv1, bv2, bv3) || YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
|
||||||
|
/// @brief Return true if left version number is not lower than right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_NL(av1, av2, av3, bv1, bv2, bv3) YYCC_VERCMP_GE(av1, av2, av3, bv1, bv2, bv3)
|
||||||
|
/// @brief Return true if left version number is lower than right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_L(av1, av2, av3, bv1, bv2, bv3) ( \
|
||||||
|
((av1) < (bv1)) || \
|
||||||
|
((av1) == (bv1) && (av2) < (bv2)) || \
|
||||||
|
((av1) == (bv1) && (av2) == (bv2) && (av3) < (bv3)) \
|
||||||
|
)
|
||||||
|
/// @brief Return true if left version number is lower than or equal to right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_LE(av1, av2, av3, bv1, bv2, bv3) (YYCC_VERCMP_L(av1, av2, av3, bv1, bv2, bv3) || YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
|
||||||
|
/// @brief Return true if left version number is not greater than right version number, otherwise false.
|
||||||
|
#define YYCC_VERCMP_NG(av1, av2, av3, bv1, bv2, bv3) YYCC_VERCMP_LE(av1, av2, av3, bv1, bv2, bv3)
|
0
src/yycc/patch/container.hpp
Normal file
0
src/yycc/patch/container.hpp
Normal file
0
src/yycc/patch/path.hpp
Normal file
0
src/yycc/patch/path.hpp
Normal file
0
src/yycc/patch/string.hpp
Normal file
0
src/yycc/patch/string.hpp
Normal file
18
src/yycc/prelude/core.hpp
Normal file
18
src/yycc/prelude/core.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Prelude section
|
||||||
|
#include "../string.hpp"
|
||||||
|
namespace yycc::prelude {
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
|
||||||
|
using u8char = NS_YYCC_STRING::u8char;
|
||||||
|
using u8string = NS_YYCC_STRING::u8string;
|
||||||
|
using u8string_view = NS_YYCC_STRING::u8string_view;
|
||||||
|
|
||||||
|
#undef NS_YYCC_STRING
|
||||||
|
|
||||||
|
} // namespace yycc::prelude
|
||||||
|
|
||||||
|
// Expose all members
|
||||||
|
using namespace yycc::prelude;
|
41
src/yycc/prelude/rust.hpp
Normal file
41
src/yycc/prelude/rust.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Include YYCC prelude first
|
||||||
|
#include "core.hpp"
|
||||||
|
|
||||||
|
// Rust prelude section
|
||||||
|
#include "../rust/primitive.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace yycc::prelude::rust {
|
||||||
|
// Include primitive types
|
||||||
|
|
||||||
|
#define NS_RUST_PRIMITIVE ::yycc::rust::primitive
|
||||||
|
|
||||||
|
using i8 = NS_RUST_PRIMITIVE::i8;
|
||||||
|
using i16 = NS_RUST_PRIMITIVE::i16;
|
||||||
|
using i32 = NS_RUST_PRIMITIVE::i32;
|
||||||
|
using i64 = NS_RUST_PRIMITIVE::i64;
|
||||||
|
using u8 = NS_RUST_PRIMITIVE::u8;
|
||||||
|
using u16 = NS_RUST_PRIMITIVE::u16;
|
||||||
|
using u32 = NS_RUST_PRIMITIVE::u32;
|
||||||
|
using u64 = NS_RUST_PRIMITIVE::u64;
|
||||||
|
|
||||||
|
using isize = NS_RUST_PRIMITIVE::isize;
|
||||||
|
using usize = NS_RUST_PRIMITIVE::usize;
|
||||||
|
|
||||||
|
using f32 = NS_RUST_PRIMITIVE::f32;
|
||||||
|
using f64 = NS_RUST_PRIMITIVE::f64;
|
||||||
|
|
||||||
|
using str = NS_RUST_PRIMITIVE::str;
|
||||||
|
|
||||||
|
#undef NS_RUST_PRIMITIVE
|
||||||
|
|
||||||
|
// Other types
|
||||||
|
using String = ::yycc::string::u8string;
|
||||||
|
template<typename T>
|
||||||
|
using Vec = std::vector<T>;
|
||||||
|
} // namespace yycc::prelude::rust
|
||||||
|
|
||||||
|
// Expose all members
|
||||||
|
using namespace yycc::prelude::rust;
|
0
src/yycc/rust/parse.hpp
Normal file
0
src/yycc/rust/parse.hpp
Normal file
28
src/yycc/rust/primitive.hpp
Normal file
28
src/yycc/rust/primitive.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cstddef>
|
||||||
|
#include "../string.hpp"
|
||||||
|
|
||||||
|
namespace yycc::rust::primitive {
|
||||||
|
|
||||||
|
// `bool` is keyword so should not declare it anymore.
|
||||||
|
// `char` is keyword so should not declare it anymore.
|
||||||
|
|
||||||
|
using i8 = std::int8_t;
|
||||||
|
using i16 = std::int16_t;
|
||||||
|
using i32 = std::int32_t;
|
||||||
|
using i64 = std::int64_t;
|
||||||
|
using u8 = std::uint8_t;
|
||||||
|
using u16 = std::uint16_t;
|
||||||
|
using u32 = std::uint32_t;
|
||||||
|
using u64 = std::uint64_t;
|
||||||
|
|
||||||
|
using isize = std::ptrdiff_t;
|
||||||
|
using usize = std::size_t;
|
||||||
|
|
||||||
|
using f32 = float;
|
||||||
|
using f64 = double;
|
||||||
|
|
||||||
|
using str = ::yycc::string::u8string_view;
|
||||||
|
}
|
||||||
|
|
41
src/yycc/string.hpp
Normal file
41
src/yycc/string.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Define the UTF8 char type we used.
|
||||||
|
// And do a polyfill if no embedded char8_t type.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace yycc::string {
|
||||||
|
/**
|
||||||
|
\typedef u8char_t
|
||||||
|
\brief YYCC UTF8 char type.
|
||||||
|
\details
|
||||||
|
This char type is an alias to \c char8_t if your current C++ standard support it.
|
||||||
|
Otherwise it is defined as <TT>unsigned char</TT> as C++ 20 stdandard does.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
\typedef u8string
|
||||||
|
\brief YYCC UTF8 string container type.
|
||||||
|
\details
|
||||||
|
This type is defined as \c std::basic_string<yycc_char8_t>.
|
||||||
|
It is equal to \c std::u8string if your current C++ standard support it.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
\typedef u8string_view
|
||||||
|
\brief YYCC UTF8 string view type.
|
||||||
|
\details
|
||||||
|
This type is defined as \c std::basic_string_view<yycc_char8_t>.
|
||||||
|
It is equal to \c std::u8string_view if your current C++ standard support it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__cpp_char8_t)
|
||||||
|
using u8char = char8_t;
|
||||||
|
using u8string = std::u8string;
|
||||||
|
using u8string_view = std::u8string_view;
|
||||||
|
#else
|
||||||
|
using u8char = unsigned char;
|
||||||
|
using u8string = std::basic_string<u8char>;
|
||||||
|
using u8string_view = std::basic_string_view<u8char>;
|
||||||
|
#endif
|
||||||
|
} // namespace yycc::string
|
226
src/yycc/string/op.cpp
Normal file
226
src/yycc/string/op.cpp
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#include "op.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include "reinterpret.hpp"
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
||||||
|
|
||||||
|
namespace yycc::string::op {
|
||||||
|
|
||||||
|
#pragma region Printf VPrintf
|
||||||
|
|
||||||
|
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, format);
|
||||||
|
bool ret = vprintf(strl, format, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr) {
|
||||||
|
va_list args1;
|
||||||
|
va_copy(args1, argptr);
|
||||||
|
va_list args2;
|
||||||
|
va_copy(args2, argptr);
|
||||||
|
|
||||||
|
// the return value is desired char count without NULL terminal.
|
||||||
|
// minus number means error
|
||||||
|
int count = std::vsnprintf(
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
NS_YYCC_STRING_REINTERPRET::as_ordinary(format),
|
||||||
|
args1
|
||||||
|
);
|
||||||
|
if (count < 0) {
|
||||||
|
// invalid length returned by vsnprintf.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
va_end(args1);
|
||||||
|
|
||||||
|
// resize std::string to desired count.
|
||||||
|
// and pass its length + 1 to std::vsnprintf,
|
||||||
|
// because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
|
||||||
|
// however std::vsnprintf already have a trailing NULL, so we plus 1 for it.
|
||||||
|
strl.resize(count);
|
||||||
|
int write_result = std::vsnprintf(
|
||||||
|
NS_YYCC_STRING_REINTERPRET::as_ordinary(strl.data()),
|
||||||
|
strl.size() + 1,
|
||||||
|
NS_YYCC_STRING_REINTERPRET::as_ordinary(format),
|
||||||
|
args2
|
||||||
|
);
|
||||||
|
va_end(args2);
|
||||||
|
|
||||||
|
if (write_result < 0 || write_result > count) {
|
||||||
|
// invalid write result in vsnprintf.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...) {
|
||||||
|
NS_YYCC_STRING::u8string ret;
|
||||||
|
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, format);
|
||||||
|
vprintf(ret, format, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr) {
|
||||||
|
NS_YYCC_STRING::u8string ret;
|
||||||
|
|
||||||
|
va_list argcpy;
|
||||||
|
va_copy(argcpy, argptr);
|
||||||
|
vprintf(ret, format, argcpy);
|
||||||
|
va_end(argcpy);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Replace
|
||||||
|
|
||||||
|
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
|
||||||
|
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
|
||||||
|
|
||||||
|
// check requirements
|
||||||
|
// from string should not be empty
|
||||||
|
NS_YYCC_STRING::u8string from_strl(_from_strl);
|
||||||
|
NS_YYCC_STRING::u8string to_strl(_to_strl);
|
||||||
|
if (from_strl.empty()) return;
|
||||||
|
|
||||||
|
// start replace one by one
|
||||||
|
size_t start_pos = 0;
|
||||||
|
while ((start_pos = strl.find(from_strl, start_pos)) != NS_YYCC_STRING::u8string::npos) {
|
||||||
|
strl.replace(start_pos, from_strl.size(), to_strl);
|
||||||
|
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
|
||||||
|
// prepare result
|
||||||
|
NS_YYCC_STRING::u8string strl(_strl);
|
||||||
|
replace(strl, _from_strl, _to_strl);
|
||||||
|
// return value
|
||||||
|
return strl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Join
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& decilmer) {
|
||||||
|
NS_YYCC_STRING::u8string ret;
|
||||||
|
bool is_first = true;
|
||||||
|
NS_YYCC_STRING::u8string_view element;
|
||||||
|
|
||||||
|
// fetch element
|
||||||
|
while (fct_data(element)) {
|
||||||
|
// insert decilmer
|
||||||
|
if (is_first) is_first = false;
|
||||||
|
else {
|
||||||
|
// append decilmer.
|
||||||
|
ret.append(decilmer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert element if it is not empty
|
||||||
|
if (!element.empty())
|
||||||
|
ret.append(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Upper Lower
|
||||||
|
|
||||||
|
template<bool BIsToLower>
|
||||||
|
static void generic_lower_upper(NS_YYCC_STRING::u8string& strl) {
|
||||||
|
// References:
|
||||||
|
// https://en.cppreference.com/w/cpp/algorithm/transform
|
||||||
|
// https://en.cppreference.com/w/cpp/string/byte/tolower
|
||||||
|
std::transform(
|
||||||
|
strl.cbegin(), strl.cend(), strl.begin(),
|
||||||
|
[](unsigned char c) -> char {
|
||||||
|
if constexpr (BIsToLower) return std::tolower(c);
|
||||||
|
else return std::toupper(c);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lower(NS_YYCC_STRING::u8string& strl) {
|
||||||
|
generic_lower_upper<true>(strl);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string lower(const NS_YYCC_STRING::u8string_view& strl) {
|
||||||
|
NS_YYCC_STRING::u8string ret(strl);
|
||||||
|
lower(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void upper(NS_YYCC_STRING::u8string& strl) {
|
||||||
|
generic_lower_upper<false>(strl);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_STRING::u8string upper(const NS_YYCC_STRING::u8string_view& strl) {
|
||||||
|
// same as Lower, just replace char transform function.
|
||||||
|
NS_YYCC_STRING::u8string ret(strl);
|
||||||
|
upper(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Split
|
||||||
|
|
||||||
|
std::vector<NS_YYCC_STRING::u8string> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer) {
|
||||||
|
// call split view
|
||||||
|
auto view_result = split_view(strl, _decilmer);
|
||||||
|
|
||||||
|
// copy string view result to string
|
||||||
|
std::vector<NS_YYCC_STRING::u8string> elems;
|
||||||
|
elems.reserve(view_result.size());
|
||||||
|
for (const auto& strl_view : view_result) {
|
||||||
|
elems.emplace_back(NS_YYCC_STRING::u8string(strl_view));
|
||||||
|
}
|
||||||
|
// return copied result
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<NS_YYCC_STRING::u8string_view> split_view(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer) {
|
||||||
|
// Reference:
|
||||||
|
// https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
|
||||||
|
|
||||||
|
// prepare return value
|
||||||
|
std::vector<NS_YYCC_STRING::u8string_view> elems;
|
||||||
|
|
||||||
|
// if string need to be splitted is empty, return original string (empty string).
|
||||||
|
// if decilmer is empty, return original string.
|
||||||
|
NS_YYCC_STRING::u8string decilmer(_decilmer);
|
||||||
|
if (strl.empty() || decilmer.empty()) {
|
||||||
|
elems.emplace_back(strl);
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start spliting
|
||||||
|
std::size_t previous = 0, current;
|
||||||
|
while ((current = strl.find(decilmer.c_str(), previous)) != NS_YYCC_STRING::u8string::npos) {
|
||||||
|
elems.emplace_back(strl.substr(previous, current - previous));
|
||||||
|
previous = current + decilmer.size();
|
||||||
|
}
|
||||||
|
// try insert last part but prevent possible out of range exception
|
||||||
|
if (previous <= strl.size()) {
|
||||||
|
elems.emplace_back(strl.substr(previous));
|
||||||
|
}
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
}
|
156
src/yycc/string/op.hpp
Normal file
156
src/yycc/string/op.hpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include "../string.hpp"
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
|
||||||
|
namespace yycc::string::op {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform a string formatting operation.
|
||||||
|
* @param[out] strl
|
||||||
|
* The string container receiving the result.
|
||||||
|
* There is no guarantee that the content is not modified when function failed.
|
||||||
|
* @param[in] format The format string.
|
||||||
|
* @param[in] ... Argument list of format string.
|
||||||
|
* @return True if success, otherwise false.
|
||||||
|
*/
|
||||||
|
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...);
|
||||||
|
/**
|
||||||
|
* @brief Perform a string formatting operation.
|
||||||
|
* @param[out] strl
|
||||||
|
* The string container receiving the result.
|
||||||
|
* There is no guarantee that the content is not modified when function failed.
|
||||||
|
* @param[in] format The format string.
|
||||||
|
* @param[in] argptr Argument list of format string.
|
||||||
|
* @return True if success, otherwise false.
|
||||||
|
*/
|
||||||
|
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr);
|
||||||
|
/**
|
||||||
|
* @brief Perform a string formatting operation.
|
||||||
|
* @param[in] format The format string.
|
||||||
|
* @param[in] ... Argument list of format string.
|
||||||
|
* @return The formatting result. Empty string if error happened.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...);
|
||||||
|
/**
|
||||||
|
* @brief Perform a string formatting operation.
|
||||||
|
* @param[in] format The format string.
|
||||||
|
* @param[in] argptr Argument list of format string.
|
||||||
|
* @return The formatting result. Empty string if error happened.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modify given string with all occurrences of substring \e old replaced by \e new.
|
||||||
|
* @param[in,out] strl The string for replacing
|
||||||
|
* @param[in] _from_strl The \e old string.
|
||||||
|
* @param[in] _to_strl The \e new string.
|
||||||
|
*/
|
||||||
|
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
|
||||||
|
/**
|
||||||
|
* @brief Return a copy with all occurrences of substring \e old replaced by \e new.
|
||||||
|
* @param[in] _strl The string for replacing
|
||||||
|
* @param[in] _from_strl The \e old string.
|
||||||
|
* @param[in] _to_strl The \e new string.
|
||||||
|
* @return The result of replacement.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The data provider of general join function.
|
||||||
|
* @details
|
||||||
|
* For programmer using lambda to implement this function pointer:
|
||||||
|
* \li During calling, implementation should assign the reference of string view passed in argument
|
||||||
|
* to the string which need to be joined.
|
||||||
|
* \li Function return true to continue joining. otherwise return false to stop joining.
|
||||||
|
* The argument content assigned in the calling returning false is not included in join process.
|
||||||
|
*/
|
||||||
|
using JoinDataProvider = std::function<bool(NS_YYCC_STRING::u8string_view&)>;
|
||||||
|
/**
|
||||||
|
* @brief Universal join function.
|
||||||
|
* @details
|
||||||
|
* This function use function pointer as a general data provider interface,
|
||||||
|
* so this function suit for all types container.
|
||||||
|
* You can use this universal join function for any custom container by
|
||||||
|
* using C++ lambda syntax to create a code block adapted to this function pointer.
|
||||||
|
* @param[in] fct_data The function pointer in JoinDataProvider type prividing the data to be joined.
|
||||||
|
* @param[in] decilmer The decilmer used for joining.
|
||||||
|
* @return The result string of joining.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& decilmer);
|
||||||
|
/**
|
||||||
|
* @brief Specialized join function for standard library container.
|
||||||
|
* @tparam InputIt
|
||||||
|
* Must meet the requirements of LegacyInputIterator.
|
||||||
|
* It also can be dereferenced and then implicitly converted to NS_YYCC_STRING::u8string_view.
|
||||||
|
* @param[in] first The beginning of the range of elements to join.
|
||||||
|
* @param[in] last The terminal of the range of elements to join (exclusive).
|
||||||
|
* @param[in] decilmer The decilmer used for joining.
|
||||||
|
* @return The result string of joining.
|
||||||
|
*/
|
||||||
|
template<class InputIt>
|
||||||
|
NS_YYCC_STRING::u8string join(InputIt first, InputIt last, const NS_YYCC_STRING::u8string_view& decilmer) {
|
||||||
|
return join([&first, &last](NS_YYCC_STRING::u8string_view& view) -> bool {
|
||||||
|
// if we reach tail, return false to stop join process
|
||||||
|
if (first == last) return false;
|
||||||
|
// otherwise fetch data, inc iterator and return.
|
||||||
|
view = *first;
|
||||||
|
++first;
|
||||||
|
return true;
|
||||||
|
}, decilmer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert given string to lowercase.
|
||||||
|
* @param[in,out] strl The string to be lowercase.
|
||||||
|
*/
|
||||||
|
void lower(NS_YYCC_STRING::u8string& strl);
|
||||||
|
/**
|
||||||
|
* @brief Return a copy of the string converted to lowercase.
|
||||||
|
* @param[in] strl The string to be lowercase.
|
||||||
|
* @return The copy of the string converted to lowercase.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string lower(const NS_YYCC_STRING::u8string_view& strl);
|
||||||
|
/**
|
||||||
|
* @brief Convert given string to uppercase.
|
||||||
|
* @param[in,out] strl The string to be uppercase.
|
||||||
|
*/
|
||||||
|
void upper(NS_YYCC_STRING::u8string& strl);
|
||||||
|
/**
|
||||||
|
* @brief Return a copy of the string converted to uppercase.
|
||||||
|
* @param[in] strl The string to be uppercase.
|
||||||
|
* @return The copy of the string converted to uppercase.
|
||||||
|
*/
|
||||||
|
NS_YYCC_STRING::u8string upper(const NS_YYCC_STRING::u8string_view& strl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Split given string with specified decilmer.
|
||||||
|
* @param[in] strl The string need to be splitting.
|
||||||
|
* @param[in] _decilmer The decilmer for splitting.
|
||||||
|
* @return
|
||||||
|
* The split result.
|
||||||
|
* \par
|
||||||
|
* If given string or decilmer are empty,
|
||||||
|
* the result container will only contain 1 entry which is equal to given string.
|
||||||
|
*/
|
||||||
|
std::vector<NS_YYCC_STRING::u8string> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer);
|
||||||
|
/**
|
||||||
|
* @brief Split given string with specified decilmer as string view.
|
||||||
|
* @param[in] strl The string need to be splitting.
|
||||||
|
* @param[in] _decilmer The decilmer for splitting.
|
||||||
|
* @return
|
||||||
|
* The split result with string view format.
|
||||||
|
* This will not produce any copy of original string.
|
||||||
|
* \par
|
||||||
|
* If given string or decilmer are empty,
|
||||||
|
* the result container will only contain 1 entry which is equal to given string.
|
||||||
|
* @see Split(const NS_YYCC_STRING::u8string_view&, const NS_YYCC_STRING::u8char*)
|
||||||
|
*/
|
||||||
|
std::vector<NS_YYCC_STRING::u8string_view> split_view(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef NS_YYCC_STRING
|
33
src/yycc/string/reinterpret.cpp
Normal file
33
src/yycc/string/reinterpret.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "reinterpret.hpp"
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
|
||||||
|
namespace yycc::string::reinterpret {
|
||||||
|
|
||||||
|
const NS_YYCC_STRING::u8char* as_utf8(const char* src) {
|
||||||
|
return reinterpret_cast<const NS_YYCC_STRING::u8char*>(src);
|
||||||
|
}
|
||||||
|
NS_YYCC_STRING::u8char* as_utf8(char* src) {
|
||||||
|
return reinterpret_cast<NS_YYCC_STRING::u8char*>(src);
|
||||||
|
}
|
||||||
|
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src) {
|
||||||
|
return NS_YYCC_STRING::u8string(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
|
||||||
|
}
|
||||||
|
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src) {
|
||||||
|
return NS_YYCC_STRING::u8string_view(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* as_ordinary(const NS_YYCC_STRING::u8char* src) {
|
||||||
|
return reinterpret_cast<const char*>(src);
|
||||||
|
}
|
||||||
|
char* as_ordinary(NS_YYCC_STRING::u8char* src) {
|
||||||
|
return reinterpret_cast<char*>(src);
|
||||||
|
}
|
||||||
|
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src) {
|
||||||
|
return std::string(reinterpret_cast<const char*>(src.data()), src.size());
|
||||||
|
}
|
||||||
|
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src) {
|
||||||
|
return std::string_view(reinterpret_cast<const char*>(src.data()), src.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/yycc/string/reinterpret.hpp
Normal file
24
src/yycc/string/reinterpret.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../string.hpp"
|
||||||
|
|
||||||
|
#define NS_YYCC_STRING ::yycc::string
|
||||||
|
|
||||||
|
namespace yycc::string::reinterpret {
|
||||||
|
|
||||||
|
#define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8.
|
||||||
|
#define YYCC_U8(strl) (reinterpret_cast<const ::yycc::string::u8char*>(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding.
|
||||||
|
#define YYCC_U8_CHAR(chr) (static_cast<::yycc::string::u8char>(chr)) ///< The macro for casting ordinary char type into YYCC UTF8 char type.
|
||||||
|
|
||||||
|
const NS_YYCC_STRING::u8char* as_utf8(const char* src);
|
||||||
|
NS_YYCC_STRING::u8char* as_utf8(char* src);
|
||||||
|
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src);
|
||||||
|
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src);
|
||||||
|
|
||||||
|
const char* as_ordinary(const NS_YYCC_STRING::u8char* src);
|
||||||
|
char* as_ordinary(NS_YYCC_STRING::u8char* src);
|
||||||
|
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src);
|
||||||
|
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef NS_YYCC_STRING
|
5
src/yycc/version.hpp
Normal file
5
src/yycc/version.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define YYCC_VER_MAJOR 2
|
||||||
|
#define YYCC_VER_MINOR 0
|
||||||
|
#define YYCC_VER_PATCH 0
|
0
src/yycc/windows/com.cpp
Normal file
0
src/yycc/windows/com.cpp
Normal file
0
src/yycc/windows/com.hpp
Normal file
0
src/yycc/windows/com.hpp
Normal file
0
src/yycc/windows/dialog.cpp
Normal file
0
src/yycc/windows/dialog.cpp
Normal file
0
src/yycc/windows/dialog.hpp
Normal file
0
src/yycc/windows/dialog.hpp
Normal file
19
src/yycc/windows/import_guard_head.hpp
Normal file
19
src/yycc/windows/import_guard_head.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||||
|
// Because this header is the part of wrapper, not a real header.
|
||||||
|
// #pragma once
|
||||||
|
|
||||||
|
#include "../macro/os_detector.hpp"
|
||||||
|
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
// Define 2 macros to disallow Windows generate MIN and MAX macros
|
||||||
|
// which cause std::min and std::max can not function as normal.
|
||||||
|
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NOMINMAX)
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
23
src/yycc/windows/import_guard_tail.hpp
Normal file
23
src/yycc/windows/import_guard_tail.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||||
|
// Because this header is the part of wrapper, not a real header.
|
||||||
|
// #pragma once
|
||||||
|
|
||||||
|
#include "../macro/os_detector.hpp"
|
||||||
|
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
// Windows also will generate following macros
|
||||||
|
// which may cause the function sign is different in Windows and other platforms.
|
||||||
|
// So we simply remove them.
|
||||||
|
// Because #undef will not throw error if there are no matched macro,
|
||||||
|
// so we simply #undef them directly.
|
||||||
|
#undef GetObject
|
||||||
|
#undef GetClassName
|
||||||
|
#undef LoadImage
|
||||||
|
#undef GetTempPath
|
||||||
|
#undef GetModuleFileName
|
||||||
|
#undef CopyFile
|
||||||
|
#undef MoveFile
|
||||||
|
#undef DeleteFile
|
||||||
|
|
||||||
|
#endif
|
16
src/yycc/windows/unsafe_suppressor.hpp
Normal file
16
src/yycc/windows/unsafe_suppressor.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../macro/os_detector.hpp"
|
||||||
|
|
||||||
|
// If we are in Windows,
|
||||||
|
// we need add 2 macros to disable Windows shitty warnings and errors of
|
||||||
|
// depracted functions and not secure functions.
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
#if !defined(_CRT_NONSTDC_NO_DEPRECATE)
|
||||||
|
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -4,15 +4,22 @@ add_executable(YYCCTestbench "")
|
|||||||
target_sources(YYCCTestbench
|
target_sources(YYCCTestbench
|
||||||
PRIVATE
|
PRIVATE
|
||||||
main.cpp
|
main.cpp
|
||||||
|
yycc/constraint.cpp
|
||||||
|
yycc/constraint/builder.cpp
|
||||||
|
yycc/string.cpp
|
||||||
|
yycc/string/op.cpp
|
||||||
|
yycc/string/reinterpret.cpp
|
||||||
)
|
)
|
||||||
# Add YYCC as its library
|
# Setup headers
|
||||||
target_include_directories(YYCCTestbench
|
target_include_directories(YYCCTestbench
|
||||||
PRIVATE
|
PUBLIC
|
||||||
YYCCommonplace
|
"${CMAKE_CURRENT_LIST_DIR}"
|
||||||
)
|
)
|
||||||
|
# Setup libraries
|
||||||
target_link_libraries(YYCCTestbench
|
target_link_libraries(YYCCTestbench
|
||||||
PRIVATE
|
PRIVATE
|
||||||
YYCCommonplace
|
YYCCommonplace
|
||||||
|
GTest::gtest_main
|
||||||
)
|
)
|
||||||
# Setup C++ standard
|
# Setup C++ standard
|
||||||
target_compile_features(YYCCTestbench PUBLIC cxx_std_17)
|
target_compile_features(YYCCTestbench PUBLIC cxx_std_17)
|
||||||
@ -29,8 +36,6 @@ PRIVATE
|
|||||||
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install testbench only on Release mode
|
# Discover all test
|
||||||
install(TARGETS YYCCTestbench
|
include(GoogleTest)
|
||||||
CONFIGURATIONS Release RelWithDebInfo MinSizeRel
|
gtest_discover_tests(YYCCTestbench)
|
||||||
RUNTIME DESTINATION ${YYCC_INSTALL_BIN_PATH}
|
|
||||||
)
|
|
||||||
|
@ -1,735 +1,6 @@
|
|||||||
#include <YYCCommonplace.hpp>
|
#include <gtest/gtest.h>
|
||||||
#include <cstdio>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace Console = YYCC::ConsoleHelper;
|
|
||||||
|
|
||||||
namespace YYCCTestbench {
|
|
||||||
|
|
||||||
#pragma region Unicode Test Data
|
|
||||||
|
|
||||||
// UNICODE Test Strings
|
|
||||||
// Ref: https://stackoverflow.com/questions/478201/how-to-test-an-application-for-correct-encoding-e-g-utf-8
|
|
||||||
#define TEST_UNICODE_STR_JAPAN "\u30E6\u30FC\u30B6\u30FC\u5225\u30B5\u30A4\u30C8"
|
|
||||||
#define TEST_UNICODE_STR_CHINA "\u7B80\u4F53\u4E2D\u6587"
|
|
||||||
#define TEST_UNICODE_STR_KOREA "\uD06C\uB85C\uC2A4 \uD50C\uB7AB\uD3FC\uC73C\uB85C"
|
|
||||||
#define TEST_UNICODE_STR_ISRAEL "\u05DE\u05D3\u05D5\u05E8\u05D9\u05DD \u05DE\u05D1\u05D5\u05E7\u05E9\u05D9\u05DD"
|
|
||||||
#define TEST_UNICODE_STR_EGYPT "\u0623\u0641\u0636\u0644 \u0627\u0644\u0628\u062D\u0648\u062B"
|
|
||||||
#define TEST_UNICODE_STR_GREECE "\u03A3\u1F72 \u03B3\u03BD\u03C9\u03C1\u03AF\u03B6\u03C9 \u1F00\u03C0\u1F78"
|
|
||||||
#define TEST_UNICODE_STR_RUSSIA "\u0414\u0435\u0441\u044F\u0442\u0443\u044E \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E"
|
|
||||||
#define TEST_UNICODE_STR_THAILAND "\u0E41\u0E1C\u0E48\u0E19\u0E14\u0E34\u0E19\u0E2E\u0E31\u0E48\u0E19\u0E40\u0E2A\u0E37\u0E48\u0E2D\u0E21\u0E42\u0E17\u0E23\u0E21\u0E41\u0E2A\u0E19\u0E2A\u0E31\u0E07\u0E40\u0E27\u0E0A"
|
|
||||||
#define TEST_UNICODE_STR_FRANCE "fran\u00E7ais langue \u00E9trang\u00E8re"
|
|
||||||
#define TEST_UNICODE_STR_SPAIN "ma\u00F1ana ol\u00E9"
|
|
||||||
#define TEST_UNICODE_STR_MATHMATICS "\u222E E\u22C5da = Q, n \u2192 \u221E, \u2211 f(i) = \u220F g(i)"
|
|
||||||
#define TEST_UNICODE_STR_EMOJI "\U0001F363 \u2716 \U0001F37A" // sushi x beer mug
|
|
||||||
|
|
||||||
#define CONCAT(prefix, strl) prefix ## strl
|
|
||||||
#define CPP_U8_LITERAL(strl) YYCC_U8(strl)
|
|
||||||
#define CPP_U16_LITERAL(strl) CONCAT(u, strl)
|
|
||||||
#define CPP_U32_LITERAL(strl) CONCAT(U, strl)
|
|
||||||
#define CPP_WSTR_LITERAL(strl) CONCAT(L, strl)
|
|
||||||
|
|
||||||
static std::vector<YYCC::yycc_u8string> c_UTF8TestStrTable {
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_JAPAN),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_EGYPT),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_GREECE),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_THAILAND),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_FRANCE),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_SPAIN),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
|
||||||
CPP_U8_LITERAL(TEST_UNICODE_STR_EMOJI),
|
|
||||||
};
|
|
||||||
static std::vector<std::wstring> c_WStrTestStrTable {
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_JAPAN),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_CHINA),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_KOREA),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_EGYPT),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_GREECE),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_THAILAND),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_FRANCE),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_SPAIN),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
|
||||||
CPP_WSTR_LITERAL(TEST_UNICODE_STR_EMOJI),
|
|
||||||
};
|
|
||||||
static std::vector<std::u16string> c_UTF16TestStrTable {
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_JAPAN),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_CHINA),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_KOREA),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_EGYPT),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_GREECE),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_THAILAND),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_FRANCE),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_SPAIN),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
|
||||||
CPP_U16_LITERAL(TEST_UNICODE_STR_EMOJI),
|
|
||||||
};
|
|
||||||
static std::vector<std::u32string> c_UTF32TestStrTable {
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_JAPAN),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_CHINA),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_KOREA),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_EGYPT),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_GREECE),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_THAILAND),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_FRANCE),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_SPAIN),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
|
||||||
CPP_U32_LITERAL(TEST_UNICODE_STR_EMOJI),
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef CPP_WSTR_LITERAL
|
|
||||||
#undef CPP_U32_LITERAL
|
|
||||||
#undef CPP_U16_LITERAL
|
|
||||||
#undef CPP_U8_LITERAL
|
|
||||||
#undef CONCAT
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
static void Assert(bool condition, const YYCC::yycc_char8_t* description) {
|
|
||||||
if (condition) {
|
|
||||||
Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_GREEN("OK: %s")), description);
|
|
||||||
} else {
|
|
||||||
Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("Failed: %s\n")), description);
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ConsoleTestbench() {
|
|
||||||
// Color Test
|
|
||||||
Console::EnableColorfulConsole();
|
|
||||||
Console::WriteLine(YYCC_U8("Color Test:"));
|
|
||||||
|
|
||||||
#define TEST_MACRO(col) Console::WriteLine(YYCC_U8("\t" YYCC_COLOR_ ## col ("\u2588\u2588") YYCC_COLOR_LIGHT_ ## col("\u2588\u2588") " " #col " / LIGHT " #col ));
|
|
||||||
// U+2588 is full block
|
|
||||||
|
|
||||||
TEST_MACRO(BLACK);
|
|
||||||
TEST_MACRO(RED);
|
|
||||||
TEST_MACRO(GREEN);
|
|
||||||
TEST_MACRO(YELLOW);
|
|
||||||
TEST_MACRO(BLUE);
|
|
||||||
TEST_MACRO(MAGENTA);
|
|
||||||
TEST_MACRO(CYAN);
|
|
||||||
TEST_MACRO(WHITE);
|
|
||||||
|
|
||||||
#undef TEST_MACRO
|
|
||||||
|
|
||||||
// UTF8 Output Test
|
|
||||||
Console::WriteLine(YYCC_U8("UTF8 Output Test:"));
|
|
||||||
for (const auto& strl : c_UTF8TestStrTable) {
|
|
||||||
Console::FormatLine(YYCC_U8("\t%s"), strl.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// UTF8 Input Test
|
|
||||||
Console::WriteLine(YYCC_U8("UTF8 Input Test:"));
|
|
||||||
for (const auto& strl : c_UTF8TestStrTable) {
|
|
||||||
Console::FormatLine(YYCC_U8("\tPlease type: %s"), strl.c_str());
|
|
||||||
Console::Write(YYCC_U8("\t> "));
|
|
||||||
|
|
||||||
YYCC::yycc_u8string gotten(Console::ReadLine());
|
|
||||||
if (gotten == strl) Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_GREEN("\tMatched! Got: %s")), gotten.c_str());
|
|
||||||
else Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("\tNOT Matched! Got: %s")), gotten.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EncodingTestbench() {
|
|
||||||
// get test tuple size
|
|
||||||
size_t count = c_UTF8TestStrTable.size();
|
|
||||||
|
|
||||||
// check the convertion between given string
|
|
||||||
for (size_t i = 0u; i < count; ++i) {
|
|
||||||
// get item
|
|
||||||
const auto& u8str = c_UTF8TestStrTable[i];
|
|
||||||
const auto& u16str = c_UTF16TestStrTable[i];
|
|
||||||
const auto& u32str = c_UTF32TestStrTable[i];
|
|
||||||
|
|
||||||
// create cache variables
|
|
||||||
YYCC::yycc_u8string u8cache;
|
|
||||||
std::u16string u16cache;
|
|
||||||
std::u32string u32cache;
|
|
||||||
|
|
||||||
// do convertion check
|
|
||||||
Assert(YYCC::EncodingHelper::UTF8ToUTF16(u8str, u16cache) && u16cache == u16str, YYCC_U8("YYCC::EncodingHelper::UTF8ToUTF16"));
|
|
||||||
Assert(YYCC::EncodingHelper::UTF8ToUTF32(u8str, u32cache) && u32cache == u32str, YYCC_U8("YYCC::EncodingHelper::UTF8ToUTF32"));
|
|
||||||
|
|
||||||
Assert(YYCC::EncodingHelper::UTF16ToUTF8(u16str, u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::UTF16ToUTF8"));
|
|
||||||
Assert(YYCC::EncodingHelper::UTF32ToUTF8(u32str, u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::UTF32ToUTF8"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// check wstring convertion on windows
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
for (size_t i = 0u; i < count; ++i) {
|
|
||||||
// get item
|
|
||||||
const auto& u8str = c_UTF8TestStrTable[i];
|
|
||||||
const auto& wstr = c_WStrTestStrTable[i];
|
|
||||||
|
|
||||||
// create cache variables
|
|
||||||
YYCC::yycc_u8string u8cache;
|
|
||||||
std::wstring wcache;
|
|
||||||
|
|
||||||
// do convertion check
|
|
||||||
Assert(YYCC::EncodingHelper::UTF8ToWchar(u8str.c_str(), wcache) && wcache == wstr, YYCC_U8("YYCC::EncodingHelper::UTF8ToWchar"));
|
|
||||||
Assert(YYCC::EncodingHelper::WcharToUTF8(wstr.c_str(), u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::WcharToUTF8"));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void StringTestbench() {
|
|
||||||
// Test Printf
|
|
||||||
auto test_printf = YYCC::StringHelper::Printf(YYCC_U8("%s == %s"), YYCC_U8("Hello World"), YYCC_U8("Hello, world"));
|
|
||||||
Assert(test_printf == YYCC_U8("Hello World == Hello, world"), YYCC_U8("YYCC::StringHelper::Printf"));
|
|
||||||
|
|
||||||
// Test Replace
|
|
||||||
auto test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8("bb"), YYCC_U8("dd")); // normal case
|
|
||||||
Assert(test_replace == YYCC_U8("aaddcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8("zz"), YYCC_U8("yy")); // no replace
|
|
||||||
Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC::yycc_u8string_view(), YYCC_U8("zz")); // empty finding
|
|
||||||
Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaaabbaa"), YYCC_U8("aa"), YYCC_U8("")); // no replaced string
|
|
||||||
Assert(test_replace == YYCC_U8("bb"), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaxcc"), YYCC_U8("x"), YYCC_U8("yx")); // nested replacing
|
|
||||||
Assert(test_replace == YYCC_U8("aayxcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
test_replace = YYCC::StringHelper::Replace(YYCC::yycc_u8string_view(), YYCC_U8(""), YYCC_U8("xy")); // empty source string
|
|
||||||
Assert(test_replace == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Replace"));
|
|
||||||
|
|
||||||
// Test Upper / Lower
|
|
||||||
auto test_lower = YYCC::StringHelper::Lower(YYCC_U8("LOWER"));
|
|
||||||
Assert(test_lower == YYCC_U8("lower"), YYCC_U8("YYCC::StringHelper::Lower"));
|
|
||||||
auto test_upper = YYCC::StringHelper::Upper(YYCC_U8("upper"));
|
|
||||||
Assert(test_upper == YYCC_U8("UPPER"), YYCC_U8("YYCC::StringHelper::Upper"));
|
|
||||||
|
|
||||||
// Test Join
|
|
||||||
std::vector<YYCC::yycc_u8string> test_join_container {
|
|
||||||
YYCC_U8(""), YYCC_U8("1"), YYCC_U8("2"), YYCC_U8("")
|
|
||||||
};
|
|
||||||
auto test_join = YYCC::StringHelper::Join(test_join_container.begin(), test_join_container.end(), YYCC_U8(", "));
|
|
||||||
Assert(test_join == YYCC_U8(", 1, 2, "), YYCC_U8("YYCC::StringHelper::Join"));
|
|
||||||
|
|
||||||
// Test Split
|
|
||||||
auto test_split = YYCC::StringHelper::Split(YYCC_U8(", 1, 2, "), YYCC_U8(", ")); // normal
|
|
||||||
Assert(test_split.size() == 4u, YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[0] == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[1] == YYCC_U8("1"), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[2] == YYCC_U8("2"), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[3] == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC_U8("-")); // no matched decilmer
|
|
||||||
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC::yycc_u8string_view()); // empty decilmer
|
|
||||||
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
test_split = YYCC::StringHelper::Split(YYCC::yycc_u8string_view(), YYCC_U8("")); // empty source string
|
|
||||||
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
Assert(test_split[0].empty(), YYCC_U8("YYCC::StringHelper::Split"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ParserTestbench() {
|
|
||||||
|
|
||||||
// Test success TryParse
|
|
||||||
#define TEST_MACRO(type_t, value, string_value, ...) { \
|
|
||||||
YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \
|
|
||||||
type_t cache; \
|
|
||||||
Assert(YYCC::ParserHelper::TryParse<type_t>(cache_string, cache, ##__VA_ARGS__) && cache == value, YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_MACRO(int8_t, INT8_C(-61), "-61");
|
|
||||||
TEST_MACRO(uint8_t, UINT8_C(200), "200");
|
|
||||||
TEST_MACRO(int16_t, INT16_C(6161), "6161");
|
|
||||||
TEST_MACRO(uint16_t, UINT16_C(32800), "32800");
|
|
||||||
TEST_MACRO(int32_t, INT32_C(61616161), "61616161");
|
|
||||||
TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293");
|
|
||||||
TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161");
|
|
||||||
TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807");
|
|
||||||
TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16);
|
|
||||||
TEST_MACRO(float, 1.0f, "1.0");
|
|
||||||
TEST_MACRO(double, 1.0, "1.0");
|
|
||||||
TEST_MACRO(bool, true, "true");
|
|
||||||
|
|
||||||
#undef TEST_MACRO
|
|
||||||
|
|
||||||
// Test failed TryParse
|
|
||||||
#define TEST_MACRO(type_t, string_value, ...) { \
|
|
||||||
YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \
|
|
||||||
type_t cache; \
|
|
||||||
Assert(!YYCC::ParserHelper::TryParse<type_t>(cache_string, cache, ##__VA_ARGS__), YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_MACRO(int8_t, "6161");
|
|
||||||
TEST_MACRO(uint8_t, "32800");
|
|
||||||
TEST_MACRO(int16_t, "61616161");
|
|
||||||
TEST_MACRO(uint16_t, "4294967293");
|
|
||||||
TEST_MACRO(int32_t, "616161616161");
|
|
||||||
TEST_MACRO(uint32_t, "9223372036854775807");
|
|
||||||
TEST_MACRO(int64_t, "616161616161616161616161");
|
|
||||||
TEST_MACRO(uint64_t, "92233720368547758079223372036854775807");
|
|
||||||
TEST_MACRO(float, "1e40");
|
|
||||||
TEST_MACRO(double, "1e114514");
|
|
||||||
TEST_MACRO(bool, "hello, world!");
|
|
||||||
|
|
||||||
#undef TEST_MACRO
|
|
||||||
|
|
||||||
// Test ToString
|
|
||||||
#define TEST_MACRO(type_t, value, string_value, ...) { \
|
|
||||||
type_t cache = value; \
|
|
||||||
YYCC::yycc_u8string ret(YYCC::ParserHelper::ToString<type_t>(cache, ##__VA_ARGS__)); \
|
|
||||||
Assert(ret == YYCC_U8(string_value), YYCC_U8("YYCC::StringHelper::ToString<" #type_t ">")); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_MACRO(int8_t, INT8_C(-61), "-61");
|
|
||||||
TEST_MACRO(uint8_t, UINT8_C(200), "200");
|
|
||||||
TEST_MACRO(int16_t, INT16_C(6161), "6161");
|
|
||||||
TEST_MACRO(uint16_t, UINT16_C(32800), "32800");
|
|
||||||
TEST_MACRO(int32_t, INT32_C(61616161), "61616161");
|
|
||||||
TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293");
|
|
||||||
TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161");
|
|
||||||
TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807");
|
|
||||||
TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16);
|
|
||||||
TEST_MACRO(float, 1.0f, "1.0", std::chars_format::fixed, 1);
|
|
||||||
TEST_MACRO(double, 1.0, "1.0", std::chars_format::fixed, 1);
|
|
||||||
TEST_MACRO(bool, true, "true");
|
|
||||||
|
|
||||||
#undef TEST_MACRO
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DialogTestbench() {
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
|
|
||||||
YYCC::yycc_u8string ret;
|
|
||||||
std::vector<YYCC::yycc_u8string> rets;
|
|
||||||
|
|
||||||
YYCC::DialogHelper::FileDialog params;
|
|
||||||
auto& filters = params.ConfigreFileTypes();
|
|
||||||
filters.Add(YYCC_U8("Microsoft Word (*.docx; *.doc)"), { YYCC_U8("*.docx"), YYCC_U8("*.doc") });
|
|
||||||
filters.Add(YYCC_U8("Microsoft Excel (*.xlsx; *.xls)"), { YYCC_U8("*.xlsx"), YYCC_U8("*.xls") });
|
|
||||||
filters.Add(YYCC_U8("Microsoft PowerPoint (*.pptx; *.ppt)"), { YYCC_U8("*.pptx"), YYCC_U8("*.ppt") });
|
|
||||||
filters.Add(YYCC_U8("Text File (*.txt)"), { YYCC_U8("*.txt") });
|
|
||||||
filters.Add(YYCC_U8("All Files (*.*)"), { YYCC_U8("*.*") });
|
|
||||||
params.SetDefaultFileTypeIndex(0u);
|
|
||||||
if (YYCC::DialogHelper::OpenFileDialog(params, ret)) {
|
|
||||||
Console::FormatLine(YYCC_U8("Open File: %s"), ret.c_str());
|
|
||||||
}
|
|
||||||
if (YYCC::DialogHelper::OpenMultipleFileDialog(params, rets)) {
|
|
||||||
Console::WriteLine(YYCC_U8("Open Multiple Files:"));
|
|
||||||
for (const auto& item : rets) {
|
|
||||||
Console::FormatLine(YYCC_U8("\t%s"), item.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (YYCC::DialogHelper::SaveFileDialog(params, ret)) {
|
|
||||||
Console::FormatLine(YYCC_U8("Save File: %s"), ret.c_str());
|
|
||||||
}
|
|
||||||
params.Clear();
|
|
||||||
if (YYCC::DialogHelper::OpenFolderDialog(params, ret)) {
|
|
||||||
Console::FormatLine(YYCC_U8("Open Folder: %s"), ret.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ExceptionTestbench() {
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
|
|
||||||
YYCC::ExceptionHelper::Register([](const YYCC::yycc_u8string& log_path, const YYCC::yycc_u8string& coredump_path) -> void {
|
|
||||||
MessageBoxW(
|
|
||||||
NULL,
|
|
||||||
YYCC::EncodingHelper::UTF8ToWchar(
|
|
||||||
YYCC::StringHelper::Printf(YYCC_U8("Log generated:\nLog path: %s\nCore dump path: %s"), log_path.c_str(), coredump_path.c_str())
|
|
||||||
).c_str(),
|
|
||||||
L"Fatal Error", MB_OK + MB_ICONERROR
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Perform a div zero exception.
|
|
||||||
#if defined (YYCC_DEBUG_UE_FILTER)
|
|
||||||
// Reference: https://stackoverflow.com/questions/20981982/is-it-possible-to-debug-unhandledexceptionfilters-with-a-debugger
|
|
||||||
__try {
|
|
||||||
// all of code normally inside of main or WinMain here...
|
|
||||||
int i = 1, j = 0;
|
|
||||||
int k = i / j;
|
|
||||||
} __except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) {
|
|
||||||
OutputDebugStringW(L"executed filter function\n");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int i = 1, j = 0;
|
|
||||||
int k = i / j;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
YYCC::ExceptionHelper::Unregister();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WinFctTestbench() {
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
|
|
||||||
HMODULE test_current_module;
|
|
||||||
Assert((test_current_module = YYCC::WinFctHelper::GetCurrentModule()) != nullptr, YYCC_U8("YYCC::WinFctHelper::GetCurrentModule"));
|
|
||||||
Console::FormatLine(YYCC_U8("Current Module HANDLE: 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR), test_current_module);
|
|
||||||
|
|
||||||
YYCC::yycc_u8string test_temp;
|
|
||||||
Assert(YYCC::WinFctHelper::GetTempDirectory(test_temp), YYCC_U8("YYCC::WinFctHelper::GetTempDirectory"));
|
|
||||||
Console::FormatLine(YYCC_U8("Temp Directory: %s"), test_temp.c_str());
|
|
||||||
|
|
||||||
YYCC::yycc_u8string test_module_name;
|
|
||||||
Assert(YYCC::WinFctHelper::GetModuleFileName(YYCC::WinFctHelper::GetCurrentModule(), test_module_name), YYCC_U8("YYCC::WinFctHelper::GetModuleFileName"));
|
|
||||||
Console::FormatLine(YYCC_U8("Current Module File Name: %s"), test_module_name.c_str());
|
|
||||||
|
|
||||||
YYCC::yycc_u8string test_localappdata_path;
|
|
||||||
Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData"));
|
|
||||||
Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str());
|
|
||||||
|
|
||||||
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(1252)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
|
|
||||||
Assert(!YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(114514)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
|
|
||||||
|
|
||||||
// MARK: There is no testbench for MoveFile, CopyFile DeleteFile.
|
|
||||||
// Because they can operate file system files.
|
|
||||||
// And may cause test environment entering unstable status.
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void StdPatchTestbench() {
|
|
||||||
|
|
||||||
// Std Path
|
|
||||||
|
|
||||||
std::filesystem::path test_path;
|
|
||||||
for (const auto& strl : c_UTF8TestStrTable) {
|
|
||||||
test_path /= YYCC::StdPatch::ToStdPath(strl);
|
|
||||||
}
|
|
||||||
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
|
|
||||||
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator);
|
|
||||||
YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer));
|
|
||||||
#else
|
|
||||||
YYCC::yycc_u8string decilmer(1u, std::filesystem::path::preferred_separator);
|
|
||||||
#endif
|
|
||||||
YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable.begin(), c_UTF8TestStrTable.end(), decilmer));
|
|
||||||
|
|
||||||
Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch::ToStdPath, YYCC::StdPatch::ToUTF8Path"));
|
|
||||||
|
|
||||||
// StartsWith, EndsWith
|
|
||||||
YYCC::yycc_u8string test_starts_ends_with(YYCC_U8("aaabbbccc"));
|
|
||||||
Assert(YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::StartsWith"));
|
|
||||||
Assert(!YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::StartsWith"));
|
|
||||||
Assert(!YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::EndsWith"));
|
|
||||||
Assert(YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::EndsWith"));
|
|
||||||
|
|
||||||
// Contains
|
|
||||||
std::set<int> test_set { 1, 2, 3, 4, 6, 7 };
|
|
||||||
Assert(YYCC::StdPatch::Contains(test_set, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
|
|
||||||
Assert(!YYCC::StdPatch::Contains(test_set, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
|
|
||||||
std::map<int, float> test_map { { 1, 1.0f }, { 4, 4.0f } };
|
|
||||||
Assert(YYCC::StdPatch::Contains(test_map, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
|
|
||||||
Assert(!YYCC::StdPatch::Contains(test_map, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class TestFlagEnum : uint8_t {
|
|
||||||
Test1 = 0b00000000,
|
|
||||||
Test2 = 0b00000001,
|
|
||||||
Test3 = 0b00000010,
|
|
||||||
Test4 = 0b00000100,
|
|
||||||
Test5 = 0b00001000,
|
|
||||||
Test6 = 0b00010000,
|
|
||||||
Test7 = 0b00100000,
|
|
||||||
Test8 = 0b01000000,
|
|
||||||
Test9 = 0b10000000,
|
|
||||||
Inverted = 0b01111111,
|
|
||||||
Merged = Test3 + Test5,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void EnumHelperTestbench() {
|
|
||||||
TestFlagEnum val;
|
|
||||||
|
|
||||||
Assert(YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5) == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Merge"));
|
|
||||||
|
|
||||||
Assert(YYCC::EnumHelper::Invert(TestFlagEnum::Test9) == TestFlagEnum::Inverted, YYCC_U8("YYCC::EnumHelper::Invert"));
|
|
||||||
|
|
||||||
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
|
||||||
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test3);
|
|
||||||
Assert(YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
|
||||||
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
|
||||||
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test4);
|
|
||||||
Assert(!YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
|
||||||
|
|
||||||
val = TestFlagEnum::Test3;
|
|
||||||
YYCC::EnumHelper::Add(val, TestFlagEnum::Test5);
|
|
||||||
Assert(val == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Add"));
|
|
||||||
|
|
||||||
val = TestFlagEnum::Merged;
|
|
||||||
YYCC::EnumHelper::Remove(val, TestFlagEnum::Test5);
|
|
||||||
Assert(val == TestFlagEnum::Test3, YYCC_U8("YYCC::EnumHelper::Remove"));
|
|
||||||
|
|
||||||
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
|
||||||
Assert(YYCC::EnumHelper::Has(val, TestFlagEnum::Test3), YYCC_U8("YYCC::EnumHelper::Has"));
|
|
||||||
Assert(!YYCC::EnumHelper::Has(val, TestFlagEnum::Test4), YYCC_U8("YYCC::EnumHelper::Has"));
|
|
||||||
|
|
||||||
Assert(!YYCC::EnumHelper::Bool(TestFlagEnum::Test1), YYCC_U8("YYCC::EnumHelper::Bool"));
|
|
||||||
Assert(YYCC::EnumHelper::Bool(TestFlagEnum::Test2), YYCC_U8("YYCC::EnumHelper::Bool"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void VersionMacroTestbench() {
|
|
||||||
Assert(YYCC_VERCMP_E(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_E"));
|
|
||||||
Assert(!YYCC_VERCMP_NE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NE"));
|
|
||||||
Assert(YYCC_VERCMP_G(1, 2, 3, 0, 2, 5), YYCC_U8("YYCC_VERCMP_G"));
|
|
||||||
Assert(YYCC_VERCMP_GE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_GE"));
|
|
||||||
Assert(YYCC_VERCMP_NL(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NL"));
|
|
||||||
Assert(YYCC_VERCMP_L(0, 2, 5, 1, 2, 3), YYCC_U8("YYCC_VERCMP_L"));
|
|
||||||
Assert(YYCC_VERCMP_LE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_LE"));
|
|
||||||
Assert(YYCC_VERCMP_NG(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NG"));
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class TestEnum : int8_t {
|
|
||||||
Test1, Test2, Test3
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestConfigManager {
|
|
||||||
public:
|
|
||||||
TestConfigManager() :
|
|
||||||
m_IntSetting(YYCC_U8("int-setting"), INT32_C(0)),
|
|
||||||
m_FloatSetting(YYCC_U8("float-setting"), 0.0f),
|
|
||||||
m_StringSetting(YYCC_U8("string-setting"), YYCC_U8("")),
|
|
||||||
m_BoolSetting(YYCC_U8("bool-setting"), false),
|
|
||||||
m_ClampedFloatSetting(YYCC_U8("clamped-float-setting"), 0.0f, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
|
||||||
m_EnumSetting(YYCC_U8("enum-setting"), TestEnum::Test1),
|
|
||||||
m_CoreManager(YYCC_U8("test.cfg"), UINT64_C(0), {
|
|
||||||
&m_IntSetting, &m_FloatSetting, &m_StringSetting, &m_BoolSetting, &m_ClampedFloatSetting, &m_EnumSetting
|
|
||||||
}) {}
|
|
||||||
~TestConfigManager() {}
|
|
||||||
|
|
||||||
void PrintSettings() {
|
|
||||||
Console::WriteLine(YYCC_U8("Config Manager Settings:"));
|
|
||||||
|
|
||||||
Console::FormatLine(YYCC_U8("\tint-setting: %" PRIi32), m_IntSetting.Get());
|
|
||||||
Console::FormatLine(YYCC_U8("\tfloat-setting: %f"), m_FloatSetting.Get());
|
|
||||||
Console::FormatLine(YYCC_U8("\tstring-setting: %s"), m_StringSetting.Get().c_str());
|
|
||||||
|
|
||||||
Console::FormatLine(YYCC_U8("\tbool-setting: %s"), m_BoolSetting.Get() ? YYCC_U8("true") : YYCC_U8("false"));
|
|
||||||
Console::FormatLine(YYCC_U8("\tfloat-setting: %f"), m_ClampedFloatSetting.Get());
|
|
||||||
Console::FormatLine(YYCC_U8("\tenum-setting: %" PRIi8), static_cast<std::underlying_type_t<TestEnum>>(m_EnumSetting.Get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
YYCC::ConfigManager::NumberSetting<int32_t> m_IntSetting;
|
|
||||||
YYCC::ConfigManager::NumberSetting<float> m_FloatSetting;
|
|
||||||
YYCC::ConfigManager::StringSetting m_StringSetting;
|
|
||||||
|
|
||||||
YYCC::ConfigManager::NumberSetting<bool> m_BoolSetting;
|
|
||||||
YYCC::ConfigManager::NumberSetting<float> m_ClampedFloatSetting;
|
|
||||||
YYCC::ConfigManager::NumberSetting<TestEnum> m_EnumSetting;
|
|
||||||
|
|
||||||
YYCC::ConfigManager::CoreManager m_CoreManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ConfigManagerTestbench() {
|
|
||||||
// init cfg manager
|
|
||||||
TestConfigManager test;
|
|
||||||
|
|
||||||
// test constraint works
|
|
||||||
Assert(!test.m_ClampedFloatSetting.Set(2.0f), YYCC_U8("YYCC::Constraints::Constraint"));
|
|
||||||
Assert(test.m_ClampedFloatSetting.Get() == 0.0f, YYCC_U8("YYCC::Constraints::Constraint"));
|
|
||||||
|
|
||||||
// test modify settings
|
|
||||||
#define TEST_MACRO(member_name, set_val) { \
|
|
||||||
Assert(test.member_name.Set(set_val), YYCC_U8("YYCC::ConfigManager::AbstractSetting::Set")); \
|
|
||||||
Assert(test.member_name.Get() == set_val, YYCC_U8("YYCC::ConfigManager::AbstractSetting::Set")); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_MACRO(m_IntSetting, INT32_C(114));
|
|
||||||
TEST_MACRO(m_FloatSetting, 2.0f);
|
|
||||||
TEST_MACRO(m_StringSetting, YYCC_U8("fuck"));
|
|
||||||
TEST_MACRO(m_BoolSetting, true);
|
|
||||||
TEST_MACRO(m_ClampedFloatSetting, 0.5f);
|
|
||||||
TEST_MACRO(m_EnumSetting, TestEnum::Test2);
|
|
||||||
|
|
||||||
#undef TEST_MACRO
|
|
||||||
|
|
||||||
// test save
|
|
||||||
test.PrintSettings();
|
|
||||||
Assert(test.m_CoreManager.Save(), YYCC_U8("YYCC::ConfigManager::CoreManager::Save"));
|
|
||||||
|
|
||||||
// test reset
|
|
||||||
test.m_CoreManager.Reset();
|
|
||||||
test.PrintSettings();
|
|
||||||
Assert(test.m_IntSetting.Get() == INT32_C(0), YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
Assert(test.m_FloatSetting.Get() == 0.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
Assert(test.m_StringSetting.Get() == YYCC_U8(""), YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
Assert(test.m_BoolSetting.Get() == false, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
Assert(test.m_ClampedFloatSetting.Get() == 0.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
Assert(test.m_EnumSetting.Get() == TestEnum::Test1, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
|
||||||
|
|
||||||
// test load
|
|
||||||
YYCC::ConfigManager::ConfigLoadResult wrong_result = YYCC::EnumHelper::Merge(
|
|
||||||
YYCC::ConfigManager::ConfigLoadResult::ItemError,
|
|
||||||
YYCC::ConfigManager::ConfigLoadResult::BrokenFile
|
|
||||||
);
|
|
||||||
Assert(!YYCC::EnumHelper::Has(test.m_CoreManager.Load(), wrong_result), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
test.PrintSettings();
|
|
||||||
Assert(test.m_IntSetting.Get() == INT32_C(114), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
Assert(test.m_FloatSetting.Get() == 2.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
Assert(test.m_StringSetting.Get() == YYCC_U8("fuck"), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
Assert(test.m_BoolSetting.Get() == true, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
Assert(test.m_ClampedFloatSetting.Get() == 0.5f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
Assert(test.m_EnumSetting.Get() == TestEnum::Test2, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestArgParser {
|
|
||||||
public:
|
|
||||||
TestArgParser() :
|
|
||||||
m_IntArgument(YYCC_U8("int"), YYCC_U8_CHAR('i'), YYCC_U8("integral argument"), YYCC_U8("114514")),
|
|
||||||
m_FloatArgument(nullptr, YYCC_U8_CHAR('f'), nullptr, nullptr, true),
|
|
||||||
m_StringArgument(YYCC_U8("string"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true),
|
|
||||||
m_BoolArgument(nullptr, YYCC_U8_CHAR('b'), nullptr),
|
|
||||||
m_ClampedFloatArgument(YYCC_U8("clamped-float"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
|
||||||
m_OptionContext(YYCC_U8("TestArgParser"), YYCC_U8("This is the testbench of argument parser."), {
|
|
||||||
&m_IntArgument, &m_FloatArgument, &m_StringArgument,
|
|
||||||
&m_BoolArgument, &m_ClampedFloatArgument
|
|
||||||
}) {}
|
|
||||||
~TestArgParser() {}
|
|
||||||
|
|
||||||
YYCC::ArgParser::NumberArgument<int32_t> m_IntArgument;
|
|
||||||
YYCC::ArgParser::NumberArgument<float> m_FloatArgument;
|
|
||||||
YYCC::ArgParser::StringArgument m_StringArgument;
|
|
||||||
|
|
||||||
YYCC::ArgParser::SwitchArgument m_BoolArgument;
|
|
||||||
YYCC::ArgParser::NumberArgument<float> m_ClampedFloatArgument;
|
|
||||||
|
|
||||||
YYCC::ArgParser::OptionContext m_OptionContext;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ArgParserTestbench(int argc, char* argv[]) {
|
|
||||||
// test command line getter
|
|
||||||
{
|
|
||||||
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromStd"));
|
|
||||||
auto result = YYCC::ArgParser::ArgumentList::CreateFromStd(argc, argv);
|
|
||||||
for (result.Reset(); !result.IsEOF(); result.Next()) {
|
|
||||||
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
|
||||||
{
|
|
||||||
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromWin32"));
|
|
||||||
auto result = YYCC::ArgParser::ArgumentList::CreateFromWin32();
|
|
||||||
for (result.Reset(); !result.IsEOF(); result.Next()) {
|
|
||||||
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// test option context
|
|
||||||
// init option context
|
|
||||||
TestArgParser test;
|
|
||||||
|
|
||||||
#define PREPARE_DATA(...) const char* test_argv[] = { __VA_ARGS__ }; \
|
|
||||||
auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(sizeof(test_argv) / sizeof(char*), const_cast<char**>(test_argv));
|
|
||||||
|
|
||||||
// normal test
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i", "114514");
|
|
||||||
Assert(test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_IntArgument.IsCaptured() && test.m_IntArgument.Get() == UINT32_C(114514), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(!test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(!test.m_FloatArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(!test.m_StringArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(!test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(!test.m_ClampedFloatArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// no argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// error argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-?", "114514");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// lost argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// dplicated assign
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i", "114514" "--int", "114514");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// extra useless argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i", "114514" "1919810");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// invalid clamp argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i", "114514", "--clamped-float", "114.0");
|
|
||||||
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
// full argument
|
|
||||||
{
|
|
||||||
PREPARE_DATA("exec", "-i", "114514", "-f", "2.0", "--string", "fuck", "-b", "--clamped-float", "0.5");
|
|
||||||
Assert(test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_IntArgument.IsCaptured() && test.m_IntArgument.Get() == UINT32_C(114514), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_FloatArgument.IsCaptured() && test.m_FloatArgument.Get() == 2.0f, YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_StringArgument.IsCaptured() && test.m_StringArgument.Get() == YYCC_U8("fuck"), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
Assert(test.m_ClampedFloatArgument.IsCaptured() && test.m_ClampedFloatArgument.Get() == 0.5f, YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
|
||||||
test.m_OptionContext.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Help text
|
|
||||||
test.m_OptionContext.Help();
|
|
||||||
|
|
||||||
#undef PREPARE_DATA
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
#if YYCC_VERCMP_NE(YYCC_VER_MAJOR, YYCC_VER_MINOR, YYCC_VER_PATCH, 1, 3 ,0)
|
return RUN_ALL_TESTS();
|
||||||
#error "The YYCC library used when compiling is not match code expected, this may cause build error."
|
|
||||||
#error "If you trust it, please annotate these preprocessor statement, otherwise please contact developer."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// common testbench
|
|
||||||
// normal
|
|
||||||
YYCCTestbench::EncodingTestbench();
|
|
||||||
YYCCTestbench::StringTestbench();
|
|
||||||
YYCCTestbench::ParserTestbench();
|
|
||||||
YYCCTestbench::WinFctTestbench();
|
|
||||||
YYCCTestbench::StdPatchTestbench();
|
|
||||||
YYCCTestbench::EnumHelperTestbench();
|
|
||||||
YYCCTestbench::VersionMacroTestbench();
|
|
||||||
// advanced
|
|
||||||
YYCCTestbench::ConfigManagerTestbench();
|
|
||||||
YYCCTestbench::ArgParserTestbench(argc, argv);
|
|
||||||
|
|
||||||
// testbench which may terminal app or ordering input
|
|
||||||
YYCCTestbench::ConsoleTestbench();
|
|
||||||
YYCCTestbench::DialogTestbench();
|
|
||||||
YYCCTestbench::ExceptionTestbench();
|
|
||||||
}
|
}
|
||||||
|
735
testbench/main_legacy.cpp
Normal file
735
testbench/main_legacy.cpp
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
#include <YYCCommonplace.hpp>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace Console = YYCC::ConsoleHelper;
|
||||||
|
|
||||||
|
namespace YYCCTestbench {
|
||||||
|
|
||||||
|
#pragma region Unicode Test Data
|
||||||
|
|
||||||
|
// UNICODE Test Strings
|
||||||
|
// Ref: https://stackoverflow.com/questions/478201/how-to-test-an-application-for-correct-encoding-e-g-utf-8
|
||||||
|
#define TEST_UNICODE_STR_JAPAN "\u30E6\u30FC\u30B6\u30FC\u5225\u30B5\u30A4\u30C8"
|
||||||
|
#define TEST_UNICODE_STR_CHINA "\u7B80\u4F53\u4E2D\u6587"
|
||||||
|
#define TEST_UNICODE_STR_KOREA "\uD06C\uB85C\uC2A4 \uD50C\uB7AB\uD3FC\uC73C\uB85C"
|
||||||
|
#define TEST_UNICODE_STR_ISRAEL "\u05DE\u05D3\u05D5\u05E8\u05D9\u05DD \u05DE\u05D1\u05D5\u05E7\u05E9\u05D9\u05DD"
|
||||||
|
#define TEST_UNICODE_STR_EGYPT "\u0623\u0641\u0636\u0644 \u0627\u0644\u0628\u062D\u0648\u062B"
|
||||||
|
#define TEST_UNICODE_STR_GREECE "\u03A3\u1F72 \u03B3\u03BD\u03C9\u03C1\u03AF\u03B6\u03C9 \u1F00\u03C0\u1F78"
|
||||||
|
#define TEST_UNICODE_STR_RUSSIA "\u0414\u0435\u0441\u044F\u0442\u0443\u044E \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E"
|
||||||
|
#define TEST_UNICODE_STR_THAILAND "\u0E41\u0E1C\u0E48\u0E19\u0E14\u0E34\u0E19\u0E2E\u0E31\u0E48\u0E19\u0E40\u0E2A\u0E37\u0E48\u0E2D\u0E21\u0E42\u0E17\u0E23\u0E21\u0E41\u0E2A\u0E19\u0E2A\u0E31\u0E07\u0E40\u0E27\u0E0A"
|
||||||
|
#define TEST_UNICODE_STR_FRANCE "fran\u00E7ais langue \u00E9trang\u00E8re"
|
||||||
|
#define TEST_UNICODE_STR_SPAIN "ma\u00F1ana ol\u00E9"
|
||||||
|
#define TEST_UNICODE_STR_MATHMATICS "\u222E E\u22C5da = Q, n \u2192 \u221E, \u2211 f(i) = \u220F g(i)"
|
||||||
|
#define TEST_UNICODE_STR_EMOJI "\U0001F363 \u2716 \U0001F37A" // sushi x beer mug
|
||||||
|
|
||||||
|
#define CONCAT(prefix, strl) prefix ## strl
|
||||||
|
#define CPP_U8_LITERAL(strl) YYCC_U8(strl)
|
||||||
|
#define CPP_U16_LITERAL(strl) CONCAT(u, strl)
|
||||||
|
#define CPP_U32_LITERAL(strl) CONCAT(U, strl)
|
||||||
|
#define CPP_WSTR_LITERAL(strl) CONCAT(L, strl)
|
||||||
|
|
||||||
|
static std::vector<YYCC::yycc_u8string> c_UTF8TestStrTable {
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_JAPAN),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_EGYPT),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_GREECE),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_THAILAND),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_FRANCE),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_SPAIN),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
||||||
|
CPP_U8_LITERAL(TEST_UNICODE_STR_EMOJI),
|
||||||
|
};
|
||||||
|
static std::vector<std::wstring> c_WStrTestStrTable {
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_JAPAN),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_CHINA),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_KOREA),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_EGYPT),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_GREECE),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_THAILAND),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_FRANCE),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_SPAIN),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
||||||
|
CPP_WSTR_LITERAL(TEST_UNICODE_STR_EMOJI),
|
||||||
|
};
|
||||||
|
static std::vector<std::u16string> c_UTF16TestStrTable {
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_JAPAN),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_CHINA),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_KOREA),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_EGYPT),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_GREECE),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_THAILAND),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_FRANCE),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_SPAIN),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
||||||
|
CPP_U16_LITERAL(TEST_UNICODE_STR_EMOJI),
|
||||||
|
};
|
||||||
|
static std::vector<std::u32string> c_UTF32TestStrTable {
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_JAPAN),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_CHINA),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_KOREA),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_ISRAEL),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_EGYPT),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_GREECE),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_RUSSIA),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_THAILAND),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_FRANCE),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_SPAIN),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_MATHMATICS),
|
||||||
|
CPP_U32_LITERAL(TEST_UNICODE_STR_EMOJI),
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef CPP_WSTR_LITERAL
|
||||||
|
#undef CPP_U32_LITERAL
|
||||||
|
#undef CPP_U16_LITERAL
|
||||||
|
#undef CPP_U8_LITERAL
|
||||||
|
#undef CONCAT
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
static void Assert(bool condition, const YYCC::yycc_char8_t* description) {
|
||||||
|
if (condition) {
|
||||||
|
Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_GREEN("OK: %s")), description);
|
||||||
|
} else {
|
||||||
|
Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("Failed: %s\n")), description);
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConsoleTestbench() {
|
||||||
|
// Color Test
|
||||||
|
Console::EnableColorfulConsole();
|
||||||
|
Console::WriteLine(YYCC_U8("Color Test:"));
|
||||||
|
|
||||||
|
#define TEST_MACRO(col) Console::WriteLine(YYCC_U8("\t" YYCC_COLOR_ ## col ("\u2588\u2588") YYCC_COLOR_LIGHT_ ## col("\u2588\u2588") " " #col " / LIGHT " #col ));
|
||||||
|
// U+2588 is full block
|
||||||
|
|
||||||
|
TEST_MACRO(BLACK);
|
||||||
|
TEST_MACRO(RED);
|
||||||
|
TEST_MACRO(GREEN);
|
||||||
|
TEST_MACRO(YELLOW);
|
||||||
|
TEST_MACRO(BLUE);
|
||||||
|
TEST_MACRO(MAGENTA);
|
||||||
|
TEST_MACRO(CYAN);
|
||||||
|
TEST_MACRO(WHITE);
|
||||||
|
|
||||||
|
#undef TEST_MACRO
|
||||||
|
|
||||||
|
// UTF8 Output Test
|
||||||
|
Console::WriteLine(YYCC_U8("UTF8 Output Test:"));
|
||||||
|
for (const auto& strl : c_UTF8TestStrTable) {
|
||||||
|
Console::FormatLine(YYCC_U8("\t%s"), strl.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF8 Input Test
|
||||||
|
Console::WriteLine(YYCC_U8("UTF8 Input Test:"));
|
||||||
|
for (const auto& strl : c_UTF8TestStrTable) {
|
||||||
|
Console::FormatLine(YYCC_U8("\tPlease type: %s"), strl.c_str());
|
||||||
|
Console::Write(YYCC_U8("\t> "));
|
||||||
|
|
||||||
|
YYCC::yycc_u8string gotten(Console::ReadLine());
|
||||||
|
if (gotten == strl) Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_GREEN("\tMatched! Got: %s")), gotten.c_str());
|
||||||
|
else Console::FormatLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("\tNOT Matched! Got: %s")), gotten.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EncodingTestbench() {
|
||||||
|
// get test tuple size
|
||||||
|
size_t count = c_UTF8TestStrTable.size();
|
||||||
|
|
||||||
|
// check the convertion between given string
|
||||||
|
for (size_t i = 0u; i < count; ++i) {
|
||||||
|
// get item
|
||||||
|
const auto& u8str = c_UTF8TestStrTable[i];
|
||||||
|
const auto& u16str = c_UTF16TestStrTable[i];
|
||||||
|
const auto& u32str = c_UTF32TestStrTable[i];
|
||||||
|
|
||||||
|
// create cache variables
|
||||||
|
YYCC::yycc_u8string u8cache;
|
||||||
|
std::u16string u16cache;
|
||||||
|
std::u32string u32cache;
|
||||||
|
|
||||||
|
// do convertion check
|
||||||
|
Assert(YYCC::EncodingHelper::UTF8ToUTF16(u8str, u16cache) && u16cache == u16str, YYCC_U8("YYCC::EncodingHelper::UTF8ToUTF16"));
|
||||||
|
Assert(YYCC::EncodingHelper::UTF8ToUTF32(u8str, u32cache) && u32cache == u32str, YYCC_U8("YYCC::EncodingHelper::UTF8ToUTF32"));
|
||||||
|
|
||||||
|
Assert(YYCC::EncodingHelper::UTF16ToUTF8(u16str, u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::UTF16ToUTF8"));
|
||||||
|
Assert(YYCC::EncodingHelper::UTF32ToUTF8(u32str, u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::UTF32ToUTF8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check wstring convertion on windows
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
for (size_t i = 0u; i < count; ++i) {
|
||||||
|
// get item
|
||||||
|
const auto& u8str = c_UTF8TestStrTable[i];
|
||||||
|
const auto& wstr = c_WStrTestStrTable[i];
|
||||||
|
|
||||||
|
// create cache variables
|
||||||
|
YYCC::yycc_u8string u8cache;
|
||||||
|
std::wstring wcache;
|
||||||
|
|
||||||
|
// do convertion check
|
||||||
|
Assert(YYCC::EncodingHelper::UTF8ToWchar(u8str.c_str(), wcache) && wcache == wstr, YYCC_U8("YYCC::EncodingHelper::UTF8ToWchar"));
|
||||||
|
Assert(YYCC::EncodingHelper::WcharToUTF8(wstr.c_str(), u8cache) && u8cache == u8str, YYCC_U8("YYCC::EncodingHelper::WcharToUTF8"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StringTestbench() {
|
||||||
|
// Test Printf
|
||||||
|
auto test_printf = YYCC::StringHelper::Printf(YYCC_U8("%s == %s"), YYCC_U8("Hello World"), YYCC_U8("Hello, world"));
|
||||||
|
Assert(test_printf == YYCC_U8("Hello World == Hello, world"), YYCC_U8("YYCC::StringHelper::Printf"));
|
||||||
|
|
||||||
|
// Test Replace
|
||||||
|
auto test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8("bb"), YYCC_U8("dd")); // normal case
|
||||||
|
Assert(test_replace == YYCC_U8("aaddcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC_U8("zz"), YYCC_U8("yy")); // no replace
|
||||||
|
Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aabbcc"), YYCC::yycc_u8string_view(), YYCC_U8("zz")); // empty finding
|
||||||
|
Assert(test_replace == YYCC_U8("aabbcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaaabbaa"), YYCC_U8("aa"), YYCC_U8("")); // no replaced string
|
||||||
|
Assert(test_replace == YYCC_U8("bb"), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
test_replace = YYCC::StringHelper::Replace(YYCC_U8("aaxcc"), YYCC_U8("x"), YYCC_U8("yx")); // nested replacing
|
||||||
|
Assert(test_replace == YYCC_U8("aayxcc"), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
test_replace = YYCC::StringHelper::Replace(YYCC::yycc_u8string_view(), YYCC_U8(""), YYCC_U8("xy")); // empty source string
|
||||||
|
Assert(test_replace == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Replace"));
|
||||||
|
|
||||||
|
// Test Upper / Lower
|
||||||
|
auto test_lower = YYCC::StringHelper::Lower(YYCC_U8("LOWER"));
|
||||||
|
Assert(test_lower == YYCC_U8("lower"), YYCC_U8("YYCC::StringHelper::Lower"));
|
||||||
|
auto test_upper = YYCC::StringHelper::Upper(YYCC_U8("upper"));
|
||||||
|
Assert(test_upper == YYCC_U8("UPPER"), YYCC_U8("YYCC::StringHelper::Upper"));
|
||||||
|
|
||||||
|
// Test Join
|
||||||
|
std::vector<YYCC::yycc_u8string> test_join_container {
|
||||||
|
YYCC_U8(""), YYCC_U8("1"), YYCC_U8("2"), YYCC_U8("")
|
||||||
|
};
|
||||||
|
auto test_join = YYCC::StringHelper::Join(test_join_container.begin(), test_join_container.end(), YYCC_U8(", "));
|
||||||
|
Assert(test_join == YYCC_U8(", 1, 2, "), YYCC_U8("YYCC::StringHelper::Join"));
|
||||||
|
|
||||||
|
// Test Split
|
||||||
|
auto test_split = YYCC::StringHelper::Split(YYCC_U8(", 1, 2, "), YYCC_U8(", ")); // normal
|
||||||
|
Assert(test_split.size() == 4u, YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[0] == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[1] == YYCC_U8("1"), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[2] == YYCC_U8("2"), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[3] == YYCC_U8(""), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC_U8("-")); // no matched decilmer
|
||||||
|
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
test_split = YYCC::StringHelper::Split(YYCC_U8("test"), YYCC::yycc_u8string_view()); // empty decilmer
|
||||||
|
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[0] == YYCC_U8("test"), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
test_split = YYCC::StringHelper::Split(YYCC::yycc_u8string_view(), YYCC_U8("")); // empty source string
|
||||||
|
Assert(test_split.size() == 1u, YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
Assert(test_split[0].empty(), YYCC_U8("YYCC::StringHelper::Split"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ParserTestbench() {
|
||||||
|
|
||||||
|
// Test success TryParse
|
||||||
|
#define TEST_MACRO(type_t, value, string_value, ...) { \
|
||||||
|
YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \
|
||||||
|
type_t cache; \
|
||||||
|
Assert(YYCC::ParserHelper::TryParse<type_t>(cache_string, cache, ##__VA_ARGS__) && cache == value, YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_MACRO(int8_t, INT8_C(-61), "-61");
|
||||||
|
TEST_MACRO(uint8_t, UINT8_C(200), "200");
|
||||||
|
TEST_MACRO(int16_t, INT16_C(6161), "6161");
|
||||||
|
TEST_MACRO(uint16_t, UINT16_C(32800), "32800");
|
||||||
|
TEST_MACRO(int32_t, INT32_C(61616161), "61616161");
|
||||||
|
TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293");
|
||||||
|
TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161");
|
||||||
|
TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807");
|
||||||
|
TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16);
|
||||||
|
TEST_MACRO(float, 1.0f, "1.0");
|
||||||
|
TEST_MACRO(double, 1.0, "1.0");
|
||||||
|
TEST_MACRO(bool, true, "true");
|
||||||
|
|
||||||
|
#undef TEST_MACRO
|
||||||
|
|
||||||
|
// Test failed TryParse
|
||||||
|
#define TEST_MACRO(type_t, string_value, ...) { \
|
||||||
|
YYCC::yycc_u8string cache_string(YYCC_U8(string_value)); \
|
||||||
|
type_t cache; \
|
||||||
|
Assert(!YYCC::ParserHelper::TryParse<type_t>(cache_string, cache, ##__VA_ARGS__), YYCC_U8("YYCC::StringHelper::TryParse<" #type_t ">")); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_MACRO(int8_t, "6161");
|
||||||
|
TEST_MACRO(uint8_t, "32800");
|
||||||
|
TEST_MACRO(int16_t, "61616161");
|
||||||
|
TEST_MACRO(uint16_t, "4294967293");
|
||||||
|
TEST_MACRO(int32_t, "616161616161");
|
||||||
|
TEST_MACRO(uint32_t, "9223372036854775807");
|
||||||
|
TEST_MACRO(int64_t, "616161616161616161616161");
|
||||||
|
TEST_MACRO(uint64_t, "92233720368547758079223372036854775807");
|
||||||
|
TEST_MACRO(float, "1e40");
|
||||||
|
TEST_MACRO(double, "1e114514");
|
||||||
|
TEST_MACRO(bool, "hello, world!");
|
||||||
|
|
||||||
|
#undef TEST_MACRO
|
||||||
|
|
||||||
|
// Test ToString
|
||||||
|
#define TEST_MACRO(type_t, value, string_value, ...) { \
|
||||||
|
type_t cache = value; \
|
||||||
|
YYCC::yycc_u8string ret(YYCC::ParserHelper::ToString<type_t>(cache, ##__VA_ARGS__)); \
|
||||||
|
Assert(ret == YYCC_U8(string_value), YYCC_U8("YYCC::StringHelper::ToString<" #type_t ">")); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_MACRO(int8_t, INT8_C(-61), "-61");
|
||||||
|
TEST_MACRO(uint8_t, UINT8_C(200), "200");
|
||||||
|
TEST_MACRO(int16_t, INT16_C(6161), "6161");
|
||||||
|
TEST_MACRO(uint16_t, UINT16_C(32800), "32800");
|
||||||
|
TEST_MACRO(int32_t, INT32_C(61616161), "61616161");
|
||||||
|
TEST_MACRO(uint32_t, UINT32_C(4294967293), "4294967293");
|
||||||
|
TEST_MACRO(int64_t, INT64_C(616161616161), "616161616161");
|
||||||
|
TEST_MACRO(uint64_t, UINT64_C(9223372036854775807), "9223372036854775807");
|
||||||
|
TEST_MACRO(uint32_t, UINT32_C(0xffff), "ffff", 16);
|
||||||
|
TEST_MACRO(float, 1.0f, "1.0", std::chars_format::fixed, 1);
|
||||||
|
TEST_MACRO(double, 1.0, "1.0", std::chars_format::fixed, 1);
|
||||||
|
TEST_MACRO(bool, true, "true");
|
||||||
|
|
||||||
|
#undef TEST_MACRO
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DialogTestbench() {
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
YYCC::yycc_u8string ret;
|
||||||
|
std::vector<YYCC::yycc_u8string> rets;
|
||||||
|
|
||||||
|
YYCC::DialogHelper::FileDialog params;
|
||||||
|
auto& filters = params.ConfigreFileTypes();
|
||||||
|
filters.Add(YYCC_U8("Microsoft Word (*.docx; *.doc)"), { YYCC_U8("*.docx"), YYCC_U8("*.doc") });
|
||||||
|
filters.Add(YYCC_U8("Microsoft Excel (*.xlsx; *.xls)"), { YYCC_U8("*.xlsx"), YYCC_U8("*.xls") });
|
||||||
|
filters.Add(YYCC_U8("Microsoft PowerPoint (*.pptx; *.ppt)"), { YYCC_U8("*.pptx"), YYCC_U8("*.ppt") });
|
||||||
|
filters.Add(YYCC_U8("Text File (*.txt)"), { YYCC_U8("*.txt") });
|
||||||
|
filters.Add(YYCC_U8("All Files (*.*)"), { YYCC_U8("*.*") });
|
||||||
|
params.SetDefaultFileTypeIndex(0u);
|
||||||
|
if (YYCC::DialogHelper::OpenFileDialog(params, ret)) {
|
||||||
|
Console::FormatLine(YYCC_U8("Open File: %s"), ret.c_str());
|
||||||
|
}
|
||||||
|
if (YYCC::DialogHelper::OpenMultipleFileDialog(params, rets)) {
|
||||||
|
Console::WriteLine(YYCC_U8("Open Multiple Files:"));
|
||||||
|
for (const auto& item : rets) {
|
||||||
|
Console::FormatLine(YYCC_U8("\t%s"), item.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (YYCC::DialogHelper::SaveFileDialog(params, ret)) {
|
||||||
|
Console::FormatLine(YYCC_U8("Save File: %s"), ret.c_str());
|
||||||
|
}
|
||||||
|
params.Clear();
|
||||||
|
if (YYCC::DialogHelper::OpenFolderDialog(params, ret)) {
|
||||||
|
Console::FormatLine(YYCC_U8("Open Folder: %s"), ret.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExceptionTestbench() {
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
YYCC::ExceptionHelper::Register([](const YYCC::yycc_u8string& log_path, const YYCC::yycc_u8string& coredump_path) -> void {
|
||||||
|
MessageBoxW(
|
||||||
|
NULL,
|
||||||
|
YYCC::EncodingHelper::UTF8ToWchar(
|
||||||
|
YYCC::StringHelper::Printf(YYCC_U8("Log generated:\nLog path: %s\nCore dump path: %s"), log_path.c_str(), coredump_path.c_str())
|
||||||
|
).c_str(),
|
||||||
|
L"Fatal Error", MB_OK + MB_ICONERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Perform a div zero exception.
|
||||||
|
#if defined (YYCC_DEBUG_UE_FILTER)
|
||||||
|
// Reference: https://stackoverflow.com/questions/20981982/is-it-possible-to-debug-unhandledexceptionfilters-with-a-debugger
|
||||||
|
__try {
|
||||||
|
// all of code normally inside of main or WinMain here...
|
||||||
|
int i = 1, j = 0;
|
||||||
|
int k = i / j;
|
||||||
|
} __except (YYCC::ExceptionHelper::DebugCallUExceptionImpl(GetExceptionInformation())) {
|
||||||
|
OutputDebugStringW(L"executed filter function\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int i = 1, j = 0;
|
||||||
|
int k = i / j;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
YYCC::ExceptionHelper::Unregister();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WinFctTestbench() {
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
HMODULE test_current_module;
|
||||||
|
Assert((test_current_module = YYCC::WinFctHelper::GetCurrentModule()) != nullptr, YYCC_U8("YYCC::WinFctHelper::GetCurrentModule"));
|
||||||
|
Console::FormatLine(YYCC_U8("Current Module HANDLE: 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR), test_current_module);
|
||||||
|
|
||||||
|
YYCC::yycc_u8string test_temp;
|
||||||
|
Assert(YYCC::WinFctHelper::GetTempDirectory(test_temp), YYCC_U8("YYCC::WinFctHelper::GetTempDirectory"));
|
||||||
|
Console::FormatLine(YYCC_U8("Temp Directory: %s"), test_temp.c_str());
|
||||||
|
|
||||||
|
YYCC::yycc_u8string test_module_name;
|
||||||
|
Assert(YYCC::WinFctHelper::GetModuleFileName(YYCC::WinFctHelper::GetCurrentModule(), test_module_name), YYCC_U8("YYCC::WinFctHelper::GetModuleFileName"));
|
||||||
|
Console::FormatLine(YYCC_U8("Current Module File Name: %s"), test_module_name.c_str());
|
||||||
|
|
||||||
|
YYCC::yycc_u8string test_localappdata_path;
|
||||||
|
Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData"));
|
||||||
|
Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str());
|
||||||
|
|
||||||
|
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(1252)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
|
||||||
|
Assert(!YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(114514)), YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
|
||||||
|
|
||||||
|
// MARK: There is no testbench for MoveFile, CopyFile DeleteFile.
|
||||||
|
// Because they can operate file system files.
|
||||||
|
// And may cause test environment entering unstable status.
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StdPatchTestbench() {
|
||||||
|
|
||||||
|
// Std Path
|
||||||
|
|
||||||
|
std::filesystem::path test_path;
|
||||||
|
for (const auto& strl : c_UTF8TestStrTable) {
|
||||||
|
test_path /= YYCC::StdPatch::ToStdPath(strl);
|
||||||
|
}
|
||||||
|
YYCC::yycc_u8string test_slashed_path(YYCC::StdPatch::ToUTF8Path(test_path));
|
||||||
|
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
std::wstring wdecilmer(1u, std::filesystem::path::preferred_separator);
|
||||||
|
YYCC::yycc_u8string decilmer(YYCC::EncodingHelper::WcharToUTF8(wdecilmer));
|
||||||
|
#else
|
||||||
|
YYCC::yycc_u8string decilmer(1u, std::filesystem::path::preferred_separator);
|
||||||
|
#endif
|
||||||
|
YYCC::yycc_u8string test_joined_path(YYCC::StringHelper::Join(c_UTF8TestStrTable.begin(), c_UTF8TestStrTable.end(), decilmer));
|
||||||
|
|
||||||
|
Assert(test_slashed_path == test_joined_path, YYCC_U8("YYCC::StdPatch::ToStdPath, YYCC::StdPatch::ToUTF8Path"));
|
||||||
|
|
||||||
|
// StartsWith, EndsWith
|
||||||
|
YYCC::yycc_u8string test_starts_ends_with(YYCC_U8("aaabbbccc"));
|
||||||
|
Assert(YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::StartsWith"));
|
||||||
|
Assert(!YYCC::StdPatch::StartsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::StartsWith"));
|
||||||
|
Assert(!YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("aaa")), YYCC_U8("YYCC::StdPatch::EndsWith"));
|
||||||
|
Assert(YYCC::StdPatch::EndsWith(test_starts_ends_with, YYCC_U8("ccc")), YYCC_U8("YYCC::StdPatch::EndsWith"));
|
||||||
|
|
||||||
|
// Contains
|
||||||
|
std::set<int> test_set { 1, 2, 3, 4, 6, 7 };
|
||||||
|
Assert(YYCC::StdPatch::Contains(test_set, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
|
||||||
|
Assert(!YYCC::StdPatch::Contains(test_set, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
|
||||||
|
std::map<int, float> test_map { { 1, 1.0f }, { 4, 4.0f } };
|
||||||
|
Assert(YYCC::StdPatch::Contains(test_map, static_cast<int>(1)), YYCC_U8("YYCC::StdPatch::Contains"));
|
||||||
|
Assert(!YYCC::StdPatch::Contains(test_map, static_cast<int>(5)), YYCC_U8("YYCC::StdPatch::Contains"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TestFlagEnum : uint8_t {
|
||||||
|
Test1 = 0b00000000,
|
||||||
|
Test2 = 0b00000001,
|
||||||
|
Test3 = 0b00000010,
|
||||||
|
Test4 = 0b00000100,
|
||||||
|
Test5 = 0b00001000,
|
||||||
|
Test6 = 0b00010000,
|
||||||
|
Test7 = 0b00100000,
|
||||||
|
Test8 = 0b01000000,
|
||||||
|
Test9 = 0b10000000,
|
||||||
|
Inverted = 0b01111111,
|
||||||
|
Merged = Test3 + Test5,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void EnumHelperTestbench() {
|
||||||
|
TestFlagEnum val;
|
||||||
|
|
||||||
|
Assert(YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5) == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Merge"));
|
||||||
|
|
||||||
|
Assert(YYCC::EnumHelper::Invert(TestFlagEnum::Test9) == TestFlagEnum::Inverted, YYCC_U8("YYCC::EnumHelper::Invert"));
|
||||||
|
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test3);
|
||||||
|
Assert(YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test4);
|
||||||
|
Assert(!YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
||||||
|
|
||||||
|
val = TestFlagEnum::Test3;
|
||||||
|
YYCC::EnumHelper::Add(val, TestFlagEnum::Test5);
|
||||||
|
Assert(val == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Add"));
|
||||||
|
|
||||||
|
val = TestFlagEnum::Merged;
|
||||||
|
YYCC::EnumHelper::Remove(val, TestFlagEnum::Test5);
|
||||||
|
Assert(val == TestFlagEnum::Test3, YYCC_U8("YYCC::EnumHelper::Remove"));
|
||||||
|
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
Assert(YYCC::EnumHelper::Has(val, TestFlagEnum::Test3), YYCC_U8("YYCC::EnumHelper::Has"));
|
||||||
|
Assert(!YYCC::EnumHelper::Has(val, TestFlagEnum::Test4), YYCC_U8("YYCC::EnumHelper::Has"));
|
||||||
|
|
||||||
|
Assert(!YYCC::EnumHelper::Bool(TestFlagEnum::Test1), YYCC_U8("YYCC::EnumHelper::Bool"));
|
||||||
|
Assert(YYCC::EnumHelper::Bool(TestFlagEnum::Test2), YYCC_U8("YYCC::EnumHelper::Bool"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VersionMacroTestbench() {
|
||||||
|
Assert(YYCC_VERCMP_E(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_E"));
|
||||||
|
Assert(!YYCC_VERCMP_NE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NE"));
|
||||||
|
Assert(YYCC_VERCMP_G(1, 2, 3, 0, 2, 5), YYCC_U8("YYCC_VERCMP_G"));
|
||||||
|
Assert(YYCC_VERCMP_GE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_GE"));
|
||||||
|
Assert(YYCC_VERCMP_NL(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NL"));
|
||||||
|
Assert(YYCC_VERCMP_L(0, 2, 5, 1, 2, 3), YYCC_U8("YYCC_VERCMP_L"));
|
||||||
|
Assert(YYCC_VERCMP_LE(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_LE"));
|
||||||
|
Assert(YYCC_VERCMP_NG(1, 2, 3, 1, 2, 3), YYCC_U8("YYCC_VERCMP_NG"));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TestEnum : int8_t {
|
||||||
|
Test1, Test2, Test3
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestConfigManager {
|
||||||
|
public:
|
||||||
|
TestConfigManager() :
|
||||||
|
m_IntSetting(YYCC_U8("int-setting"), INT32_C(0)),
|
||||||
|
m_FloatSetting(YYCC_U8("float-setting"), 0.0f),
|
||||||
|
m_StringSetting(YYCC_U8("string-setting"), YYCC_U8("")),
|
||||||
|
m_BoolSetting(YYCC_U8("bool-setting"), false),
|
||||||
|
m_ClampedFloatSetting(YYCC_U8("clamped-float-setting"), 0.0f, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
||||||
|
m_EnumSetting(YYCC_U8("enum-setting"), TestEnum::Test1),
|
||||||
|
m_CoreManager(YYCC_U8("test.cfg"), UINT64_C(0), {
|
||||||
|
&m_IntSetting, &m_FloatSetting, &m_StringSetting, &m_BoolSetting, &m_ClampedFloatSetting, &m_EnumSetting
|
||||||
|
}) {}
|
||||||
|
~TestConfigManager() {}
|
||||||
|
|
||||||
|
void PrintSettings() {
|
||||||
|
Console::WriteLine(YYCC_U8("Config Manager Settings:"));
|
||||||
|
|
||||||
|
Console::FormatLine(YYCC_U8("\tint-setting: %" PRIi32), m_IntSetting.Get());
|
||||||
|
Console::FormatLine(YYCC_U8("\tfloat-setting: %f"), m_FloatSetting.Get());
|
||||||
|
Console::FormatLine(YYCC_U8("\tstring-setting: %s"), m_StringSetting.Get().c_str());
|
||||||
|
|
||||||
|
Console::FormatLine(YYCC_U8("\tbool-setting: %s"), m_BoolSetting.Get() ? YYCC_U8("true") : YYCC_U8("false"));
|
||||||
|
Console::FormatLine(YYCC_U8("\tfloat-setting: %f"), m_ClampedFloatSetting.Get());
|
||||||
|
Console::FormatLine(YYCC_U8("\tenum-setting: %" PRIi8), static_cast<std::underlying_type_t<TestEnum>>(m_EnumSetting.Get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
YYCC::ConfigManager::NumberSetting<int32_t> m_IntSetting;
|
||||||
|
YYCC::ConfigManager::NumberSetting<float> m_FloatSetting;
|
||||||
|
YYCC::ConfigManager::StringSetting m_StringSetting;
|
||||||
|
|
||||||
|
YYCC::ConfigManager::NumberSetting<bool> m_BoolSetting;
|
||||||
|
YYCC::ConfigManager::NumberSetting<float> m_ClampedFloatSetting;
|
||||||
|
YYCC::ConfigManager::NumberSetting<TestEnum> m_EnumSetting;
|
||||||
|
|
||||||
|
YYCC::ConfigManager::CoreManager m_CoreManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ConfigManagerTestbench() {
|
||||||
|
// init cfg manager
|
||||||
|
TestConfigManager test;
|
||||||
|
|
||||||
|
// test constraint works
|
||||||
|
Assert(!test.m_ClampedFloatSetting.Set(2.0f), YYCC_U8("YYCC::Constraints::Constraint"));
|
||||||
|
Assert(test.m_ClampedFloatSetting.Get() == 0.0f, YYCC_U8("YYCC::Constraints::Constraint"));
|
||||||
|
|
||||||
|
// test modify settings
|
||||||
|
#define TEST_MACRO(member_name, set_val) { \
|
||||||
|
Assert(test.member_name.Set(set_val), YYCC_U8("YYCC::ConfigManager::AbstractSetting::Set")); \
|
||||||
|
Assert(test.member_name.Get() == set_val, YYCC_U8("YYCC::ConfigManager::AbstractSetting::Set")); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_MACRO(m_IntSetting, INT32_C(114));
|
||||||
|
TEST_MACRO(m_FloatSetting, 2.0f);
|
||||||
|
TEST_MACRO(m_StringSetting, YYCC_U8("fuck"));
|
||||||
|
TEST_MACRO(m_BoolSetting, true);
|
||||||
|
TEST_MACRO(m_ClampedFloatSetting, 0.5f);
|
||||||
|
TEST_MACRO(m_EnumSetting, TestEnum::Test2);
|
||||||
|
|
||||||
|
#undef TEST_MACRO
|
||||||
|
|
||||||
|
// test save
|
||||||
|
test.PrintSettings();
|
||||||
|
Assert(test.m_CoreManager.Save(), YYCC_U8("YYCC::ConfigManager::CoreManager::Save"));
|
||||||
|
|
||||||
|
// test reset
|
||||||
|
test.m_CoreManager.Reset();
|
||||||
|
test.PrintSettings();
|
||||||
|
Assert(test.m_IntSetting.Get() == INT32_C(0), YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
Assert(test.m_FloatSetting.Get() == 0.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
Assert(test.m_StringSetting.Get() == YYCC_U8(""), YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
Assert(test.m_BoolSetting.Get() == false, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
Assert(test.m_ClampedFloatSetting.Get() == 0.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
Assert(test.m_EnumSetting.Get() == TestEnum::Test1, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
|
||||||
|
// test load
|
||||||
|
YYCC::ConfigManager::ConfigLoadResult wrong_result = YYCC::EnumHelper::Merge(
|
||||||
|
YYCC::ConfigManager::ConfigLoadResult::ItemError,
|
||||||
|
YYCC::ConfigManager::ConfigLoadResult::BrokenFile
|
||||||
|
);
|
||||||
|
Assert(!YYCC::EnumHelper::Has(test.m_CoreManager.Load(), wrong_result), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
test.PrintSettings();
|
||||||
|
Assert(test.m_IntSetting.Get() == INT32_C(114), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
Assert(test.m_FloatSetting.Get() == 2.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
Assert(test.m_StringSetting.Get() == YYCC_U8("fuck"), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
Assert(test.m_BoolSetting.Get() == true, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
Assert(test.m_ClampedFloatSetting.Get() == 0.5f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
Assert(test.m_EnumSetting.Get() == TestEnum::Test2, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestArgParser {
|
||||||
|
public:
|
||||||
|
TestArgParser() :
|
||||||
|
m_IntArgument(YYCC_U8("int"), YYCC_U8_CHAR('i'), YYCC_U8("integral argument"), YYCC_U8("114514")),
|
||||||
|
m_FloatArgument(nullptr, YYCC_U8_CHAR('f'), nullptr, nullptr, true),
|
||||||
|
m_StringArgument(YYCC_U8("string"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true),
|
||||||
|
m_BoolArgument(nullptr, YYCC_U8_CHAR('b'), nullptr),
|
||||||
|
m_ClampedFloatArgument(YYCC_U8("clamped-float"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
||||||
|
m_OptionContext(YYCC_U8("TestArgParser"), YYCC_U8("This is the testbench of argument parser."), {
|
||||||
|
&m_IntArgument, &m_FloatArgument, &m_StringArgument,
|
||||||
|
&m_BoolArgument, &m_ClampedFloatArgument
|
||||||
|
}) {}
|
||||||
|
~TestArgParser() {}
|
||||||
|
|
||||||
|
YYCC::ArgParser::NumberArgument<int32_t> m_IntArgument;
|
||||||
|
YYCC::ArgParser::NumberArgument<float> m_FloatArgument;
|
||||||
|
YYCC::ArgParser::StringArgument m_StringArgument;
|
||||||
|
|
||||||
|
YYCC::ArgParser::SwitchArgument m_BoolArgument;
|
||||||
|
YYCC::ArgParser::NumberArgument<float> m_ClampedFloatArgument;
|
||||||
|
|
||||||
|
YYCC::ArgParser::OptionContext m_OptionContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ArgParserTestbench(int argc, char* argv[]) {
|
||||||
|
// test command line getter
|
||||||
|
{
|
||||||
|
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromStd"));
|
||||||
|
auto result = YYCC::ArgParser::ArgumentList::CreateFromStd(argc, argv);
|
||||||
|
for (result.Reset(); !result.IsEOF(); result.Next()) {
|
||||||
|
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
{
|
||||||
|
YYCC::ConsoleHelper::WriteLine(YYCC_U8("YYCC::ArgParser::ArgumentList::CreateFromWin32"));
|
||||||
|
auto result = YYCC::ArgParser::ArgumentList::CreateFromWin32();
|
||||||
|
for (result.Reset(); !result.IsEOF(); result.Next()) {
|
||||||
|
YYCC::ConsoleHelper::FormatLine(YYCC_U8("\t%s"), result.Argument().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// test option context
|
||||||
|
// init option context
|
||||||
|
TestArgParser test;
|
||||||
|
|
||||||
|
#define PREPARE_DATA(...) const char* test_argv[] = { __VA_ARGS__ }; \
|
||||||
|
auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(sizeof(test_argv) / sizeof(char*), const_cast<char**>(test_argv));
|
||||||
|
|
||||||
|
// normal test
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i", "114514");
|
||||||
|
Assert(test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_IntArgument.IsCaptured() && test.m_IntArgument.Get() == UINT32_C(114514), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(!test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(!test.m_FloatArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(!test.m_StringArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(!test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(!test.m_ClampedFloatArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// no argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// error argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-?", "114514");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// lost argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// dplicated assign
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i", "114514" "--int", "114514");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// extra useless argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i", "114514" "1919810");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// invalid clamp argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i", "114514", "--clamped-float", "114.0");
|
||||||
|
Assert(!test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
// full argument
|
||||||
|
{
|
||||||
|
PREPARE_DATA("exec", "-i", "114514", "-f", "2.0", "--string", "fuck", "-b", "--clamped-float", "0.5");
|
||||||
|
Assert(test.m_OptionContext.Parse(al), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_IntArgument.IsCaptured() && test.m_IntArgument.Get() == UINT32_C(114514), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_FloatArgument.IsCaptured() && test.m_FloatArgument.Get() == 2.0f, YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_StringArgument.IsCaptured() && test.m_StringArgument.Get() == YYCC_U8("fuck"), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_BoolArgument.IsCaptured(), YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
Assert(test.m_ClampedFloatArgument.IsCaptured() && test.m_ClampedFloatArgument.Get() == 0.5f, YYCC_U8("YYCC::ArgParser::OptionContext::Parse"));
|
||||||
|
test.m_OptionContext.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help text
|
||||||
|
test.m_OptionContext.Help();
|
||||||
|
|
||||||
|
#undef PREPARE_DATA
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
#if YYCC_VERCMP_NE(YYCC_VER_MAJOR, YYCC_VER_MINOR, YYCC_VER_PATCH, 1, 3 ,0)
|
||||||
|
#error "The YYCC library used when compiling is not match code expected, this may cause build error."
|
||||||
|
#error "If you trust it, please annotate these preprocessor statement, otherwise please contact developer."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// common testbench
|
||||||
|
// normal
|
||||||
|
YYCCTestbench::EncodingTestbench();
|
||||||
|
YYCCTestbench::StringTestbench();
|
||||||
|
YYCCTestbench::ParserTestbench();
|
||||||
|
YYCCTestbench::WinFctTestbench();
|
||||||
|
YYCCTestbench::StdPatchTestbench();
|
||||||
|
YYCCTestbench::EnumHelperTestbench();
|
||||||
|
YYCCTestbench::VersionMacroTestbench();
|
||||||
|
// advanced
|
||||||
|
YYCCTestbench::ConfigManagerTestbench();
|
||||||
|
YYCCTestbench::ArgParserTestbench(argc, argv);
|
||||||
|
|
||||||
|
// testbench which may terminal app or ordering input
|
||||||
|
YYCCTestbench::ConsoleTestbench();
|
||||||
|
YYCCTestbench::DialogTestbench();
|
||||||
|
YYCCTestbench::ExceptionTestbench();
|
||||||
|
}
|
49
testbench/yycc/constraint.cpp
Normal file
49
testbench/yycc/constraint.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yycc.hpp>
|
||||||
|
#include <yycc/constraint.hpp>
|
||||||
|
#include <yycc/prelude/rust.hpp>
|
||||||
|
|
||||||
|
#define CONSTRAINT ::yycc::constraint::Constraint
|
||||||
|
|
||||||
|
namespace yycctest::constraint {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool check(const T& value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T clamp(const T& value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Constraint, Normal) {
|
||||||
|
CONSTRAINT<u32> instance(check<u32>, clamp<u32>);
|
||||||
|
EXPECT_TRUE(instance.support_check());
|
||||||
|
EXPECT_TRUE(instance.support_clamp());
|
||||||
|
EXPECT_FALSE(instance.check(0));
|
||||||
|
EXPECT_EQ(instance.clamp(0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Constraint, SomeNone) {
|
||||||
|
{
|
||||||
|
CONSTRAINT<u32> instance(check<u32>, nullptr);
|
||||||
|
EXPECT_TRUE(instance.support_check());
|
||||||
|
EXPECT_FALSE(instance.support_clamp());
|
||||||
|
EXPECT_FALSE(instance.check(0));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
CONSTRAINT<u32> instance(nullptr, clamp<u32>);
|
||||||
|
EXPECT_FALSE(instance.support_check());
|
||||||
|
EXPECT_TRUE(instance.support_clamp());
|
||||||
|
EXPECT_EQ(instance.clamp(0), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Constraint, AllNone) {
|
||||||
|
CONSTRAINT<u32> instance(nullptr, nullptr);
|
||||||
|
EXPECT_FALSE(instance.support_check());
|
||||||
|
EXPECT_FALSE(instance.support_clamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
testbench/yycc/constraint/builder.cpp
Normal file
5
testbench/yycc/constraint/builder.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace yycctest::constraint::builder {
|
||||||
|
|
||||||
|
}
|
2
testbench/yycc/string.cpp
Normal file
2
testbench/yycc/string.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
namespace yycctest::string {}
|
37
testbench/yycc/string/op.cpp
Normal file
37
testbench/yycc/string/op.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yycc.hpp>
|
||||||
|
#include <yycc/string/op.hpp>
|
||||||
|
#include <yycc/string/reinterpret.hpp>
|
||||||
|
|
||||||
|
#define OP ::yycc::string::op
|
||||||
|
|
||||||
|
namespace yycctest::string::op {
|
||||||
|
|
||||||
|
TEST(StringOp, Printf) {
|
||||||
|
auto rv = OP::printf(YYCC_U8("%s == %s"), YYCC_U8("Hello World"), YYCC_U8("Hello, world"));
|
||||||
|
EXPECT_EQ(rv, YYCC_U8("Hello World == Hello, world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringOp, Replace) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringOp, Lower) {
|
||||||
|
auto rv = OP::lower(YYCC_U8("LOWER"));
|
||||||
|
EXPECT_EQ(rv, YYCC_U8("lower"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringOp, Upper) {
|
||||||
|
auto rv = OP::upper(YYCC_U8("upper"));
|
||||||
|
EXPECT_EQ(rv, YYCC_U8("UPPER"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringOp, Join) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringOp, Split) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
testbench/yycc/string/reinterpret.cpp
Normal file
6
testbench/yycc/string/reinterpret.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yycc.hpp>
|
||||||
|
|
||||||
|
namespace yycctest::string::reinterpret {
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user