OSDN Git Service

Fix crash when registry is set to an unexpected value (2)
authorTakashi Sawanaka <sdottaka@users.sourceforge.net>
Sun, 8 Aug 2021 05:48:43 +0000 (14:48 +0900)
committerTakashi Sawanaka <sdottaka@users.sourceforge.net>
Sun, 8 Aug 2021 05:48:43 +0000 (14:48 +0900)
Testing/GoogleTest/GUITests/ConfigTest.cpp [new file with mode: 0644]

diff --git a/Testing/GoogleTest/GUITests/ConfigTest.cpp b/Testing/GoogleTest/GUITests/ConfigTest.cpp
new file mode 100644 (file)
index 0000000..e25c916
--- /dev/null
@@ -0,0 +1,547 @@
+/**
+ * @file  ConfigTest.cpp
+ *
+ * @brief Implementation for Config testcase.
+ */
+
+#include "pch.h"
+#include "Resource.h"
+#define OP(x) (_T(x), sizeof(_T(x))/sizeof(TCHAR) - 1)
+#include "OptionsDef.h"
+#include "varprop.h"
+#include <variant>
+
+namespace
+{
+
+       using namespace GUITestUtils;
+
+       class ConfigTest : public CommonTest
+       {
+       public:
+               ConfigTest()
+               {
+               }
+
+               virtual ~ConfigTest()
+               {
+               }
+
+               static void SetUpTestCase()
+               {
+                       // You can do set-up work for each test here.
+               }
+
+               static void TearDownTestCase()
+               {
+                       // You can do clean-up work     that doesn't throw exceptions here.
+               }
+
+               // If   the     constructor     and     destructor are not enough for setting up
+               // and cleaning up each test, you can define the following methods:
+               virtual void SetUp()
+               {
+                       // Code here will be called     immediately     after the constructor (right
+                       // before each test).
+               }
+
+               virtual void TearDown()
+               {
+                       // Code here will be called     immediately     after each test (right
+                       // before the destructor).
+               }
+
+               // Objects declared here can be used by all tests in the test case for Foo.
+       };
+
+       struct Option
+       {
+               const std::wstring name;
+               varprop::VT_TYPE type;
+               std::vector<int> iValues;
+               const std::vector<std::wstring> sValues;
+       } options[] =
+       {
+               // User's language
+               { OPT_SELECTED_LANGUAGE, varprop::VT_INT, {
+                       MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+                       MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA),
+                       MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED),
+                       MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL),
+                       MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH),
+                       MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_FINNISH, SUBLANG_FINNISH_FINLAND),
+                       MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH),
+                       MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),
+                       MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN),
+                       MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE),
+                       MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN),
+                       MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC),
+                       MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA),
+                       MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN),
+                       MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT),
+                       MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT),
+                       }, {} },
+               { OPT_SHOW_UNIQUE_LEFT, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_UNIQUE_MIDDLE, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_UNIQUE_RIGHT, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_DIFFERENT, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_IDENTICAL, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_BINARIES, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_SKIPPED, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_DIFFERENT_LEFT_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_DIFFERENT_MIDDLE_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_DIFFERENT_RIGHT_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_MISSING_LEFT_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_MISSING_MIDDLE_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_MISSING_RIGHT_ONLY, varprop::VT_BOOL, {}, {} },
+               { OPT_TREE_MODE, varprop::VT_BOOL, {}, {} },
+               // Show/hide toolbar/statusbar/tabbar
+               { OPT_SHOW_TOOLBAR, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_STATUSBAR, varprop::VT_BOOL, {}, {} },
+               { OPT_SHOW_TABBAR, varprop::VT_BOOL, {}, {} },
+               { OPT_TOOLBAR_SIZE, varprop::VT_INT, {0, 1, 2}, {} },
+               { OPT_RESIZE_PANES, varprop::VT_BOOL, {}, {} },
+               //
+               { OPT_SYNTAX_HIGHLIGHT, varprop::VT_BOOL, {}, {} },
+               { OPT_VIEW_WHITESPACE, varprop::VT_BOOL, {}, {} },
+               { OPT_VIEW_EOL, varprop::VT_BOOL, {}, {} },
+               { OPT_SCROLL_TO_FIRST, varprop::VT_BOOL, {}, {} },
+               { OPT_SCROLL_TO_FIRST_INLINE_DIFF, varprop::VT_BOOL, {}, {} },
+               { OPT_RENDERING_MODE, varprop::VT_INT, {0, 1, 2, 3, 4, 6}, {} },
+               //
+               { OPT_WORDDIFF_HIGHLIGHT, varprop::VT_BOOL, {}, {} },
+               { OPT_BREAK_ON_WORDS, varprop::VT_BOOL, {}, {} },
+               { OPT_BREAK_TYPE, varprop::VT_INT, {0, 1}, {} },
+               { OPT_BREAK_SEPARATORS, varprop::VT_STRING, {}, {L"", L".,:; ? []() {} <=> `'!\"#$%&^~\\|@+-*/"}},
+               // Backup options
+               { OPT_BACKUP_FOLDERCMP, varprop::VT_BOOL, {}, {} },
+               { OPT_BACKUP_FILECMP, varprop::VT_BOOL, {}, {} },
+               { OPT_BACKUP_LOCATION, varprop::VT_INT, {0, 1}, {} },
+               { OPT_BACKUP_GLOBALFOLDER, varprop::VT_STRING, {}, {L"", L"c:\\tmp"}},
+               { OPT_BACKUP_ADD_BAK, varprop::VT_BOOL, {}, {} },
+               { OPT_BACKUP_ADD_TIME, varprop::VT_BOOL, {}, {} },
+               //
+               { OPT_DIRVIEW_SORT_COLUMN, varprop::VT_INT, {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {} },
+               { OPT_DIRVIEW_SORT_COLUMN3, varprop::VT_INT, {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {} },
+               { OPT_DIRVIEW_SORT_ASCENDING, varprop::VT_BOOL, {}, {} },
+               { OPT_DIRVIEW_EXPAND_SUBDIRS, varprop::VT_BOOL, {}, {} },
+               { OPT_DIRVIEW_COLUMN_ORDERS, varprop::VT_STRING, {}, { L"", L"0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26"}},
+               { OPT_DIRVIEW_COLUMN_WIDTHS, varprop::VT_STRING, {}, {L"", L"222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222"}},
+               { OPT_DIRVIEW3_COLUMN_ORDERS, varprop::VT_STRING, {}, { L"", L"0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26"}},
+               { OPT_DIRVIEW3_COLUMN_WIDTHS, varprop::VT_STRING, {}, {L"", L"222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222 222"}},
+               // Window / Pane
+               { OPT_ACTIVE_FRAME_MAX, varprop::VT_BOOL, {}, {} },
+               { OPT_ACTIVE_PANE, varprop::VT_INT, {-1, 0, 1, 2}, {} },
+               // Folder Compare Report
+               { OPT_REPORTFILES_REPORTTYPE, varprop::VT_INT, {0, 1, 2, 3}, {} },
+               { OPT_REPORTFILES_COPYTOCLIPBOARD, varprop::VT_BOOL, {}, {} },
+               { OPT_REPORTFILES_INCLUDEFILECMPREPORT, varprop::VT_BOOL, {}, {} },
+               //  File compare
+               { OPT_AUTOMATIC_RESCAN, varprop::VT_BOOL, {}, {} },
+               { OPT_ALLOW_MIXED_EOL, varprop::VT_BOOL, {}, {} },
+               { OPT_COPY_FULL_LINE, varprop::VT_BOOL, {}, {} },
+               { OPT_TAB_SIZE, varprop::VT_INT, {1, 2, 4, 8, 128}, {} },
+               { OPT_TAB_TYPE, varprop::VT_INT, {0, 1}, {} },
+               { OPT_WORDWRAP, varprop::VT_BOOL, {}, {} },
+               { OPT_VIEW_LINENUMBERS, varprop::VT_BOOL, {}, {} },
+               { OPT_VIEW_FILEMARGIN, varprop::VT_BOOL, {}, {} },
+               { OPT_DIFF_CONTEXT, varprop::VT_INT, {0, 1, 3, 5, 7, 9}, {} },
+               { OPT_INVERT_DIFF_CONTEXT, varprop::VT_BOOL, {}, {} },
+               { OPT_EXT_EDITOR_CMD, varprop::VT_STRING, {}, {L"", L"notepad.exe"}},
+               { OPT_USE_RECYCLE_BIN, varprop::VT_BOOL, {}, {} },
+               { OPT_SINGLE_INSTANCE, varprop::VT_INT, {0, 1, 2}, {} },
+               { OPT_MERGE_MODE, varprop::VT_BOOL, {}, {} },
+               { OPT_CLOSE_WITH_ESC, varprop::VT_INT, {0, 1, 2}, {} },
+               { OPT_CLOSE_WITH_OK, varprop::VT_BOOL, {}, {} },
+               { OPT_VERIFY_OPEN_PATHS, varprop::VT_BOOL, {}, {} },
+               { OPT_AUTO_COMPLETE_SOURCE, varprop::VT_INT, {0, 1, 2}, {} },
+               { OPT_IGNORE_SMALL_FILETIME, varprop::VT_BOOL, {}, {} },
+               { OPT_ASK_MULTIWINDOW_CLOSE, varprop::VT_BOOL, {}, {} },
+               { OPT_PRESERVE_FILETIMES, varprop::VT_BOOL, {}, {} },
+               { OPT_CP_DEFAULT_CUSTOM, varprop::VT_INT, {1252, 1200, 65001}, {} },
+               { OPT_CP_DETECT, varprop::VT_INT, 
+                       {0,
+                        1,
+                        static_cast<int>(2 | (50001u << 16)),
+                        static_cast<int>(2 | (50936u << 16)),
+                        static_cast<int>(2 | (50950u << 16)),
+                        static_cast<int>(2 | (50932u << 16)),
+                        static_cast<int>(2 | (50949u << 16)),
+                        static_cast<int>(3 | (50001u << 16)),
+                        static_cast<int>(3 | (50936u << 16)),
+                        static_cast<int>(3 | (50950u << 16)),
+                        static_cast<int>(3 | (50932u << 16)),
+                        static_cast<int>(3 | (50949u << 16)),
+                       }, {} },
+               { OPT_PRESERVE_FILETIMES, varprop::VT_BOOL, {}, {} },
+               { OPT_PROJECTS_PATH, varprop::VT_STRING, {}, {L"", L"c:\\tmp"}},
+               { OPT_USE_SYSTEM_TEMP_PATH, varprop::VT_BOOL, {}, {}},
+               { OPT_CUSTOM_TEMP_PATH, varprop::VT_STRING, {}, {L"", L"c:\\tmp"}},
+               { OPT_SPLIT_HORIZONTALLY, varprop::VT_BOOL, {}, {}},
+               { OPT_FILE_SIZE_THRESHOLD, varprop::VT_INT, {0xffff, 0x7fffffff}, {}},
+               //
+               { OPT_DIRCLR_USE_COLORS, varprop::VT_BOOL, {}, {}},
+               { OPT_COLOR_SCHEME, varprop::VT_STRING, {}, {L"", L"Default", L"Modern", L"Solarized Dark", L"Solarized Light"}},
+               // Compare options
+               { OPT_CMP_IGNORE_WHITESPACE, varprop::VT_INT, {0, 1, 2}, {}},
+               { OPT_CMP_IGNORE_BLANKLINES, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_FILTER_COMMENTLINES, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IGNORE_CASE, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IGNORE_EOL, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IGNORE_CODEPAGE, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_METHOD, varprop::VT_INT, {0, 1, 2, 3, 4, 5}, {}},
+               { OPT_CMP_MOVED_BLOCKS, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_MATCH_SIMILAR_LINES, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_STOP_AFTER_FIRST, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_QUICK_LIMIT, varprop::VT_INT, {0, 1, 4, 1024}, {}},
+               { OPT_CMP_BINARY_LIMIT, varprop::VT_INT, {0, 1, 4, 1024}, {}},
+               { OPT_CMP_COMPARE_THREADS, varprop::VT_INT, {-1, 1, 2}, {}},
+               { OPT_CMP_IGNORE_REPARSE_POINTS, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_INCLUDE_SUBDIRS, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_DIFF_ALGORITHM, varprop::VT_INT, {0, 1, 2, 3}, {}},
+               { OPT_CMP_INDENT_HEURISTIC, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_COMPLETELY_BLANK_OUT_IGNORED_CHANGES, varprop::VT_BOOL, {}, {}},
+               // Image Compare options
+               { OPT_CMP_IMG_FILEPATTERNS, varprop::VT_STRING, {}, {L"", L"*.bmp;*.cut;*.dds;*.exr;*.g3;*.gif;*.hdr;*.ico;*.iff;*.lbm;*.j2k;*.j2c;*.jng;*.jp2;*.jpg;*.jif;*.jpeg;*.jpe;*.jxr;*.wdp;*.hdp;*.koa;*.mng;*.pcd;*.pcx;*.pfm;*.pct;*.pict;*.pic;*.png;*.pbm;*.pgm;*.ppm;*.psd;*.ras;*.sgi;*.rgb;*.rgba;*.bw;*.tga;*.targa;*.tif;*.tiff;*.wap;*.wbmp;*.wbm;*.webp;*.xbm;*.xpm"}},
+               { OPT_CMP_IMG_SHOWDIFFERENCES, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IMG_OVERLAYMODE, varprop::VT_INT, {0, 1, 2, 3}, {}},
+               { OPT_CMP_IMG_OVERLAYALPHA, varprop::VT_INT, {0, 30, 70, 100}, {}},
+               { OPT_CMP_IMG_DRAGGING_MODE, varprop::VT_INT, {0, 1, 2, 3, 4, 5}, {}},
+               { OPT_CMP_IMG_ZOOM, varprop::VT_INT, {1, 50, 100, 200, 800}, {}},
+               { OPT_CMP_IMG_USEBACKCOLOR, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IMG_BACKCOLOR, varprop::VT_INT, {0, 0xffffff}, {}},
+               { OPT_CMP_IMG_DIFFBLOCKSIZE, varprop::VT_INT, {1, 2, 8, 32}, {}},
+               { OPT_CMP_IMG_DIFFCOLORALPHA, varprop::VT_INT, {0, 30, 70, 100}, {}},
+               { OPT_CMP_IMG_THRESHOLD, varprop::VT_INT, {0, 50, 100, 441}, {}},
+               { OPT_CMP_IMG_INSERTIONDELETIONDETECTION_MODE, varprop::VT_INT, {0, 1, 2}, {}},
+               { OPT_CMP_IMG_VECTOR_IMAGE_ZOOM_RATIO, varprop::VT_INT, {1, 50, 100, 200, 800}, {}},
+               { OPT_CMP_ENABLE_IMGCMP_IN_DIRCMP, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_IMG_OCR_RESULT_TYPE, varprop::VT_INT, {0, 1, 2}, {}},
+               // Binary options
+               { OPT_CMP_BIN_FILEPATTERNS, varprop::VT_STRING, {}, {L"", L"*.bin;*.frx"}},
+               // Table options
+               { OPT_CMP_CSV_FILEPATTERNS, varprop::VT_STRING, {}, {L"", L"*.csv"}},
+               { OPT_CMP_TSV_FILEPATTERNS, varprop::VT_STRING, {}, {L"", L"*.tsv"}},
+               { OPT_CMP_DSV_FILEPATTERNS, varprop::VT_STRING, {}, {L"", L"*.ssv"}},
+               { OPT_CMP_DSV_DELIM_CHAR, varprop::VT_STRING, {}, {L"", L";"}},
+               { OPT_CMP_TBL_ALLOW_NEWLINES_IN_QUOTES, varprop::VT_BOOL, {}, {}},
+               { OPT_CMP_TBL_QUOTE_CHAR, varprop::VT_STRING, {}, {L"", L"\""}},
+               // Are regular expression linefilters enabled?
+               { OPT_LINEFILTER_ENABLED, varprop::VT_BOOL, {}, {}},
+               // Currently selected filefilter
+               { OPT_FILEFILTER_CURRENT, varprop::VT_STRING, {}, {L"", L"*.*", L"Visual C++ loose"}},
+               { OPT_FILTER_USERPATH, varprop::VT_STRING, {}, {L"", L"c:\\tmp"}},
+               { OPT_FILEFILTER_SHARED, varprop::VT_BOOL, {}, {}},
+               // Substitution Filters
+               { OPT_SUBSTITUTION_FILTERS_ENABLED, varprop::VT_BOOL, {}, {}},
+               // Archive support
+               { OPT_ARCHIVE_ENABLE, varprop::VT_BOOL, {}, {}},
+               { OPT_ARCHIVE_PROBETYPE, varprop::VT_BOOL, {}, {}},
+               { OPT_ARCHIVE_FILTER_INDEX, varprop::VT_INT, {0, 1, 2, 12}, {}},
+               // Patch Creator
+               { OPT_PATCHCREATOR_PATCH_STYLE, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_CONTEXT_LINES, varprop::VT_INT, {0, 1, 2, 3, 5, 7}, {}},
+               { OPT_PATCHCREATOR_CASE_SENSITIVE, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_EOL_SENSITIVE, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_IGNORE_BLANK_LINES, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_WHITESPACE, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_OPEN_TO_EDITOR, varprop::VT_BOOL, {}, {}},
+               { OPT_PATCHCREATOR_INCLUDE_CMD_LINE, varprop::VT_BOOL, {}, {}},
+               // Plugins
+               { OPT_PLUGINS_ENABLED, varprop::VT_BOOL, {}, {}},
+               { OPT_PLUGINS_CUSTOM_SETTINGS_LIST, varprop::VT_STRING, {}, {L"EDITOR_SCRIPT.PrettifyHTML=arguments:-indent --tab-size 1 --indent-spaces 1 -wrap 0 --sort-attributes alpha \tFILE_PACK_UNPACK.PrettifyHTML=arguments:-indent --indent-attributes yes --tab-size 2 --indent-spaces 2 -wrap 0 --sort-attributes alpha     FILE_PACK_UNPACK.PrettifyXML=arguments:-xml -indent --indent-attributes yes --tab-size 2 --indent-spaces 2 -wrap 0 --sort-attributes alpha|automatic:true       FILE_PACK_UNPACK.PrettifyJSON=automatic:true"}},
+               { OPT_PLUGINS_UNPACKER_MODE, varprop::VT_BOOL, {}, {}},
+               { OPT_PLUGINS_PREDIFFER_MODE, varprop::VT_BOOL, {}, {}},
+               { OPT_PLUGINS_UNPACK_DONT_CHECK_EXTENSION, varprop::VT_BOOL, {}, {}},
+               { OPT_PLUGINS_OPEN_IN_SAME_FRAME_TYPE, varprop::VT_BOOL, {}, {}},
+               // Startup options
+               { OPT_SHOW_SELECT_FILES_AT_STARTUP, varprop::VT_BOOL, {}, {}},
+               // MDI Tab Bar
+               { OPT_TABBAR_AUTO_MAXWIDTH, varprop::VT_BOOL, {}, {}},
+               // MRU
+               { OPT_MRU_MAX, varprop::VT_INT, {0, 1, 9}, {}},
+               // Font options
+               { OPT_FONT_FILECMP + OPT_FONT_USECUSTOM, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_POINTSIZE, varprop::VT_INT, {0, 12, 72}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_HEIGHT, varprop::VT_INT, {0, -23, -95}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_ESCAPEMENT, varprop::VT_INT, {0, 900}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_ORIENTATION, varprop::VT_INT, {0, 900}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_WEIGHT, varprop::VT_INT, {0, 400, 700, 1000}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_ITALIC, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_UNDERLINE, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_STRIKEOUT, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_CHARSET, varprop::VT_INT, {ANSI_CHARSET, DEFAULT_CHARSET, SYMBOL_CHARSET, SHIFTJIS_CHARSET, HANGUL_CHARSET, GB2312_CHARSET, CHINESEBIG5_CHARSET, JOHAB_CHARSET, HEBREW_CHARSET, ARABIC_CHARSET, GREEK_CHARSET, TURKISH_CHARSET, VIETNAMESE_CHARSET, THAI_CHARSET, EASTEUROPE_CHARSET, RUSSIAN_CHARSET, MAC_CHARSET, BALTIC_CHARSET, OEM_CHARSET}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_OUTPRECISION, varprop::VT_INT, {OUT_DEFAULT_PRECIS, OUT_STRING_PRECIS, OUT_CHARACTER_PRECIS, OUT_STROKE_PRECIS, OUT_TT_PRECIS, OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, OUT_TT_ONLY_PRECIS, OUT_OUTLINE_PRECIS, OUT_SCREEN_OUTLINE_PRECIS, OUT_PS_ONLY_PRECIS}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_CLIPPRECISION, varprop::VT_INT, {CLIP_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS, CLIP_STROKE_PRECIS, CLIP_LH_ANGLES, CLIP_TT_ALWAYS, CLIP_DFA_DISABLE, CLIP_EMBEDDED}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_QUALITY, varprop::VT_INT, {DEFAULT_QUALITY, DRAFT_QUALITY, PROOF_QUALITY, NONANTIALIASED_QUALITY, ANTIALIASED_QUALITY, CLEARTYPE_QUALITY, CLEARTYPE_NATURAL_QUALITY}, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_PITCHANDFAMILY, varprop::VT_INT, {DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH, }, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_PITCHANDFAMILY, varprop::VT_INT, 
+                       {
+                               DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH,
+                               DEFAULT_PITCH | FF_ROMAN, FIXED_PITCH | FF_ROMAN, VARIABLE_PITCH | FF_ROMAN,
+                               DEFAULT_PITCH | FF_SWISS, FIXED_PITCH | FF_SWISS, VARIABLE_PITCH | FF_SWISS,
+                               DEFAULT_PITCH | FF_MODERN, FIXED_PITCH | FF_MODERN, VARIABLE_PITCH | FF_MODERN,
+                               DEFAULT_PITCH | FF_SCRIPT, FIXED_PITCH | FF_SCRIPT, VARIABLE_PITCH | FF_SCRIPT,
+                               DEFAULT_PITCH | FF_DECORATIVE, FIXED_PITCH | FF_DECORATIVE, VARIABLE_PITCH | FF_DECORATIVE,
+               }, {}},
+               { OPT_FONT_FILECMP + OPT_FONT_FACENAME, varprop::VT_STRING, {}, {L"Consolas", L"Courier", L"Courier New", L"FixedSys", L"Terminal"}},
+               { OPT_FONT_DIRCMP + OPT_FONT_USECUSTOM, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_POINTSIZE, varprop::VT_INT, {0, 12, 72}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_HEIGHT, varprop::VT_INT, {0, -23, -95}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_ESCAPEMENT, varprop::VT_INT, {0, 900}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_ORIENTATION, varprop::VT_INT, {0, 900}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_WEIGHT, varprop::VT_INT, {0, 400, 700, 1000}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_ITALIC, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_UNDERLINE, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_STRIKEOUT, varprop::VT_BOOL, {}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_CHARSET, varprop::VT_INT, {ANSI_CHARSET, DEFAULT_CHARSET, SYMBOL_CHARSET, SHIFTJIS_CHARSET, HANGUL_CHARSET, GB2312_CHARSET, CHINESEBIG5_CHARSET, JOHAB_CHARSET, HEBREW_CHARSET, ARABIC_CHARSET, GREEK_CHARSET, TURKISH_CHARSET, VIETNAMESE_CHARSET, THAI_CHARSET, EASTEUROPE_CHARSET, RUSSIAN_CHARSET, MAC_CHARSET, BALTIC_CHARSET, OEM_CHARSET}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_OUTPRECISION, varprop::VT_INT, {OUT_DEFAULT_PRECIS, OUT_STRING_PRECIS, OUT_CHARACTER_PRECIS, OUT_STROKE_PRECIS, OUT_TT_PRECIS, OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, OUT_TT_ONLY_PRECIS, OUT_OUTLINE_PRECIS, OUT_SCREEN_OUTLINE_PRECIS, OUT_PS_ONLY_PRECIS}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_CLIPPRECISION, varprop::VT_INT, {CLIP_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS, CLIP_STROKE_PRECIS, CLIP_LH_ANGLES, CLIP_TT_ALWAYS, CLIP_DFA_DISABLE, CLIP_EMBEDDED}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_QUALITY, varprop::VT_INT, {DEFAULT_QUALITY, DRAFT_QUALITY, PROOF_QUALITY, NONANTIALIASED_QUALITY, ANTIALIASED_QUALITY, CLEARTYPE_QUALITY, CLEARTYPE_NATURAL_QUALITY}, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_PITCHANDFAMILY, varprop::VT_INT, {DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH, }, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_PITCHANDFAMILY, varprop::VT_INT, 
+                       {
+                               DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH,
+                               DEFAULT_PITCH | FF_ROMAN, FIXED_PITCH | FF_ROMAN, VARIABLE_PITCH | FF_ROMAN,
+                               DEFAULT_PITCH | FF_SWISS, FIXED_PITCH | FF_SWISS, VARIABLE_PITCH | FF_SWISS,
+                               DEFAULT_PITCH | FF_MODERN, FIXED_PITCH | FF_MODERN, VARIABLE_PITCH | FF_MODERN,
+                               DEFAULT_PITCH | FF_SCRIPT, FIXED_PITCH | FF_SCRIPT, VARIABLE_PITCH | FF_SCRIPT,
+                               DEFAULT_PITCH | FF_DECORATIVE, FIXED_PITCH | FF_DECORATIVE, VARIABLE_PITCH | FF_DECORATIVE,
+               }, {}},
+               { OPT_FONT_DIRCMP + OPT_FONT_FACENAME, varprop::VT_STRING, {}, {L"Consolas", L"Courier", L"Courier New", L"FixedSys", L"Terminal"}},
+       };
+
+       static std::map<std::wstring, std::variant<bool, int, std::wstring>> SaveOptions()
+       {
+               std::map<std::wstring, std::variant<bool, int, std::wstring>> savedOptions;
+               for (auto& option : options)
+               {
+                       switch (option.type)
+                       {
+                       case varprop::VT_BOOL:
+                       {
+                               std::optional<bool> bval = regReadBool(option.name);
+                               if (bval.has_value())
+                                       savedOptions.insert_or_assign(option.name, *bval);
+                               break;
+                       }
+                       case varprop::VT_INT:
+                       {
+                               std::optional<int> ival = regReadInt(option.name);
+                               if (ival.has_value())
+                                       savedOptions.insert_or_assign(option.name, *ival);
+                               break;
+                       }
+                       case varprop::VT_STRING:
+                       {
+                               std::optional<std::wstring> sval = regReadString(option.name);
+                               if (sval.has_value())
+                                       savedOptions.insert_or_assign(option.name, *sval);
+                               break;
+                       }
+                       }
+               }
+               return savedOptions;
+       }
+
+       static void RestoreOptions(const std::map<std::wstring, std::variant<bool, int, std::wstring>>& savedOptions)
+       {
+               for (auto& option : options)
+               {
+                       auto it = savedOptions.find(option.name);
+                       if (it != savedOptions.end())
+                       {
+                               const auto& [name, value] = *it;
+                               switch (value.index())
+                               {
+                               case 0: regWrite(name, std::get<0>(value)); break;
+                               case 1: regWrite(name, std::get<1>(value)); break;
+                               case 2: regWrite(name, std::get<2>(value)); break;
+                               }
+                       }
+                       else
+                               regDelete(option.name);
+               }
+       }
+
+       TEST_P(ConfigTest, RandomTest)
+       {
+               std::string dir1 = (getModuleFolder() / "..\\..\\Data\\Compare\\Dir1\\").u8string();
+               std::string dir2 = (getModuleFolder() / "..\\..\\Data\\Compare\\Dir2\\").u8string();
+               std::string file1 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string file2 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8-NOBOM\\DiffItem.h").u8string();
+               std::string csvfile1 = (getModuleFolder() / "..\\..\\..\\Externals\\crystaledit\\test\\test.csv").u8string();
+               std::string csvfile2 = (getModuleFolder() / "..\\..\\..\\Externals\\crystaledit\\test\\test2.csv").u8string();
+               std::string binfile1 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string binfile2 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string imgfile1 = (getModuleFolder() / "..\\..\\..\\Docs\\Logos\\WinMerge_logo_24bit.png").u8string();
+               std::string imgfile2 = (getModuleFolder() / "..\\..\\..\\Docs\\Logos\\WinMerge_logo_shadow_24bit.png").u8string();
+
+               auto savedOptions = SaveOptions();
+
+               for (int i = 0; i < 20; ++i)
+               {
+                       const BOOL bValues[] = { TRUE, FALSE };
+                       for (auto& option : options)
+                       {
+                               size_t size;
+                               int idx;
+                               switch (option.type)
+                               {
+                               case varprop::VT_BOOL:
+                                       idx = rand() % 2;
+                                       regWrite(option.name, bValues[idx]);
+                                       break;
+                               case varprop::VT_INT:
+                                       size = option.iValues.size();
+                                       idx = rand() % size;
+                                       regWrite(option.name, option.iValues[idx]);
+                                       break;
+                               case varprop::VT_STRING:
+                                       size = option.sValues.size();
+                                       idx = rand() % size;
+                                       regWrite(option.name, option.sValues[idx]);
+                                       break;
+                               }
+                       }
+
+                       // Text file compare
+                       m_hwndWinMerge = execWinMerge(("/t text " + file1 + " " + file2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Table file compare
+                       m_hwndWinMerge = execWinMerge(("/t table /table-delimiter , " + csvfile1 + " " + csvfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Binary file compare
+                       m_hwndWinMerge = execWinMerge(("/t binary " + binfile1 + " " + binfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Image file compare
+                       m_hwndWinMerge = execWinMerge(("/t image " + imgfile1 + " " + imgfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Folder compare
+                       m_hwndWinMerge = execWinMerge(("-r " + dir1 + " " + dir2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       Sleep(1000);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+               }
+
+               RestoreOptions(savedOptions);
+       }
+
+       TEST_P(ConfigTest, FuzzingTest)
+       {
+               std::string dir1 = (getModuleFolder() / "..\\..\\Data\\Compare\\Dir1\\").u8string();
+               std::string dir2 = (getModuleFolder() / "..\\..\\Data\\Compare\\Dir2\\").u8string();
+               std::string file1 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string file2 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8-NOBOM\\DiffItem.h").u8string();
+               std::string csvfile1 = (getModuleFolder() / "..\\..\\..\\Externals\\crystaledit\\test\\test.csv").u8string();
+               std::string csvfile2 = (getModuleFolder() / "..\\..\\..\\Externals\\crystaledit\\test\\test2.csv").u8string();
+               std::string binfile1 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string binfile2 = (getModuleFolder() / "..\\..\\Data\\Unicode\\UTF-8\\DiffItem.h").u8string();
+               std::string imgfile1 = (getModuleFolder() / "..\\..\\..\\Docs\\Logos\\WinMerge_logo_24bit.png").u8string();
+               std::string imgfile2 = (getModuleFolder() / "..\\..\\..\\Docs\\Logos\\WinMerge_logo_shadow_24bit.png").u8string();
+
+               auto savedOptions = SaveOptions();
+
+               for (int i = 0; i < 20; ++i)
+               {
+                       const BOOL bValues[] = { TRUE, FALSE };
+                       for (auto& option : options)
+                       {
+                               size_t size;
+                               int idx;
+                               int ival;
+                               std::wstring sval;
+                               switch (option.type)
+                               {
+                               case varprop::VT_BOOL:
+                                       idx = rand() % 2;
+                                       regWrite(option.name, bValues[idx]);
+                                       break;
+                               case varprop::VT_INT:
+                                       ival = rand() * ((rand() < RAND_MAX / 2) ? 1 : -1);
+                                       regWrite(option.name, ival);
+                                       break;
+                               case varprop::VT_STRING:
+                                       size = option.sValues.size();
+                                       idx = rand() % size;
+                                       sval = option.sValues[idx];
+                                       if (!sval.empty())
+                                               sval[0] = static_cast<wchar_t>(rand());
+                                       regWrite(option.name, sval);
+                                       break;
+                               }
+                       }
+
+                       // Text file compare
+                       m_hwndWinMerge = execWinMerge(("/t text " + file1 + " " + file2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Table file compare
+                       m_hwndWinMerge = execWinMerge(("/t table /table-delimiter , " + csvfile1 + " " + csvfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Binary file compare
+                       m_hwndWinMerge = execWinMerge(("/t binary " + binfile1 + " " + binfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Image file compare
+                       m_hwndWinMerge = execWinMerge(("/t image " + imgfile1 + " " + imgfile2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+                       // Folder compare
+                       m_hwndWinMerge = execWinMerge(("-r " + dir1 + " " + dir2).c_str());
+                       ASSERT_TRUE(IsWindow(m_hwndWinMerge));
+                       waitForInputIdleByHWND(m_hwndWinMerge);
+                       Sleep(1000);
+                       PostMessage(m_hwndWinMerge, WM_CLOSE, 0, 0);
+                       waitUntilProcessExit(m_hwndWinMerge);
+               }
+
+               RestoreOptions(savedOptions);
+       }
+}
+
+INSTANTIATE_TEST_CASE_P(ConfigTestInstance,
+       ConfigTest,
+       testing::ValuesIn(GUITestUtils::languages()));