blob: d2461559848eb83580a975f58ee67da2d9364203 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed 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.
*/
#include <cmath>
#include "base/stringprintf.h"
#include "cobalt/bindings/testing/bindings_test_base.h"
#include "cobalt/bindings/testing/numeric_types_test_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::ResultOf;
using ::testing::Return;
namespace cobalt {
namespace bindings {
namespace testing {
namespace {
template <typename T>
class NumericTypeBindingsTest
: public InterfaceBindingsTest<T, NumericTypesTestInterface> {
public:
};
template <typename T>
class IntegerTypeBindingsTest : public NumericTypeBindingsTest<T> {};
template <typename T>
class FloatingPointTypeBindingsTest : public NumericTypeBindingsTest<T> {};
typedef ::testing::Types<ByteTypeTest, OctetTypeTest, ShortTypeTest,
UnsignedShortTypeTest, LongTypeTest,
UnsignedLongTypeTest, DoubleTypeTest> NumericTypes;
typedef ::testing::Types<ByteTypeTest, OctetTypeTest, ShortTypeTest,
UnsignedShortTypeTest, LongTypeTest,
UnsignedLongTypeTest> IntegerTypes;
typedef ::testing::Types<DoubleTypeTest, UnrestrictedDoubleTypeTest>
FloatingPointTypes;
TYPED_TEST_CASE(NumericTypeBindingsTest, NumericTypes);
TYPED_TEST_CASE(IntegerTypeBindingsTest, IntegerTypes);
TYPED_TEST_CASE(FloatingPointTypeBindingsTest, FloatingPointTypes);
template <typename T>
bool IsNan(T number) {
#if defined(_MSC_VER)
#pragma warning(push)
// On Windows isnan() returns an int.
// warning C4800: 'int' : forcing value to bool 'true' or 'false'
#pragma warning(disable:4800)
#endif
return isnan(number);
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}
} // namespace
TYPED_TEST(NumericTypeBindingsTest, PropertyIsNumber) {
EXPECT_CALL(this->test_mock(), mock_get_property());
std::string result;
std::string script =
StringPrintf("typeof test.%sProperty;", TypeParam::type_string());
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ("number", result.c_str());
}
TYPED_TEST(NumericTypeBindingsTest, ReturnValueIsNumber) {
EXPECT_CALL(this->test_mock(), MockReturnValueOperation());
std::string result;
std::string script = StringPrintf("typeof test.%sReturnOperation();",
TypeParam::type_string());
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ("number", result.c_str());
}
TYPED_TEST(IntegerTypeBindingsTest, PropertyValueRange) {
InSequence in_sequence_dummy;
std::string result;
std::string script =
StringPrintf("test.%sProperty;", TypeParam::type_string());
EXPECT_CALL(this->test_mock(), mock_get_property()).WillOnce(Return(0));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ("0", result.c_str());
EXPECT_CALL(this->test_mock(), mock_get_property())
.WillOnce(Return(TypeParam::min_value()));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ(TypeParam::min_value_string(), result.c_str());
EXPECT_CALL(this->test_mock(), mock_get_property())
.WillOnce(Return(TypeParam::max_value()));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ(TypeParam::max_value_string(), result.c_str());
}
TYPED_TEST(IntegerTypeBindingsTest, ReturnValueRange) {
InSequence in_sequence_dummy;
std::string result;
std::string script =
StringPrintf("test.%sReturnOperation();", TypeParam::type_string());
EXPECT_CALL(this->test_mock(), MockReturnValueOperation())
.WillOnce(Return(0));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ("0", result.c_str());
EXPECT_CALL(this->test_mock(), MockReturnValueOperation())
.WillOnce(Return(TypeParam::min_value()));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ(TypeParam::min_value_string(), result.c_str());
EXPECT_CALL(this->test_mock(), MockReturnValueOperation())
.WillOnce(Return(TypeParam::max_value()));
EXPECT_TRUE(this->EvaluateScript(script, &result));
EXPECT_STREQ(TypeParam::max_value_string(), result.c_str());
}
TYPED_TEST(IntegerTypeBindingsTest, SetPropertyRange) {
InSequence in_sequence_dummy;
EXPECT_CALL(this->test_mock(), mock_set_property(0));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = 0;", TypeParam::type_string()), NULL));
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::min_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = %s;", TypeParam::type_string(),
TypeParam::min_value_string()),
NULL));
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::max_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = %s;", TypeParam::type_string(),
TypeParam::max_value_string()),
NULL));
}
TYPED_TEST(IntegerTypeBindingsTest, ArgumentOperationRange) {
InSequence in_sequence_dummy;
EXPECT_CALL(this->test_mock(), MockArgumentOperation(0));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sArgumentOperation(0);", TypeParam::type_string()),
NULL));
EXPECT_CALL(this->test_mock(), MockArgumentOperation(TypeParam::max_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sArgumentOperation(%s);", TypeParam::type_string(),
TypeParam::max_value_string()),
NULL));
EXPECT_CALL(this->test_mock(), MockArgumentOperation(TypeParam::min_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sArgumentOperation(%s);", TypeParam::type_string(),
TypeParam::min_value_string()),
NULL));
}
// In the absence of extended IDL attributes to check or enforce the range,
// out-of-range values are not clamped.
// https://www.w3.org/TR/WebIDL/#es-byte
// For the signed types (8 bit integer in this example):
// 5. x := sign(x)*floor(abs(x))
// 6. x := x modulo 2^8
// 7. return (x >= 2^7) ? x - 2^8 : x
// For unsigned types, skip step 7.
TYPED_TEST(IntegerTypeBindingsTest, OutOfRangeBehaviour) {
InSequence in_sequence_dummy;
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::min_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = (%s+1);", TypeParam::type_string(),
TypeParam::max_value_string()),
NULL));
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::min_value() + 1));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = (%s+2);", TypeParam::type_string(),
TypeParam::max_value_string()),
NULL));
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::max_value()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = (%s-1);", TypeParam::type_string(),
TypeParam::min_value_string()),
NULL));
EXPECT_CALL(this->test_mock(), mock_set_property(TypeParam::max_value() - 1));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = (%s-2);", TypeParam::type_string(),
TypeParam::min_value_string()),
NULL));
}
TYPED_TEST(FloatingPointTypeBindingsTest, NonFiniteValues) {
InSequence in_sequence_dummy;
if (TypeParam::is_restricted()) {
EXPECT_FALSE(this->EvaluateScript(
StringPrintf("test.%sProperty = Infinity;", TypeParam::type_string()),
NULL));
EXPECT_FALSE(this->EvaluateScript(
StringPrintf("test.%sProperty = -Infinity;", TypeParam::type_string()),
NULL));
EXPECT_FALSE(this->EvaluateScript(
StringPrintf("test.%sProperty = NaN;", TypeParam::type_string()),
NULL));
} else {
EXPECT_CALL(this->test_mock(),
mock_set_property(TypeParam::positive_infinity()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = Infinity;", TypeParam::type_string()),
NULL));
EXPECT_CALL(this->test_mock(),
mock_set_property(TypeParam::negative_infinity()));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = -Infinity;", TypeParam::type_string()),
NULL));
EXPECT_CALL(this->test_mock(),
mock_set_property(
ResultOf(IsNan<typename TypeParam::BaseType>, Eq(true))));
EXPECT_TRUE(this->EvaluateScript(
StringPrintf("test.%sProperty = NaN;", TypeParam::type_string()),
NULL));
}
}
} // namespace testing
} // namespace bindings
} // namespace cobalt