Skip to content

Commit 6d30b0e

Browse files
Merge pull request #417 from stephenegriffin/flag
unit tests for flags
2 parents 1b95f9c + 5c07f30 commit 6d30b0e

File tree

5 files changed

+144
-114
lines changed

5 files changed

+144
-114
lines changed

UnitTest/UnitTest.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@
524524
<ClInclude Include="UnitTest.h" />
525525
</ItemGroup>
526526
<ItemGroup>
527+
<ClCompile Include="tests\flagtest.cpp" />
527528
<ClCompile Include="tests\proptagTest.cpp" />
528529
<ClCompile Include="tests\blockPVtest.cpp" />
529530
<ClCompile Include="tests\blocktest.cpp" />

UnitTest/UnitTest.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
<ClCompile Include="tests\proptagTest.cpp">
6363
<Filter>Source Files</Filter>
6464
</ClCompile>
65+
<ClCompile Include="tests\flagtest.cpp">
66+
<Filter>Source Files</Filter>
67+
</ClCompile>
6568
</ItemGroup>
6669
<ItemGroup>
6770
<ResourceCompile Include="res\UnitTest.rc">

UnitTest/tests/flagtest.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include <UnitTest/stdafx.h>
2+
#include <UnitTest/UnitTest.h>
3+
#include <core/interpret/flags.h>
4+
#include <core/mapi/extraPropTags.h>
5+
6+
namespace flagtest
7+
{
8+
TEST_CLASS(flagtest)
9+
{
10+
public:
11+
// Without this, clang gets weird
12+
static const bool dummy_var = true;
13+
14+
TEST_CLASS_INITIALIZE(initialize) { unittest::init(); }
15+
16+
TEST_METHOD(Test_InterpretFlags)
17+
{
18+
// flagVALUE
19+
unittest::AreEqualEx(L"BMR_EQZ", flags::InterpretFlags(flagBitmask, BMR_EQZ));
20+
unittest::AreEqualEx(L"BMR_NEZ", flags::InterpretFlags(flagBitmask, BMR_NEZ));
21+
22+
// flagFLAG with null flagVALUE
23+
unittest::AreEqualEx(
24+
L"MSG_DEFAULTS_NONE", flags::InterpretFlags(PROP_ID(PR_CERT_DEFAULTS), MSG_DEFAULTS_NONE));
25+
unittest::AreEqualEx(
26+
L"MSG_DEFAULTS_FOR_FORMAT | MSG_DEFAULTS_SEND_CERT",
27+
flags::InterpretFlags(PROP_ID(PR_CERT_DEFAULTS), MSG_DEFAULTS_FOR_FORMAT | MSG_DEFAULTS_SEND_CERT));
28+
unittest::AreEqualEx(
29+
L"MSG_DEFAULTS_GLOBAL | 0x8",
30+
flags::InterpretFlags(PROP_ID(PR_CERT_DEFAULTS), MSG_DEFAULTS_GLOBAL | 0x8));
31+
32+
// flagFLAG mixed with flagVALUE
33+
unittest::AreEqualEx(
34+
L"MAPI_P1 | MAPI_SUBMITTED | MAPI_ORIG",
35+
flags::InterpretFlags(PROP_ID(PR_RECIPIENT_TYPE), MAPI_P1 | MAPI_SUBMITTED | MAPI_ORIG));
36+
unittest::AreEqualEx(
37+
L"MAPI_P1 | MAPI_TO", flags::InterpretFlags(PROP_ID(PR_RECIPIENT_TYPE), MAPI_P1 | MAPI_TO));
38+
unittest::AreEqualEx(
39+
L"MAPI_SUBMITTED | 0x5", flags::InterpretFlags(PROP_ID(PR_RECIPIENT_TYPE), MAPI_SUBMITTED | 0x5));
40+
unittest::AreEqualEx(
41+
L"MAPI_SUBMITTED | 0x20000000 | 0x5", flags::InterpretFlags(PROP_ID(PR_RECIPIENT_TYPE), MAPI_SUBMITTED | 0x20000005));
42+
43+
// flagFLAG with no null
44+
unittest::AreEqualEx(L"0x0", flags::InterpretFlags(PROP_ID(PR_SUBMIT_FLAGS), 0));
45+
unittest::AreEqualEx(
46+
L"SUBMITFLAG_LOCKED", flags::InterpretFlags(PROP_ID(PR_SUBMIT_FLAGS), SUBMITFLAG_LOCKED));
47+
48+
// FLAG_ENTRY3RDBYTE and FLAG_ENTRY4THBYTE
49+
unittest::AreEqualEx(
50+
L"DTE_FLAG_REMOTE_VALID | Remote: DT_MAILUSER | Local: DT_SEC_DISTLIST",
51+
flags::InterpretFlags(
52+
PROP_ID(PR_DISPLAY_TYPE_EX),
53+
DTE_FLAG_REMOTE_VALID | DTE_REMOTE(DT_ROOM) | DTE_LOCAL(DT_SEC_DISTLIST)));
54+
55+
// FLAG_ENTRYHIGHBYTES
56+
unittest::AreEqualEx(
57+
L"CPU: MAPIFORM_CPU_X86 | MAPIFORM_OS_WIN_95",
58+
flags::InterpretFlags(
59+
PROP_ID(PR_FORM_HOST_MAP), MAPIFORM_PLATFORM(MAPIFORM_CPU_X86, MAPIFORM_OS_WIN_95)));
60+
61+
// NON_PROP_FLAG_ENTRYLOWERNIBBLE
62+
unittest::AreEqualEx(
63+
L"BFLAGS_MASK_OUTLOOK | Type: BFLAGS_INTERNAL_MAILUSER | Home Fax",
64+
flags::InterpretFlags(flagWABEntryIDType, BFLAGS_MASK_OUTLOOK | BFLAGS_INTERNAL_MAILUSER | 0x10));
65+
}
66+
67+
TEST_METHOD(Test_AllFlagsToString)
68+
{
69+
unittest::AreEqualEx(L"", flags::AllFlagsToString(NULL, true));
70+
unittest::AreEqualEx(L"", flags::AllFlagsToString(0xFFFFFFFF, true));
71+
unittest::AreEqualEx(
72+
L"0x10000000 MAPI_P1\r\n"
73+
L"0x80000000 MAPI_SUBMITTED\r\n"
74+
L"0x00000000 MAPI_ORIG\r\n"
75+
L"0x00000001 MAPI_TO\r\n"
76+
L"0x00000002 MAPI_CC\r\n"
77+
L"0x00000003 MAPI_BCC",
78+
flags::AllFlagsToString(PROP_ID(PR_RECIPIENT_TYPE), true));
79+
unittest::AreEqualEx(
80+
L"268435456 MAPI_P1\r\n"
81+
L"-2147483648 MAPI_SUBMITTED\r\n"
82+
L" 0 MAPI_ORIG\r\n"
83+
L" 1 MAPI_TO\r\n"
84+
L" 2 MAPI_CC\r\n"
85+
L" 3 MAPI_BCC",
86+
flags::AllFlagsToString(PROP_ID(PR_RECIPIENT_TYPE), false));
87+
}
88+
};
89+
} // namespace flagtest

core/interpret/flags.cpp

+49-112
Original file line numberDiff line numberDiff line change
@@ -24,180 +24,117 @@ namespace flags
2424
if (FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";
2525

2626
// We've matched our flag name to the array - we SHOULD return a string at this point
27-
auto bNeedSeparator = false;
28-
27+
auto flags = std::vector<std::wstring>{};
2928
auto lTempValue = lFlagValue;
30-
std::wstring szTempString;
31-
for (; FlagArray[ulCurEntry].ulFlagName == ulFlagName; ulCurEntry++)
29+
while (FlagArray[ulCurEntry].ulFlagName == ulFlagName)
3230
{
33-
if (flagFLAG == FlagArray[ulCurEntry].ulFlagType)
31+
switch (FlagArray[ulCurEntry].ulFlagType)
3432
{
33+
case flagFLAG:
3534
if (FlagArray[ulCurEntry].lFlagValue & lTempValue)
3635
{
37-
if (bNeedSeparator)
38-
{
39-
szTempString += L" | "; // STRING_OK
40-
}
41-
42-
szTempString += FlagArray[ulCurEntry].lpszName;
36+
flags.push_back(FlagArray[ulCurEntry].lpszName);
4337
lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
44-
bNeedSeparator = true;
4538
}
46-
}
47-
else if (flagVALUE == FlagArray[ulCurEntry].ulFlagType)
48-
{
39+
break;
40+
case flagVALUE:
4941
if (FlagArray[ulCurEntry].lFlagValue == lTempValue)
5042
{
51-
if (bNeedSeparator)
52-
{
53-
szTempString += L" | "; // STRING_OK
54-
}
55-
56-
szTempString += FlagArray[ulCurEntry].lpszName;
43+
flags.push_back(FlagArray[ulCurEntry].lpszName);
5744
lTempValue = 0;
58-
bNeedSeparator = true;
5945
}
60-
}
61-
else if (flagVALUEHIGHBYTES == FlagArray[ulCurEntry].ulFlagType)
62-
{
46+
break;
47+
case flagVALUEHIGHBYTES:
6348
if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 16 & 0xFFFF))
6449
{
65-
if (bNeedSeparator)
66-
{
67-
szTempString += L" | "; // STRING_OK
68-
}
69-
70-
szTempString += FlagArray[ulCurEntry].lpszName;
50+
flags.push_back(FlagArray[ulCurEntry].lpszName);
7151
lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 16);
72-
bNeedSeparator = true;
7352
}
74-
}
75-
else if (flagVALUE3RDBYTE == FlagArray[ulCurEntry].ulFlagType)
76-
{
53+
break;
54+
case flagVALUE3RDBYTE:
7755
if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 8 & 0xFF))
7856
{
79-
if (bNeedSeparator)
80-
{
81-
szTempString += L" | "; // STRING_OK
82-
}
83-
84-
szTempString += FlagArray[ulCurEntry].lpszName;
57+
flags.push_back(FlagArray[ulCurEntry].lpszName);
8558
lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 8);
86-
bNeedSeparator = true;
8759
}
88-
}
89-
else if (flagVALUE4THBYTE == FlagArray[ulCurEntry].ulFlagType)
90-
{
60+
break;
61+
case flagVALUE4THBYTE:
9162
if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0xFF))
9263
{
93-
if (bNeedSeparator)
94-
{
95-
szTempString += L" | "; // STRING_OK
96-
}
97-
98-
szTempString += FlagArray[ulCurEntry].lpszName;
64+
flags.push_back(FlagArray[ulCurEntry].lpszName);
9965
lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
100-
bNeedSeparator = true;
10166
}
102-
}
103-
else if (flagVALUELOWERNIBBLE == FlagArray[ulCurEntry].ulFlagType)
104-
{
67+
break;
68+
case flagVALUELOWERNIBBLE:
10569
if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0x0F))
10670
{
107-
if (bNeedSeparator)
108-
{
109-
szTempString += L" | "; // STRING_OK
110-
}
111-
112-
szTempString += FlagArray[ulCurEntry].lpszName;
71+
flags.push_back(FlagArray[ulCurEntry].lpszName);
11372
lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
114-
bNeedSeparator = true;
11573
}
116-
}
117-
else if (flagCLEARBITS == FlagArray[ulCurEntry].ulFlagType)
118-
{
74+
break;
75+
case flagCLEARBITS:
11976
// find any bits we need to clear
12077
const auto lClearedBits = FlagArray[ulCurEntry].lFlagValue & lTempValue;
12178
// report what we found
122-
if (0 != lClearedBits)
79+
if (lClearedBits != 0)
12380
{
124-
if (bNeedSeparator)
125-
{
126-
szTempString += L" | "; // STRING_OK
127-
}
128-
129-
szTempString += strings::format(L"0x%X", lClearedBits); // STRING_OK
81+
flags.push_back(strings::format(L"0x%X", lClearedBits)); // STRING_OK
13082
// clear the bits out
13183
lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
132-
bNeedSeparator = true;
13384
}
85+
break;
13486
}
87+
88+
ulCurEntry++;
13589
}
13690

137-
// We know if we've found anything already because bNeedSeparator will be true
138-
// If bNeedSeparator isn't true, we found nothing and need to tack on
139-
// Otherwise, it's true, and we only tack if lTempValue still has something in it
140-
if (!bNeedSeparator || lTempValue)
91+
if (lTempValue || flags.empty())
14192
{
142-
if (bNeedSeparator)
143-
{
144-
szTempString += L" | "; // STRING_OK
145-
}
146-
147-
szTempString += strings::format(L"0x%X", lTempValue); // STRING_OK
93+
flags.push_back(strings::format(L"0x%X", lTempValue)); // STRING_OK
14894
}
14995

150-
return szTempString;
96+
return strings::join(flags, L" | ");
15197
}
15298

15399
// Returns a list of all known flags/values for a flag name.
154100
// For instance, for flagFuzzyLevel, would return:
155-
// \r\n0x00000000 FL_FULLSTRING\r\n\
156-
// 0x00000001 FL_SUBSTRING\r\n\
157-
// 0x00000002 FL_PREFIX\r\n\
158-
// 0x00010000 FL_IGNORECASE\r\n\
159-
// 0x00020000 FL_IGNORENONSPACE\r\n\
160-
// 0x00040000 FL_LOOSE
101+
// 0x00000000 FL_FULLSTRING\r\n\
102+
// 0x00000001 FL_SUBSTRING\r\n\
103+
// 0x00000002 FL_PREFIX\r\n\
104+
// 0x00010000 FL_IGNORECASE\r\n\
105+
// 0x00020000 FL_IGNORENONSPACE\r\n\
106+
// 0x00040000 FL_LOOSE
161107
//
162108
// Since the string is always appended to a prompt we include \r\n at the start
163109
std::wstring AllFlagsToString(ULONG ulFlagName, bool bHex)
164110
{
165-
std::wstring szFlagString;
166-
if (!ulFlagName) return szFlagString;
167-
if (FlagArray.empty()) return szFlagString;
111+
if (!ulFlagName) return L"";
112+
if (FlagArray.empty()) return L"";
168113

169114
ULONG ulCurEntry = 0;
170-
std::wstring szTempString;
171115

172116
while (ulCurEntry < FlagArray.size() && FlagArray[ulCurEntry].ulFlagName != ulFlagName)
173117
{
174118
ulCurEntry++;
175119
}
176120

177-
if (FlagArray[ulCurEntry].ulFlagName != ulFlagName) return szFlagString;
121+
if (ulCurEntry == FlagArray.size() || FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";
178122

179123
// We've matched our flag name to the array - we SHOULD return a string at this point
180-
for (; FlagArray[ulCurEntry].ulFlagName == ulFlagName; ulCurEntry++)
124+
auto flags = std::vector<std::wstring>{};
125+
while (FlagArray[ulCurEntry].ulFlagName == ulFlagName)
181126
{
182-
if (flagCLEARBITS == FlagArray[ulCurEntry].ulFlagType)
127+
if (flagCLEARBITS != FlagArray[ulCurEntry].ulFlagType)
183128
{
184-
// keep going
185-
}
186-
else
187-
{
188-
if (bHex)
189-
{
190-
szFlagString += strings::formatmessage(
191-
IDS_FLAGTOSTRINGHEX, FlagArray[ulCurEntry].lFlagValue, FlagArray[ulCurEntry].lpszName);
192-
}
193-
else
194-
{
195-
szFlagString += strings::formatmessage(
196-
IDS_FLAGTOSTRINGDEC, FlagArray[ulCurEntry].lFlagValue, FlagArray[ulCurEntry].lpszName);
197-
}
129+
flags.push_back(strings::formatmessage(
130+
bHex ? IDS_FLAGTOSTRINGHEX : IDS_FLAGTOSTRINGDEC,
131+
FlagArray[ulCurEntry].lFlagValue,
132+
FlagArray[ulCurEntry].lpszName));
198133
}
134+
135+
ulCurEntry++;
199136
}
200137

201-
return szFlagString;
138+
return strings::join(flags, L"\r\n");
202139
}
203140
} // namespace flags

core/res/MFCMapi.rc2

+2-2
Original file line numberDiff line numberDiff line change
@@ -1480,8 +1480,8 @@ IDS_SIDFLAGS "Flags: 0x%1!08X!"
14801480

14811481
IDS_INVALIDSD "This is not a valid security descriptor."
14821482

1483-
IDS_FLAGTOSTRINGHEX "\r\n0x%1!08X! %2!ws!"
1484-
IDS_FLAGTOSTRINGDEC "\r\n%1!5d! %2!ws!"
1483+
IDS_FLAGTOSTRINGHEX "0x%1!08X! %2!ws!"
1484+
IDS_FLAGTOSTRINGDEC "%1!5d! %2!ws!"
14851485

14861486
IDS_PTI8FORMATLABEL "I8: %1!X!-%2!08X!"
14871487
IDS_PTI8FORMAT "%1!X!-%2!08X!"

0 commit comments

Comments
 (0)