1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome_frame/test/mock_ie_event_sink_actions.h"
6#include "chrome_frame/test/mock_ie_event_sink_test.h"
7#include "base/rand_util.h"
8
9namespace chrome_frame_test {
10
11class TestData {
12 public:
13  TestData(const std::string& value, bool in_header, LoadedInRenderer expected)
14      : value_(value),
15        in_header_(in_header),
16        expected_(expected),
17        name_(base::IntToString(base::RandInt(0, 1000))) {
18  }
19
20  LoadedInRenderer GetExpectedRenderer() const {
21    return expected_;
22  }
23
24  std::wstring GetPath() const {
25    return ASCIIToWide("/" + name_);
26  }
27
28  std::wstring GetUrl(MockWebServer* server_mock) const {
29    return server_mock->Resolve(ASCIIToWide(name_));
30  }
31
32  void ExpectOnServer(MockWebServer* server_mock) const {
33    EXPECT_CALL(*server_mock, Get(testing::_, GetPath(), testing::_))
34        .Times(testing::AnyNumber())
35        .WillRepeatedly(SendFast(GetHeaders(), GetHtml()));
36  }
37
38  std::string GetHeaders() const {
39    std::ostringstream headers;
40    headers << "HTTP/1.1 200 OK\r\n"
41            << "Connection: close\r\n"
42            << "Content-Type: text/html\r\n"
43            << "Cache-Control: no-cache\r\n";
44    if (in_header_) {
45      headers << "X-UA-COMPATIBLE: " << value_ << "\r\n";
46    }
47    return headers.str();
48  }
49
50  std::string GetHtml() const {
51    std::ostringstream html;
52    html << "<html><head>";
53    if (!in_header_) {
54       html << "<meta http-equiv=\"x-ua-compatible\" content=\"" << value_
55            << "\" />";
56    }
57    html << "</head><body>This is some text.</body></html>";
58    return html.str();
59  }
60
61 private:
62  LoadedInRenderer expected_;
63  std::string name_;
64  std::string value_;
65  bool in_header_;
66};
67
68// Determines the major version of the installed IE
69// Returns -1 in case of failure, 0 if the version is newer than currently known
70int GetIEMajorVersion() {
71  switch (GetInstalledIEVersion()) {
72    case IE_6:
73      return 6;
74    case IE_7:
75      return 7;
76    case IE_8:
77      return 8;
78    case IE_9:
79      return 9;
80    case IE_10:
81      return 10;
82    case IE_INVALID:
83    case NON_IE:
84    case IE_UNSUPPORTED:
85      ADD_FAILURE() << "Failed to detect IE version.";
86      return -1;
87    default:
88      return 0;
89  }
90}
91
92int LowVersion() {
93  int ie_version = GetIEMajorVersion();
94  switch (ie_version) {
95    case -1:
96    case 0:
97      return 5;
98    default:
99      return ie_version - 1;
100  }
101}
102
103int HighVersion() {
104  int ie_version = GetIEMajorVersion();
105  switch (ie_version) {
106    case -1:
107    case 0:
108      return 1000;
109    default:
110      return ie_version + 1;
111  }
112}
113
114int EqualVersion() {
115  int ie_version = GetIEMajorVersion();
116  switch (ie_version) {
117    case -1:
118    case 0:
119      return 1000;
120    default:
121      return ie_version;
122  }
123}
124
125std::string HeaderValue(int ie_version) {
126  if (ie_version == -1) {
127    return "IE=8; Chrome=1";
128  } else {
129    return std::string("IE=8; Chrome=IE") + base::IntToString(ie_version);
130  }
131}
132
133std::string CorruptHeaderValue(int ie_version) {
134  return HeaderValue(ie_version) + ".0";
135}
136
137std::string LongHeaderValue(int ie_version) {
138  std::string long_value  = HeaderValue(ie_version)  + "; " +
139      std::string(256, 'a') + "=bbb";
140  DCHECK_GT(long_value.length(), 256u);
141  DCHECK_LT(long_value.length(), 512u);
142  return long_value;
143}
144
145class HeaderTest
146    : public MockIEEventSinkTest,
147      public testing::TestWithParam<TestData> {
148 public:
149  HeaderTest() {}
150};
151
152INSTANTIATE_TEST_CASE_P(MetaTag, HeaderTest, testing::Values(
153    TestData(HeaderValue(LowVersion()), false, IN_IE),
154    TestData(HeaderValue(EqualVersion()), false, IN_CF),
155    TestData(HeaderValue(HighVersion()), false, IN_CF),
156    TestData(LongHeaderValue(LowVersion()), false, IN_IE),
157    TestData(LongHeaderValue(EqualVersion()), false, IN_CF),
158    TestData(LongHeaderValue(HighVersion()), false, IN_CF)));
159INSTANTIATE_TEST_CASE_P(HttpHeader, HeaderTest, testing::Values(
160    TestData(HeaderValue(LowVersion()), true, IN_IE),
161    TestData(HeaderValue(EqualVersion()), true, IN_CF),
162    TestData(HeaderValue(HighVersion()), true, IN_CF),
163    TestData(LongHeaderValue(LowVersion()), true, IN_IE),
164    TestData(LongHeaderValue(EqualVersion()), true, IN_CF),
165    TestData(LongHeaderValue(HighVersion()), true, IN_CF)));
166INSTANTIATE_TEST_CASE_P(CorruptValueHeader, HeaderTest, testing::Values(
167    TestData(CorruptHeaderValue(LowVersion()), true, IN_IE),
168    TestData(CorruptHeaderValue(EqualVersion()), true, IN_IE),
169    TestData(CorruptHeaderValue(HighVersion()), true, IN_IE),
170    TestData(CorruptHeaderValue(LowVersion()), false, IN_IE),
171    TestData(CorruptHeaderValue(EqualVersion()), false, IN_IE),
172    TestData(CorruptHeaderValue(HighVersion()), false, IN_IE)));
173
174TEST_P(HeaderTest, HandleXUaCompatibleHeader) {
175  std::wstring url = GetParam().GetUrl(&server_mock_);
176  LoadedInRenderer expected_renderer = GetParam().GetExpectedRenderer();
177
178  GetParam().ExpectOnServer(&server_mock_);
179  ie_mock_.ExpectNavigation(expected_renderer, url);
180
181  EXPECT_CALL(ie_mock_, OnLoad(expected_renderer, testing::StrEq(url)))
182      .WillOnce(CloseBrowserMock(&ie_mock_));
183
184  LaunchIEAndNavigate(url);
185}
186
187}  // namespace chrome_frame_test
188