1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "gtest/gtest.h"
7
8 #include "mozilla/AssembleCmdLine.h"
9 #include "mozilla/CmdLineAndEnvUtils.h"
10 #include "mozilla/UniquePtrExtensions.h"
11 #include "WinRemoteMessage.h"
12
13 using namespace mozilla;
14
15 template <typename T>
16 struct TestCase {
17 const T* mArgs[4];
18 const wchar_t* mExpected;
19 };
20
21 #define ALPHA_IN_UTF8 "\xe3\x82\xa2\xe3\x83\xab\xe3\x83\x95\xe3\x82\xa1"
22 #define OMEGA_IN_UTF8 "\xe3\x82\xaa\xe3\x83\xa1\xe3\x82\xac"
23 #define ALPHA_IN_UTF16 L"\u30A2\u30EB\u30D5\u30A1"
24 #define OMEGA_IN_UTF16 L"\u30AA\u30E1\u30AC"
25 #define UPPER_CYRILLIC_P_IN_UTF8 "\xd0\xa0"
26 #define LOWER_CYRILLIC_P_IN_UTF8 "\xd1\x80"
27 #define UPPER_CYRILLIC_P_IN_UTF16 L"\u0420"
28 #define LOWER_CYRILLIC_P_IN_UTF16 L"\u0440"
29
30 TestCase<char> testCases[] = {
31 // Copied from TestXREMakeCommandLineWin.ini
32 {{"a:\\", nullptr}, L"a:\\"},
33 {{"a:\"", nullptr}, L"a:\\\""},
34 {{"a:\\b c", nullptr}, L"\"a:\\b c\""},
35 {{"a:\\b c\"", nullptr}, L"\"a:\\b c\\\"\""},
36 {{"a:\\b c\\d e", nullptr}, L"\"a:\\b c\\d e\""},
37 {{"a:\\b c\\d e\"", nullptr}, L"\"a:\\b c\\d e\\\"\""},
38 {{"a:\\", nullptr}, L"a:\\"},
39 {{"a:\"", "b:\\c d", nullptr}, L"a:\\\" \"b:\\c d\""},
40 {{"a", "b:\" c:\\d", "e", nullptr}, L"a \"b:\\\" c:\\d\" e"},
41 {{"abc", "d", "e", nullptr}, L"abc d e"},
42 {{"a b c", "d", "e", nullptr}, L"\"a b c\" d e"},
43 {{"a\\\\\\b", "de fg", "h", nullptr}, L"a\\\\\\b \"de fg\" h"},
44 {{"a", "b", nullptr}, L"a b"},
45 {{"a\tb", nullptr}, L"\"a\tb\""},
46 {{"a\\\"b", "c", "d", nullptr}, L"a\\\\\\\"b c d"},
47 {{"a\\\"b", "c", nullptr}, L"a\\\\\\\"b c"},
48 {{"a\\\\\\b c", nullptr}, L"\"a\\\\\\b c\""},
49 {{"\"a", nullptr}, L"\\\"a"},
50 {{"\\a", nullptr}, L"\\a"},
51 {{"\\\\\\a", nullptr}, L"\\\\\\a"},
52 {{"\\\\\\\"a", nullptr}, L"\\\\\\\\\\\\\\\"a"},
53 {{"a\\\"b c\" d e", nullptr}, L"\"a\\\\\\\"b c\\\" d e\""},
54 {{"a\\\\\"b", "c d e", nullptr}, L"a\\\\\\\\\\\"b \"c d e\""},
55 {{"a:\\b", "c\\" ALPHA_IN_UTF8, OMEGA_IN_UTF8 "\\d", nullptr},
56 L"a:\\b c\\" ALPHA_IN_UTF16 L" " OMEGA_IN_UTF16 L"\\d"},
57 {{"a:\\b", "c\\" ALPHA_IN_UTF8 " " OMEGA_IN_UTF8 "\\d", nullptr},
58 L"a:\\b \"c\\" ALPHA_IN_UTF16 L" " OMEGA_IN_UTF16 L"\\d\""},
59 {{ALPHA_IN_UTF8, OMEGA_IN_UTF8, nullptr},
60 ALPHA_IN_UTF16 L" " OMEGA_IN_UTF16},
61
62 // More single-argument cases
63 {{"", nullptr}, L""},
64 {{"a\fb", nullptr}, L"\"a\fb\""},
65 {{"a\nb", nullptr}, L"\"a\nb\""},
66 {{"a\rb", nullptr}, L"\"a\rb\""},
67 {{"a\vb", nullptr}, L"\"a\vb\""},
68 {{"\"a\" \"b\"", nullptr}, L"\"\\\"a\\\" \\\"b\\\"\""},
69 {{"\"a\\b\" \"c\\d\"", nullptr}, L"\"\\\"a\\b\\\" \\\"c\\d\\\"\""},
70 {{"\\\\ \\\\", nullptr}, L"\"\\\\ \\\\\\\\\""},
71 {{"\"\" \"\"", nullptr}, L"\"\\\"\\\" \\\"\\\"\""},
72 {{ALPHA_IN_UTF8 "\\" OMEGA_IN_UTF8, nullptr},
73 ALPHA_IN_UTF16 L"\\" OMEGA_IN_UTF16},
74 {{ALPHA_IN_UTF8 " " OMEGA_IN_UTF8, nullptr},
75 L"\"" ALPHA_IN_UTF16 L" " OMEGA_IN_UTF16 L"\""},
76 };
77
TEST(AssembleCommandLineWin,assembleCmdLine)78 TEST(AssembleCommandLineWin, assembleCmdLine)
79 {
80 for (const auto& testCase : testCases) {
81 UniqueFreePtr<wchar_t> assembled;
82 wchar_t* assembledRaw = nullptr;
83 EXPECT_EQ(assembleCmdLine(testCase.mArgs, &assembledRaw, CP_UTF8), 0);
84 assembled.reset(assembledRaw);
85
86 EXPECT_STREQ(assembled.get(), testCase.mExpected);
87 }
88 }
89
TEST(CommandLineParserWin,HandleCommandLine)90 TEST(CommandLineParserWin, HandleCommandLine)
91 {
92 CommandLineParserWin<char> parser;
93 for (const auto& testCase : testCases) {
94 NS_ConvertUTF16toUTF8 utf8(testCase.mExpected);
95 parser.HandleCommandLine(utf8);
96
97 if (utf8.Length() == 0) {
98 EXPECT_EQ(parser.Argc(), 0);
99 continue;
100 }
101
102 for (int i = 0; i < parser.Argc(); ++i) {
103 EXPECT_NE(testCase.mArgs[i], nullptr);
104 EXPECT_STREQ(parser.Argv()[i], testCase.mArgs[i]);
105 }
106 EXPECT_EQ(testCase.mArgs[parser.Argc()], nullptr);
107 }
108 }
109
TEST(WinRemoteMessage,SendReceive)110 TEST(WinRemoteMessage, SendReceive)
111 {
112 const char kCommandline[] =
113 "dummy.exe /arg1 --arg2 \"3rd arg\" "
114 "4th=\"" UPPER_CYRILLIC_P_IN_UTF8 " " LOWER_CYRILLIC_P_IN_UTF8 "\"";
115 const wchar_t kCommandlineW[] =
116 L"dummy.exe /arg1 --arg2 \"3rd arg\" "
117 L"4th=\"" UPPER_CYRILLIC_P_IN_UTF16 L" " LOWER_CYRILLIC_P_IN_UTF16 L"\"";
118 const wchar_t* kExpectedArgsW[] = {
119 L"-arg1", L"-arg2", L"3rd arg",
120 L"4th=" UPPER_CYRILLIC_P_IN_UTF16 L" " LOWER_CYRILLIC_P_IN_UTF16};
121
122 char workingDirA[MAX_PATH];
123 wchar_t workingDirW[MAX_PATH];
124 EXPECT_NE(getcwd(workingDirA, MAX_PATH), nullptr);
125 EXPECT_NE(_wgetcwd(workingDirW, MAX_PATH), nullptr);
126
127 WinRemoteMessageSender v0(kCommandline);
128 WinRemoteMessageSender v1(kCommandline, workingDirA);
129 WinRemoteMessageSender v2(kCommandlineW, workingDirW);
130
131 WinRemoteMessageReceiver receiver;
132 int32_t len;
133 nsAutoString arg;
134 nsCOMPtr<nsIFile> workingDir;
135
136 receiver.Parse(v0.CopyData());
137 EXPECT_TRUE(NS_SUCCEEDED(receiver.CommandLineRunner()->GetLength(&len)));
138 EXPECT_EQ(len, ArrayLength(kExpectedArgsW));
139 for (int i = 0; i < ArrayLength(kExpectedArgsW); ++i) {
140 EXPECT_TRUE(
141 NS_SUCCEEDED(receiver.CommandLineRunner()->GetArgument(i, arg)));
142 EXPECT_STREQ(arg.get(), kExpectedArgsW[i]);
143 }
144 EXPECT_EQ(receiver.CommandLineRunner()->GetWorkingDirectory(
145 getter_AddRefs(workingDir)),
146 NS_ERROR_NOT_INITIALIZED);
147
148 receiver.Parse(v1.CopyData());
149 EXPECT_TRUE(NS_SUCCEEDED(receiver.CommandLineRunner()->GetLength(&len)));
150 EXPECT_EQ(len, ArrayLength(kExpectedArgsW));
151 for (int i = 0; i < ArrayLength(kExpectedArgsW); ++i) {
152 EXPECT_TRUE(
153 NS_SUCCEEDED(receiver.CommandLineRunner()->GetArgument(i, arg)));
154 EXPECT_STREQ(arg.get(), kExpectedArgsW[i]);
155 }
156 EXPECT_TRUE(NS_SUCCEEDED(receiver.CommandLineRunner()->GetWorkingDirectory(
157 getter_AddRefs(workingDir))));
158 EXPECT_TRUE(NS_SUCCEEDED(workingDir->GetPath(arg)));
159 EXPECT_STREQ(arg.get(), workingDirW);
160
161 receiver.Parse(v2.CopyData());
162 EXPECT_TRUE(NS_SUCCEEDED(receiver.CommandLineRunner()->GetLength(&len)));
163 EXPECT_EQ(len, ArrayLength(kExpectedArgsW));
164 for (int i = 0; i < ArrayLength(kExpectedArgsW); ++i) {
165 EXPECT_TRUE(
166 NS_SUCCEEDED(receiver.CommandLineRunner()->GetArgument(i, arg)));
167 EXPECT_STREQ(arg.get(), kExpectedArgsW[i]);
168 }
169 EXPECT_TRUE(NS_SUCCEEDED(receiver.CommandLineRunner()->GetWorkingDirectory(
170 getter_AddRefs(workingDir))));
171 EXPECT_TRUE(NS_SUCCEEDED(workingDir->GetPath(arg)));
172 EXPECT_STREQ(arg.get(), workingDirW);
173 }
174