// Copyright (c) 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/spdy/spdy_alt_svc_wire_format.h" #include "base/logging.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/platform_test.h" using ::testing::_; using base::StringPiece; namespace net { namespace test { // Expose all private methods of class SpdyAltSvcWireFormat. class SpdyAltSvcWireFormatPeer { public: static void SkipWhiteSpace(StringPiece::const_iterator* c, StringPiece::const_iterator end) { SpdyAltSvcWireFormat::SkipWhiteSpace(c, end); } static bool PercentDecode(StringPiece::const_iterator c, StringPiece::const_iterator end, std::string* output) { return SpdyAltSvcWireFormat::PercentDecode(c, end, output); } static bool ParseAltAuthority(StringPiece::const_iterator c, StringPiece::const_iterator end, std::string* host, uint16_t* port) { return SpdyAltSvcWireFormat::ParseAltAuthority(c, end, host, port); } static bool ParsePositiveInteger16(StringPiece::const_iterator c, StringPiece::const_iterator end, uint16_t* max_age) { return SpdyAltSvcWireFormat::ParsePositiveInteger16(c, end, max_age); } static bool ParsePositiveInteger32(StringPiece::const_iterator c, StringPiece::const_iterator end, uint32_t* max_age) { return SpdyAltSvcWireFormat::ParsePositiveInteger32(c, end, max_age); } static bool ParseProbability(StringPiece::const_iterator c, StringPiece::const_iterator end, double* probability) { return SpdyAltSvcWireFormat::ParseProbability(c, end, probability); } }; } // namespace test namespace { // Generate header field values, possibly with multiply defined parameters and // random case, and corresponding AlternativeService entries. void FuzzHeaderFieldValue( int i, std::string* header_field_value, SpdyAltSvcWireFormat::AlternativeService* expected_altsvc) { if (!header_field_value->empty()) { header_field_value->push_back(','); } expected_altsvc->protocol_id = "a=b%c"; header_field_value->append("a%3Db%25c=\""); expected_altsvc->host = ""; if (i & 1 << 0) { expected_altsvc->host = "foo\"bar\\baz"; header_field_value->append("foo\\\"bar\\\\baz"); } expected_altsvc->port = 42; header_field_value->append(":42\""); if (i & 1 << 1) { header_field_value->append(" "); } if (i & 3 << 2) { expected_altsvc->max_age = 1111; header_field_value->append(";"); if (i & 1 << 2) { header_field_value->append(" "); } header_field_value->append("mA=1111"); if (i & 2 << 2) { header_field_value->append(" "); } } if (i & 1 << 4) { header_field_value->append("; J=s"); } if (i & 1 << 5) { expected_altsvc->probability = 0.33; header_field_value->append("; P=\".33\""); } if (i & 1 << 6) { expected_altsvc->probability = 0.0; expected_altsvc->version.push_back(24); header_field_value->append("; p=\"0\";v=\"24\""); } if (i & 1 << 7) { expected_altsvc->max_age = 999999999; header_field_value->append("; Ma=999999999"); } if (i & 1 << 8) { expected_altsvc->probability = 0.1; header_field_value->append("; P=\"0.1\""); } if (i & 1 << 9) { header_field_value->append(";"); } if (i & 1 << 10) { header_field_value->append(" "); } if (i & 1 << 11) { header_field_value->append(","); } if (i & 1 << 12) { header_field_value->append(" "); } } // Generate AlternativeService entries and corresponding header field values in // canonical form, that is, what SerializeHeaderFieldValue() should output. void FuzzAlternativeService(int i, SpdyAltSvcWireFormat::AlternativeService* altsvc, std::string* expected_header_field_value) { if (!expected_header_field_value->empty()) { expected_header_field_value->push_back(','); } altsvc->protocol_id = "a=b%c"; altsvc->port = 42; expected_header_field_value->append("a%3Db%25c=\""); if (i & 1 << 0) { altsvc->host = "foo\"bar\\baz"; expected_header_field_value->append("foo\\\"bar\\\\baz"); } expected_header_field_value->append(":42\""); if (i & 1 << 1) { altsvc->max_age = 1111; expected_header_field_value->append("; ma=1111"); } if (i & 1 << 2) { altsvc->probability = 0.33; expected_header_field_value->append("; p=\"0.33\""); } if (i & 1 << 3) { altsvc->version.push_back(24); altsvc->version.push_back(25); expected_header_field_value->append("; v=\"24,25\""); } } class SpdyAltSvcWireFormatTest : public ::testing::Test {}; // Tests of public API. TEST(SpdyAltSvcWireFormatTest, DefaultValues) { SpdyAltSvcWireFormat::AlternativeService altsvc; EXPECT_EQ("", altsvc.protocol_id); EXPECT_EQ("", altsvc.host); EXPECT_EQ(0u, altsvc.port); EXPECT_EQ(86400u, altsvc.max_age); EXPECT_DOUBLE_EQ(1.0, altsvc.probability); EXPECT_TRUE(altsvc.version.empty()); } TEST(SpdyAltSvcWireFormatTest, ParseInvalidEmptyHeaderFieldValue) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; ASSERT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue("", &altsvc_vector)); } TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueClear) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; ASSERT_TRUE( SpdyAltSvcWireFormat::ParseHeaderFieldValue("clear", &altsvc_vector)); EXPECT_EQ(0u, altsvc_vector.size()); } // Fuzz test of ParseHeaderFieldValue() with optional whitespaces, ignored // parameters, duplicate parameters, trailing space, trailing alternate service // separator, etc. Single alternative service at a time. TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValue) { for (int i = 0; i < 1 << 13; ++i) { std::string header_field_value; SpdyAltSvcWireFormat::AlternativeService expected_altsvc; FuzzHeaderFieldValue(i, &header_field_value, &expected_altsvc); SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(header_field_value, &altsvc_vector)); ASSERT_EQ(1u, altsvc_vector.size()); EXPECT_EQ(expected_altsvc.protocol_id, altsvc_vector[0].protocol_id); EXPECT_EQ(expected_altsvc.host, altsvc_vector[0].host); EXPECT_EQ(expected_altsvc.port, altsvc_vector[0].port); EXPECT_EQ(expected_altsvc.max_age, altsvc_vector[0].max_age); EXPECT_DOUBLE_EQ(expected_altsvc.probability, altsvc_vector[0].probability); EXPECT_EQ(expected_altsvc.version, altsvc_vector[0].version); // Roundtrip test starting with |altsvc_vector|. std::string reserialized_header_field_value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector); SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( reserialized_header_field_value, &roundtrip_altsvc_vector)); ASSERT_EQ(1u, roundtrip_altsvc_vector.size()); EXPECT_EQ(expected_altsvc.protocol_id, roundtrip_altsvc_vector[0].protocol_id); EXPECT_EQ(expected_altsvc.host, roundtrip_altsvc_vector[0].host); EXPECT_EQ(expected_altsvc.port, roundtrip_altsvc_vector[0].port); EXPECT_EQ(expected_altsvc.max_age, roundtrip_altsvc_vector[0].max_age); EXPECT_DOUBLE_EQ(expected_altsvc.probability, roundtrip_altsvc_vector[0].probability); EXPECT_EQ(expected_altsvc.version, roundtrip_altsvc_vector[0].version); } } // Fuzz test of ParseHeaderFieldValue() with optional whitespaces, ignored // parameters, duplicate parameters, trailing space, trailing alternate service // separator, etc. Possibly multiple alternative service at a time. TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueMultiple) { for (int i = 0; i < 1 << 13;) { std::string header_field_value; SpdyAltSvcWireFormat::AlternativeServiceVector expected_altsvc_vector; // This will generate almost two hundred header field values with two, // three, four, five, six, and seven alternative services each, and // thousands with a single one. do { SpdyAltSvcWireFormat::AlternativeService expected_altsvc; FuzzHeaderFieldValue(i, &header_field_value, &expected_altsvc); expected_altsvc_vector.push_back(expected_altsvc); ++i; } while ((i < 1 << 13) && (i % 6 < i % 7)); SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(header_field_value, &altsvc_vector)); ASSERT_EQ(expected_altsvc_vector.size(), altsvc_vector.size()); for (unsigned int j = 0; j < altsvc_vector.size(); ++j) { EXPECT_EQ(expected_altsvc_vector[j].protocol_id, altsvc_vector[j].protocol_id); EXPECT_EQ(expected_altsvc_vector[j].host, altsvc_vector[j].host); EXPECT_EQ(expected_altsvc_vector[j].port, altsvc_vector[j].port); EXPECT_EQ(expected_altsvc_vector[j].max_age, altsvc_vector[j].max_age); EXPECT_DOUBLE_EQ(expected_altsvc_vector[j].probability, altsvc_vector[j].probability); EXPECT_EQ(expected_altsvc_vector[j].version, altsvc_vector[j].version); } // Roundtrip test starting with |altsvc_vector|. std::string reserialized_header_field_value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector); SpdyAltSvcWireFormat::AlternativeServiceVector roundtrip_altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( reserialized_header_field_value, &roundtrip_altsvc_vector)); ASSERT_EQ(expected_altsvc_vector.size(), roundtrip_altsvc_vector.size()); for (unsigned int j = 0; j < roundtrip_altsvc_vector.size(); ++j) { EXPECT_EQ(expected_altsvc_vector[j].protocol_id, roundtrip_altsvc_vector[j].protocol_id); EXPECT_EQ(expected_altsvc_vector[j].host, roundtrip_altsvc_vector[j].host); EXPECT_EQ(expected_altsvc_vector[j].port, roundtrip_altsvc_vector[j].port); EXPECT_EQ(expected_altsvc_vector[j].max_age, roundtrip_altsvc_vector[j].max_age); EXPECT_DOUBLE_EQ(expected_altsvc_vector[j].probability, roundtrip_altsvc_vector[j].probability); EXPECT_EQ(expected_altsvc_vector[j].version, roundtrip_altsvc_vector[j].version); } } } TEST(SpdyAltSvcWireFormatTest, SerializeEmptyHeaderFieldValue) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; EXPECT_EQ("clear", SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); } // Test ParseHeaderFieldValue() and SerializeHeaderFieldValue() on the same pair // of |expected_header_field_value| and |altsvc|, with and without hostname and // each // parameter. Single alternative service at a time. TEST(SpdyAltSvcWireFormatTest, RoundTrip) { for (int i = 0; i < 1 << 4; ++i) { SpdyAltSvcWireFormat::AlternativeService altsvc; std::string expected_header_field_value; FuzzAlternativeService(i, &altsvc, &expected_header_field_value); // Test ParseHeaderFieldValue(). SpdyAltSvcWireFormat::AlternativeServiceVector parsed_altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( expected_header_field_value, &parsed_altsvc_vector)); ASSERT_EQ(1u, parsed_altsvc_vector.size()); EXPECT_EQ(altsvc.protocol_id, parsed_altsvc_vector[0].protocol_id); EXPECT_EQ(altsvc.host, parsed_altsvc_vector[0].host); EXPECT_EQ(altsvc.port, parsed_altsvc_vector[0].port); EXPECT_EQ(altsvc.max_age, parsed_altsvc_vector[0].max_age); EXPECT_DOUBLE_EQ(altsvc.probability, parsed_altsvc_vector[0].probability); EXPECT_EQ(altsvc.version, parsed_altsvc_vector[0].version); // Test SerializeHeaderFieldValue(). SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; altsvc_vector.push_back(altsvc); EXPECT_EQ(expected_header_field_value, SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); } } // Test ParseHeaderFieldValue() and SerializeHeaderFieldValue() on the same pair // of |expected_header_field_value| and |altsvc|, with and without hostname and // each // parameter. Multiple alternative services at a time. TEST(SpdyAltSvcWireFormatTest, RoundTripMultiple) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; std::string expected_header_field_value; for (int i = 0; i < 1 << 4; ++i) { SpdyAltSvcWireFormat::AlternativeService altsvc; FuzzAlternativeService(i, &altsvc, &expected_header_field_value); altsvc_vector.push_back(altsvc); } // Test ParseHeaderFieldValue(). SpdyAltSvcWireFormat::AlternativeServiceVector parsed_altsvc_vector; ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( expected_header_field_value, &parsed_altsvc_vector)); ASSERT_EQ(altsvc_vector.size(), parsed_altsvc_vector.size()); SpdyAltSvcWireFormat::AlternativeServiceVector::iterator expected_it = altsvc_vector.begin(); SpdyAltSvcWireFormat::AlternativeServiceVector::iterator parsed_it = parsed_altsvc_vector.begin(); for (; expected_it != altsvc_vector.end(); ++expected_it, ++parsed_it) { EXPECT_EQ(expected_it->protocol_id, parsed_it->protocol_id); EXPECT_EQ(expected_it->host, parsed_it->host); EXPECT_EQ(expected_it->port, parsed_it->port); EXPECT_EQ(expected_it->max_age, parsed_it->max_age); EXPECT_DOUBLE_EQ(expected_it->probability, parsed_it->probability); EXPECT_EQ(expected_it->version, parsed_it->version); } // Test SerializeHeaderFieldValue(). EXPECT_EQ(expected_header_field_value, SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc_vector)); } // ParseHeaderFieldValue() should return false on malformed field values: // invalid percent encoding, unmatched quotation mark, empty port, non-numeric // characters in numeric fields, negative or larger than 1.0 probability. TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueInvalid) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; const char* invalid_field_value_array[] = {"a%", "a%x", "a%b", "a%9z", "a=", "a=\"", "a=\"b\"", "a=\":\"", "a=\"c:\"", "a=\"c:foo\"", "a=\"c:42foo\"", "a=\"b:42\"bar", "a=\"b:42\" ; m", "a=\"b:42\" ; min-age", "a=\"b:42\" ; ma", "a=\"b:42\" ; ma=", "a=\"b:42\" ; ma=ma", "a=\"b:42\" ; ma=123bar", "a=\"b:42\" ; p=\"-2\"", "a=\"b:42\" ; p=\"..\"", "a=\"b:42\" ; p=\"1.05\"", "a=\"b:42\" ; p=0.4", "a=\"b:42\" ; p=\" 1.0\"", "a=\"b:42\" ; v=24", "a=\"b:42\" ; v=24,25", "a=\"b:42\" ; v=\"-3\"", "a=\"b:42\" ; v=\"1.2\"", "a=\"b:42\" ; v=\"24,\""}; for (const char* invalid_field_value : invalid_field_value_array) { EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( invalid_field_value, &altsvc_vector)) << invalid_field_value; } } // ParseHeaderFieldValue() should return false on a field values truncated // before closing quotation mark, without trying to access memory beyond the end // of the input. TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) { SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; const char* field_value_array[] = { "p=\":137\"", "p=\"foo:137\"", "p%25=\"foo\\\"bar\\\\baz:137\""}; for (const std::string& field_value : field_value_array) { for (size_t len = 1; len < field_value.size(); ++len) { EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue( field_value.substr(0, len), &altsvc_vector)) << len; } } } // Tests of private methods. // Test SkipWhiteSpace(). TEST(SpdyAltSvcWireFormatTest, SkipWhiteSpace) { StringPiece input("a \tb "); StringPiece::const_iterator c = input.begin(); test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.begin(), c); ++c; test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.begin() + 3, c); ++c; test::SpdyAltSvcWireFormatPeer::SkipWhiteSpace(&c, input.end()); ASSERT_EQ(input.end(), c); } // Test PercentDecode() on valid input. TEST(SpdyAltSvcWireFormatTest, PercentDecodeValid) { StringPiece input(""); std::string output; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( input.begin(), input.end(), &output)); EXPECT_EQ("", output); input = StringPiece("foo"); output.clear(); ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( input.begin(), input.end(), &output)); EXPECT_EQ("foo", output); input = StringPiece("%2ca%5Cb"); output.clear(); ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::PercentDecode( input.begin(), input.end(), &output)); EXPECT_EQ(",a\\b", output); } // Test PercentDecode() on invalid input. TEST(SpdyAltSvcWireFormatTest, PercentDecodeInvalid) { const char* invalid_input_array[] = {"a%", "a%x", "a%b", "%J22", "%9z"}; for (const char* invalid_input : invalid_input_array) { StringPiece input(invalid_input); std::string output; EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::PercentDecode( input.begin(), input.end(), &output)) << input; } } // Test ParseAltAuthority() on valid input. TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityValid) { StringPiece input(":42"); std::string host; uint16_t port; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)); EXPECT_TRUE(host.empty()); EXPECT_EQ(42, port); input = StringPiece("foo:137"); ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)); EXPECT_EQ("foo", host); EXPECT_EQ(137, port); } // Test ParseAltAuthority() on invalid input: empty string, no port, zero port, // non-digit characters following port. TEST(SpdyAltSvcWireFormatTest, ParseAltAuthorityInvalid) { const char* invalid_input_array[] = {"", ":", "foo:", ":bar", ":0", "foo:0", ":12bar", "foo:23bar", " ", ":12 ", "foo:12 "}; for (const char* invalid_input : invalid_input_array) { StringPiece input(invalid_input); std::string host; uint16_t port; EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseAltAuthority( input.begin(), input.end(), &host, &port)) << input; } } // Test ParseInteger() on valid input. TEST(SpdyAltSvcWireFormatTest, ParseIntegerValid) { StringPiece input("3"); uint16_t value; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)); EXPECT_EQ(3, value); input = StringPiece("1337"); ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)); EXPECT_EQ(1337, value); } // Test ParseIntegerValid() on invalid input: empty, zero, non-numeric, trailing // non-numeric characters. TEST(SpdyAltSvcWireFormatTest, ParseIntegerInvalid) { const char* invalid_input_array[] = {"", " ", "a", "0", "00", "1 ", "12b"}; for (const char* invalid_input : invalid_input_array) { StringPiece input(invalid_input); uint16_t value; EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value)) << input; } } // Test ParseIntegerValid() around overflow limit. TEST(SpdyAltSvcWireFormatTest, ParseIntegerOverflow) { // Largest possible uint16_t value. StringPiece input("65535"); uint16_t value16; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); EXPECT_EQ(65535, value16); // Overflow uint16_t, ParsePositiveInteger16() should return false. input = StringPiece("65536"); ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); // However, even if overflow is not checked for, 65536 overflows to 0, which // returns false anyway. Check for a larger number which overflows to 1. input = StringPiece("65537"); ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger16( input.begin(), input.end(), &value16)); // Largest possible uint32_t value. input = StringPiece("4294967295"); uint32_t value32; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); EXPECT_EQ(4294967295, value32); // Overflow uint32_t, ParsePositiveInteger32() should return false. input = StringPiece("4294967296"); ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); // However, even if overflow is not checked for, 4294967296 overflows to 0, // which returns false anyway. Check for a larger number which overflows to // 1. input = StringPiece("4294967297"); ASSERT_FALSE(test::SpdyAltSvcWireFormatPeer::ParsePositiveInteger32( input.begin(), input.end(), &value32)); } // Test ParseProbability() on valid input. TEST(SpdyAltSvcWireFormatTest, ParseProbabilityValid) { StringPiece input("0"); double probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(0.0, probability); input = StringPiece("0."); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(0.0, probability); input = StringPiece("0.0"); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(0.0, probability); input = StringPiece("1"); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(1.0, probability); input = StringPiece("1."); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(1.0, probability); input = StringPiece("1.0"); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(1.0, probability); input = StringPiece("0.37"); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(0.37, probability); input = StringPiece("0.72"); probability = -2.0; ASSERT_TRUE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); EXPECT_DOUBLE_EQ(0.72, probability); } // Test ParseProbability() on invalid input: empty string, non-digit characters, // negative input, larger than 1.0. TEST(SpdyAltSvcWireFormatTest, ParseProbabilityInvalid) { const char* invalid_input_array[] = {"", " ", ".", "a", "-2", "-0", "0a", "1b ", "0.9z2", "0.33 ", "0.98x", "2.0", "1.0001", "1.00001", "1.000001"}; for (const char* invalid_input : invalid_input_array) { StringPiece input(invalid_input); double probability; EXPECT_FALSE(test::SpdyAltSvcWireFormatPeer::ParseProbability( input.begin(), input.end(), &probability)); } } } // namespace } // namespace net