// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

goog.require('goog.testing.MockControl');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
goog.require('webdriver.http.Request');
goog.require('webdriver.http.XhrClient');
goog.require('webdriver.test.testutil');

function shouldRunTests() {
  return !goog.userAgent.IE || goog.userAgent.isVersionOrHigher(10);
}

// Alias for readability.
var callbackHelper = webdriver.test.testutil.callbackHelper;

function FakeXhr() {}
FakeXhr.prototype.status = 200;
FakeXhr.prototype.responseText = '';
FakeXhr.prototype.open = function() {};
FakeXhr.prototype.send = function() {};
FakeXhr.prototype.getAllResponseHeaders = function() {};
FakeXhr.prototype.setRequestHeader = function() {};

var URL = 'http://localhost:4444/wd/hub';
var REQUEST = new webdriver.http.Request('GET', '/foo');

var control = new goog.testing.MockControl();
var stubs = new goog.testing.PropertyReplacer();
var mockClient, mockXhr;

function setUp() {
  mockClient = control.createStrictMock(webdriver.http.Client);
  mockXhr = control.createStrictMock(FakeXhr);
  stubs.set(goog.global, 'XMLHttpRequest', function() {
    return mockXhr;
  });
}

function tearDown() {
  control.$tearDown();
  stubs.reset();
}

function setXhr(value) {
  stubs.set(goog.global, 'XMLHttpRequest', value);
}

function expectRequest(mockXhr) {
  mockXhr.open(REQUEST.method, URL + REQUEST.path, true);
  for (var header in REQUEST.headers) {
    mockXhr.setRequestHeader(header, REQUEST.headers[header]);
  }
  return mockXhr.send(JSON.stringify(REQUEST.data));
}

function testXhrClient_whenUnableToSendARequest() {
  expectRequest(mockXhr).$does(function() {
    mockXhr.onerror();
  });
  control.$replayAll();

  return new webdriver.http.XhrClient(URL)
      .send(REQUEST)
      .then(fail, function() {
        control.$verifyAll();
      });
}

function testXhrClient_parsesResponseHeaders_windows() {
  expectRequest(mockXhr).$does(function() {
    mockXhr.status = 200;
    mockXhr.responseText = '';
    mockXhr.onload();
  });
  mockXhr.getAllResponseHeaders().$returns([
    'a:b',
    'c: d',
    'e :f',
    'g : h'
  ].join('\r\n'));
  control.$replayAll();

  return new webdriver.http.XhrClient(URL)
      .send(REQUEST)
      .then(function(response) {
        assertEquals(200, response.status);
        assertEquals('', response.body);

        webdriver.test.testutil.assertObjectEquals({
          'a': 'b',
          'c': 'd',
          'e': 'f',
          'g': 'h'
        }, response.headers);

        control.$verifyAll();
      });
}

function testXhrClient_parsesResponseHeaders_unix() {
  expectRequest(mockXhr).$does(function() {
    mockXhr.status = 200;
    mockXhr.responseText = '';
    mockXhr.onload();
  });
  mockXhr.getAllResponseHeaders().$returns([
    'a:b',
    'c: d',
    'e :f',
    'g : h'
  ].join('\n'));
  control.$replayAll();

  return new webdriver.http.XhrClient(URL)
      .send(REQUEST)
      .then(function(response) {
        assertEquals(200, response.status);
        assertEquals('', response.body);

        webdriver.test.testutil.assertObjectEquals({
          'a': 'b',
          'c': 'd',
          'e': 'f',
          'g': 'h'
        }, response.headers);

        control.$verifyAll();
      });
}

function testXhrClient_handlesResponsesWithNoHeaders() {
  expectRequest(mockXhr).$does(function() {
    mockXhr.status = 200;
    mockXhr.responseText = '';
    mockXhr.onload();
  });
  mockXhr.getAllResponseHeaders().$returns('');
  control.$replayAll();

  return new webdriver.http.XhrClient(URL)
      .send(REQUEST)
      .then(function(response) {
        assertEquals(200, response.status);
        assertEquals('', response.body);

        webdriver.test.testutil.assertObjectEquals({}, response.headers);

        control.$verifyAll();
      });
}

function testXhrClient_stripsNullCharactersFromResponseBody() {
  expectRequest(mockXhr).$does(function() {
    mockXhr.status = 200;
    mockXhr.responseText = '\x00foo\x00\x00bar\x00';
    mockXhr.onload();
  });
  mockXhr.getAllResponseHeaders().$returns('');
  control.$replayAll();

  return new webdriver.http.XhrClient(URL)
      .send(REQUEST)
      .then(function(response) {
        assertEquals(200, response.status);
        assertEquals('foobar', response.body);
        webdriver.test.testutil.assertObjectEquals({}, response.headers);
        control.$verifyAll();
      });
}
