Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / breakpad / src / tools / windows / dump_syms / dump_syms_unittest.cc
1 // Copyright 2003 Google Inc. All rights reserved.\r
2 //\r
3 // Redistribution and use in source and binary forms, with or without\r
4 // modification, are permitted provided that the following conditions are\r
5 // met:\r
6 //\r
7 //     * Redistributions of source code must retain the above copyright\r
8 // notice, this list of conditions and the following disclaimer.\r
9 //     * Redistributions in binary form must reproduce the above\r
10 // copyright notice, this list of conditions and the following disclaimer\r
11 // in the documentation and/or other materials provided with the\r
12 // distribution.\r
13 //     * Neither the name of Google Inc. nor the names of its\r
14 // contributors may be used to endorse or promote products derived from\r
15 // this software without specific prior written permission.\r
16 //\r
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 \r
29 #include <Windows.h>\r
30 #include <shellapi.h>\r
31 \r
32 #include <string>\r
33 #include <utility>\r
34 \r
35 #include "gmock/gmock.h"\r
36 #include "gtest/gtest.h"\r
37 \r
38 namespace tools {\r
39 namespace windows {\r
40 namespace dump_syms {\r
41 \r
42 namespace {\r
43 \r
44 // Root names of PDB and dumped symbol files to be regression tested. These are\r
45 // specified in complexity of the resulting dumped symbol files.\r
46 const wchar_t* kRootNames[] = {\r
47   // A PDB file with no OMAP data.\r
48   L"dump_syms_regtest",\r
49   // A PDB file with OMAP data for an image that has been function-level\r
50   // reordered.\r
51   L"omap_reorder_funcs",\r
52   // A PDB file with OMAP data for an image that had new content injected, all\r
53   // of it with source data.\r
54   L"omap_stretched_filled",\r
55   // A PDB file with OMAP data for an image that had new content injected, but\r
56   // without source data.\r
57   L"omap_stretched",\r
58   // A PDB file with OMAP data for an image that has been basic block reordered.\r
59   L"omap_reorder_bbs",  \r
60   // A 64bit PDB file with no OMAP data.\r
61   L"dump_syms_regtest64",\r
62 };\r
63 \r
64 void TrimLastComponent(const std::wstring& path,\r
65                        std::wstring* trimmed,\r
66                        std::wstring* component) {\r
67   size_t len = path.size();\r
68   while (len > 0 && path[len - 1] != '\\')\r
69     --len;\r
70 \r
71   if (component != NULL)\r
72     component->assign(path.c_str() + len, path.c_str() + path.size());\r
73 \r
74   while (len > 0 && path[len - 1] == '\\')\r
75     --len;\r
76 \r
77   if (trimmed != NULL)\r
78     trimmed->assign(path.c_str(), len);\r
79 }\r
80 \r
81 // Get the directory of the current executable.\r
82 bool GetSelfDirectory(std::wstring* self_dir) {\r
83   std::wstring command_line = GetCommandLineW();\r
84 \r
85   int num_args = 0;\r
86   wchar_t** args = NULL;\r
87   args = ::CommandLineToArgvW(command_line.c_str(), &num_args);\r
88   if (args == NULL)\r
89     return false;\r
90 \r
91   *self_dir = args[0];\r
92   TrimLastComponent(*self_dir, self_dir, NULL);\r
93 \r
94   return true;\r
95 }\r
96 \r
97 void RunCommand(const std::wstring& command_line,\r
98                 std::string* stdout_string) {\r
99   // Create a PIPE for the child process stdout.\r
100   HANDLE child_stdout_read = 0;\r
101   HANDLE child_stdout_write = 0;\r
102   SECURITY_ATTRIBUTES sec_attr_stdout = {};\r
103   sec_attr_stdout.nLength = sizeof(sec_attr_stdout);\r
104   sec_attr_stdout.bInheritHandle = TRUE;\r
105   ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,\r
106                            &sec_attr_stdout, 0));\r
107   ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,\r
108                                      0));\r
109 \r
110   // Create a PIPE for the child process stdin.\r
111   HANDLE child_stdin_read = 0;\r
112   HANDLE child_stdin_write = 0;\r
113   SECURITY_ATTRIBUTES sec_attr_stdin = {};\r
114   sec_attr_stdin.nLength = sizeof(sec_attr_stdin);\r
115   sec_attr_stdin.bInheritHandle = TRUE;\r
116   ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,\r
117                            &sec_attr_stdin, 0));\r
118   ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,\r
119                                      0));\r
120 \r
121   // Startup the child.\r
122   STARTUPINFO startup_info = {};\r
123   PROCESS_INFORMATION process_info = {};\r
124   startup_info.cb = sizeof(STARTUPINFO);\r
125   startup_info.hStdError = child_stdout_write;\r
126   startup_info.hStdInput = child_stdin_read;\r
127   startup_info.hStdOutput = child_stdout_write;\r
128   startup_info.dwFlags = STARTF_USESTDHANDLES;\r
129   ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,\r
130                                TRUE, 0, NULL, NULL,\r
131                                &startup_info, &process_info));\r
132 \r
133   // Collect the output.\r
134   ASSERT_TRUE(::CloseHandle(child_stdout_write));\r
135   char buffer[4096] = {};\r
136   DWORD bytes_read = 0;\r
137   while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,\r
138                     NULL) && bytes_read > 0) {\r
139     stdout_string->append(buffer, bytes_read);\r
140   }\r
141 \r
142   // Wait for the process to finish.\r
143   ::WaitForSingleObject(process_info.hProcess, INFINITE);\r
144 \r
145   // Shut down all of our handles.\r
146   ASSERT_TRUE(::CloseHandle(process_info.hThread));\r
147   ASSERT_TRUE(::CloseHandle(process_info.hProcess));\r
148   ASSERT_TRUE(::CloseHandle(child_stdin_write));\r
149   ASSERT_TRUE(::CloseHandle(child_stdin_read));\r
150   ASSERT_TRUE(::CloseHandle(child_stdout_read));\r
151 }\r
152 \r
153 void GetFileContents(const std::wstring& path, std::string* content) {\r
154   FILE* f = ::_wfopen(path.c_str(), L"rb");\r
155   ASSERT_TRUE(f != NULL);\r
156 \r
157   char buffer[4096] = {};\r
158   while (true) {\r
159     size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);\r
160     if (bytes_read == 0)\r
161       break;\r
162     content->append(buffer, bytes_read);\r
163   }\r
164 }\r
165 \r
166 class DumpSymsRegressionTest : public testing::Test {\r
167  public:\r
168   virtual void SetUp() {\r
169     std::wstring self_dir;\r
170     ASSERT_TRUE(GetSelfDirectory(&self_dir));\r
171     dump_syms_exe = self_dir + L"\\dump_syms.exe";\r
172 \r
173     TrimLastComponent(self_dir, &testdata_dir, NULL);\r
174     testdata_dir += L"\\testdata";\r
175   }\r
176 \r
177   std::wstring dump_syms_exe;\r
178   std::wstring testdata_dir;\r
179 };\r
180 \r
181 }  //namespace\r
182 \r
183 TEST_F(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {\r
184   for (size_t i = 0; i < sizeof(kRootNames) / sizeof(kRootNames[0]); ++i) {\r
185     const wchar_t* root_name = kRootNames[i];\r
186     std::wstring root_path = testdata_dir + L"\\" + root_name;\r
187 \r
188     std::wstring sym_path = root_path + L".sym";\r
189     std::string expected_symbols;\r
190     ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));\r
191 \r
192     std::wstring pdb_path = root_path + L".pdb";\r
193     std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +\r
194         pdb_path + L"\"";\r
195     std::string symbols;\r
196     ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));\r
197 \r
198     EXPECT_EQ(expected_symbols, symbols);\r
199   }\r
200 }\r
201 \r
202 }  // namespace dump_syms\r
203 }  // namespace windows\r
204 }  // namespace tools