Initial import of unittests using GTest/GMock.

R=jochen@chromium.org, svenpanne@chromium.org

Review URL: https://codereview.chromium.org/439863004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22847 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-08-05 08:07:25 +00:00
parent 90bbdacbf8
commit 62ac0d1050
17 changed files with 528 additions and 6 deletions

View File

@ -11,6 +11,7 @@
'../samples/samples.gyp:*',
'../src/d8.gyp:d8',
'../test/cctest/cctest.gyp:*',
'../test/unittests/unittests.gyp:*',
],
'conditions': [
['component!="shared_library"', {

4
test/unittests/DEPS Normal file
View File

@ -0,0 +1,4 @@
include_rules = [
"+src",
"+testing",
]

View File

@ -0,0 +1,12 @@
// Copyright 2014 the V8 project 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 "src/compiler/instruction-selector-impl.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace v8 {
namespace internal {
namespace compiler {} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,78 @@
// Copyright 2014 the V8 project 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 "test/unittests/compiler/test-instruction-selector.h"
#include "test/unittests/unittests.h"
namespace v8 {
namespace internal {
namespace compiler {
InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
InstructionSelectorTest::StreamBuilderMode mode) {
Schedule* schedule = Export();
EXPECT_NE(0, graph()->NodeCount());
CompilationInfo info(test_->isolate(), test_->zone());
Linkage linkage(&info, call_descriptor());
InstructionSequence sequence(&linkage, graph(), schedule);
SourcePositionTable source_position_table(graph());
InstructionSelector selector(&sequence, &source_position_table);
selector.SelectInstructions();
OFStream out(stdout);
out << "--- Code sequence after instruction selection ---" << endl
<< sequence;
Stream s;
for (InstructionSequence::const_iterator i = sequence.begin();
i != sequence.end(); ++i) {
Instruction* instr = *i;
if (instr->opcode() < 0) continue;
if (mode == kTargetInstructions) {
switch (instr->arch_opcode()) {
#define CASE(Name) \
case k##Name: \
break;
TARGET_ARCH_OPCODE_LIST(CASE)
#undef CASE
default:
continue;
}
}
for (size_t i = 0; i < instr->OutputCount(); ++i) {
InstructionOperand* output = instr->OutputAt(i);
EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
if (output->IsConstant()) {
s.constants_.insert(std::make_pair(
output->index(), sequence.GetConstant(output->index())));
}
}
for (size_t i = 0; i < instr->InputCount(); ++i) {
InstructionOperand* input = instr->InputAt(i);
EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
if (input->IsImmediate()) {
s.immediates_.insert(std::make_pair(
input->index(), sequence.GetImmediate(input->index())));
}
}
s.instructions_.push_back(instr);
}
return s;
}
COMPILER_TEST_F(InstructionSelectorTest, ReturnZero) {
StreamBuilder m(this, kMachineWord32);
m.Return(m.Int32Constant(0));
Stream s = m.Build(kAllInstructions);
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kArchNop, s[0]->arch_opcode());
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
EXPECT_EQ(kArchRet, s[1]->arch_opcode());
EXPECT_EQ(1U, s[1]->InputCount());
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,88 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_TEST_H_
#define V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_TEST_H_
#include <deque>
#include "src/compiler/instruction-selector.h"
#include "src/compiler/raw-machine-assembler.h"
#include "test/unittests/test-zone.h"
namespace v8 {
namespace internal {
namespace compiler {
class InstructionSelectorTest : public ContextTest, public ZoneTest {
public:
InstructionSelectorTest() {}
protected:
class Stream;
enum StreamBuilderMode { kAllInstructions, kTargetInstructions };
class StreamBuilder : public RawMachineAssembler {
public:
StreamBuilder(InstructionSelectorTest* test,
MachineRepresentation return_type)
: RawMachineAssembler(new (test->zone()) Graph(test->zone()),
CallDescriptorBuilder(test->zone(), return_type)),
test_(test) {}
Stream Build(StreamBuilderMode mode = kTargetInstructions);
private:
MachineCallDescriptorBuilder* CallDescriptorBuilder(
Zone* zone, MachineRepresentation return_type) {
return new (zone) MachineCallDescriptorBuilder(return_type, 0, NULL);
}
private:
InstructionSelectorTest* test_;
};
class Stream {
public:
size_t size() const { return instructions_.size(); }
const Instruction* operator[](size_t index) const {
EXPECT_LT(index, size());
return instructions_[index];
}
int32_t ToInt32(const InstructionOperand* operand) const {
return ToConstant(operand).ToInt32();
}
private:
Constant ToConstant(const InstructionOperand* operand) const {
ConstantMap::const_iterator i;
if (operand->IsConstant()) {
i = constants_.find(operand->index());
EXPECT_NE(constants_.end(), i);
} else {
EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
i = immediates_.find(operand->index());
EXPECT_NE(immediates_.end(), i);
}
EXPECT_EQ(operand->index(), i->first);
return i->second;
}
friend class StreamBuilder;
typedef std::map<int, Constant> ConstantMap;
ConstantMap constants_;
ConstantMap immediates_;
std::deque<Instruction*> instructions_;
};
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_TEST_H_

View File

@ -0,0 +1,39 @@
// Copyright 2014 the V8 project 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 "test/unittests/test-isolate.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::NotNull;
namespace v8 {
namespace internal {
IsolateTest::IsolateTest() : isolate_(v8::Isolate::New()) {
ASSERT_THAT(isolate_, NotNull());
isolate_->Enter();
}
IsolateTest::~IsolateTest() {
ASSERT_THAT(isolate_, NotNull());
isolate_->Exit();
isolate_->Dispose();
isolate_ = NULL;
}
v8::Isolate* IsolateTest::isolate() const {
EXPECT_THAT(isolate_, NotNull());
return isolate_;
}
TEST_F(IsolateTest, GetCurrent) {
EXPECT_THAT(v8::Isolate::GetCurrent(), NotNull());
EXPECT_EQ(v8::Isolate::GetCurrent(), isolate());
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,42 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UNITTESTS_TEST_ISOLATE_H_
#define V8_UNITTESTS_TEST_ISOLATE_H_
#include "test/unittests/unittests.h"
namespace v8 {
namespace internal {
class IsolateTest : public EngineTest {
public:
IsolateTest();
virtual ~IsolateTest();
v8::Isolate* isolate() const;
Isolate* i_isolate() const { return reinterpret_cast<Isolate*>(isolate()); }
private:
v8::Isolate* isolate_;
DISALLOW_COPY_AND_ASSIGN(IsolateTest);
};
class ContextTest : public virtual IsolateTest {
public:
ContextTest()
: handle_scope_(isolate()), context_scope_(v8::Context::New(isolate())) {}
virtual ~ContextTest() {}
private:
v8::HandleScope handle_scope_;
v8::Context::Scope context_scope_;
};
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_TEST_ISOLATE_H_

View File

@ -0,0 +1,17 @@
// Copyright 2014 the V8 project 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 "test/unittests/test-zone.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace v8 {
namespace internal {
TEST_F(ZoneTest, AllocationSizeIsEmptyOnStart) {
EXPECT_EQ(0u, zone()->allocation_size());
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,29 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UNITTESTS_TEST_ZONE_H_
#define V8_UNITTESTS_TEST_ZONE_H_
#include "src/zone.h"
#include "test/unittests/test-isolate.h"
namespace v8 {
namespace internal {
class ZoneTest : public virtual IsolateTest {
public:
ZoneTest() : zone_(i_isolate()) {}
virtual ~ZoneTest() {}
Isolate* isolate() const { return i_isolate(); }
Zone* zone() { return &zone_; }
private:
Zone zone_;
};
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_TEST_ZONE_H_

51
test/unittests/testcfg.py Normal file
View File

@ -0,0 +1,51 @@
# Copyright 2014 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import shutil
from testrunner.local import commands
from testrunner.local import testsuite
from testrunner.local import utils
from testrunner.objects import testcase
class UnitTestsSuite(testsuite.TestSuite):
def __init__(self, name, root):
super(UnitTestsSuite, self).__init__(name, root)
def ListTests(self, context):
shell = os.path.abspath(os.path.join(context.shell_dir, self.shell()))
if utils.IsWindows():
shell += ".exe"
output = commands.Execute(context.command_prefix +
[shell, "--gtest_list_tests"] +
context.extra_flags)
if output.exit_code != 0:
print output.stdout
print output.stderr
return []
tests = []
test_case = ''
for test_desc in output.stdout.strip().split():
if test_desc.endswith('.'):
test_case = test_desc
else:
test = testcase.TestCase(self, test_case + test_desc, dependency=None)
tests.append(test)
tests.sort()
return tests
def GetFlagsForTestCase(self, testcase, context):
return (testcase.flags + ["--gtest_filter=" + testcase.path] +
["--gtest_random_seed=%s" % context.random_seed] +
["--gtest_print_time=0"] +
context.mode_flags)
def shell(self):
return "unittests"
def GetSuite(name, root):
return UnitTestsSuite(name, root)

View File

@ -0,0 +1,50 @@
// Copyright 2014 the V8 project 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 <cstdlib>
#include <cstring>
#include <memory>
#include "include/libplatform/libplatform.h"
#include "test/unittests/unittests.h"
#include "testing/gmock/include/gmock/gmock.h"
using ::testing::IsNull;
using ::testing::NotNull;
namespace v8 {
namespace internal {
// static
v8::Platform* EngineTest::platform_ = NULL;
// static
void EngineTest::SetUpTestCase() {
EXPECT_THAT(platform_, IsNull());
platform_ = v8::platform::CreateDefaultPlatform();
EXPECT_THAT(platform_, NotNull());
v8::V8::InitializePlatform(platform_);
EXPECT_TRUE(v8::V8::Initialize());
}
// static
void EngineTest::TearDownTestCase() {
EXPECT_THAT(platform_, NotNull());
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete platform_;
platform_ = NULL;
}
} // namespace internal
} // namespace v8
int main(int argc, char** argv) {
testing::InitGoogleMock(&argc, argv);
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,54 @@
# Copyright 2014 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
'targets': [
{
'target_name': 'unittests',
'type': 'executable',
'dependencies': [
'../../testing/gmock.gyp:gmock',
'../../testing/gtest.gyp:gtest',
'../../tools/gyp/v8.gyp:v8_libplatform',
],
'include_dirs': [
'../..',
],
'sources': [ ### gcmole(all) ###
'compiler/test-instruction-selector.cc',
'compiler/test-instruction-selector.h',
'test-isolate.cc',
'test-isolate.h',
'test-zone.cc',
'test-zone.h',
'unittests.cc',
'unittests.h',
],
'conditions': [
['v8_target_arch=="arm"', {
'sources': [ ### gcmole(arch:arm) ###
'compiler/arm/test-instruction-selector-arm.cc',
]
}],
['component=="shared_library"', {
# unittests can't be built against a shared library, so we need to
# depend on the underlying static target in that case.
'conditions': [
['v8_use_snapshot=="true"', {
'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
},
{
'dependencies': [
'../../tools/gyp/v8.gyp:v8_nosnapshot',
],
}],
],
}, {
'dependencies': ['../../tools/gyp/v8.gyp:v8'],
}],
],
},
],
}

View File

@ -0,0 +1,47 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UNITTESTS_UNITTESTS_H_
#define V8_UNITTESTS_UNITTESTS_H_
#include "src/compiler/pipeline.h"
#include "testing/gtest/include/gtest/gtest.h"
// The COMPILER_TEST(Case, Name) macro works just like
// TEST(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
#if V8_TURBOFAN_TARGET
#define COMPILER_TEST(Case, Name) TEST(Case, Name)
#else // V8_TURBOFAN_TARGET
#define COMPILER_TEST(Case, Name) TEST(Case, DISABLED_##Name)
#endif // V8_TURBOFAN_TARGET
// The COMPILER_TEST_F(Case, Name) macro works just like
// TEST_F(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
#if V8_TURBOFAN_TARGET
#define COMPILER_TEST_F(Case, Name) TEST_F(Case, Name)
#else // V8_TURBOFAN_TARGET
#define COMPILER_TEST_F(Case, Name) TEST_F(Case, DISABLED_##Name)
#endif // V8_TURBOFAN_TARGET
namespace v8 {
namespace internal {
class EngineTest : public ::testing::Test {
public:
virtual ~EngineTest() {}
static void SetUpTestCase();
static void TearDownTestCase();
private:
static v8::Platform* platform_;
};
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_UNITTESTS_H_

View File

@ -0,0 +1,6 @@
# Copyright 2014 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
[
]

View File

@ -37,9 +37,6 @@
'gtest/src/gtest-test-part.cc',
'gtest/src/gtest-typed-test.cc',
'gtest/src/gtest.cc',
'multiprocess_func_list.cc',
'multiprocess_func_list.h',
'platform_test.h',
],
'sources!': [
'gtest/src/gtest-all.cc', # Not needed by our build.

View File

@ -101,7 +101,7 @@ whitespace/tab
whitespace/todo
""".split()
# TODO(bmeurer): Fix and re-enable readability/check
#TODO(bmeurer) : Fix and re - enable readability / check
LINT_OUTPUT_PATTERN = re.compile(r'^.+[:(]\d+[:)]|^Done processing')
@ -236,7 +236,8 @@ class CppLintProcessor(SourceFileProcessor):
or (name in CppLintProcessor.IGNORE_LINT))
def GetPathsToSearch(self):
return ['src', 'include', 'samples', join('test', 'cctest')]
return ['src', 'include', 'samples', join('test', 'cctest'),
join('test', 'unittests')]
def GetCpplintScript(self, prio_path):
for path in [prio_path] + os.environ["PATH"].split(os.pathsep):

View File

@ -50,7 +50,13 @@ from testrunner.objects import context
ARCH_GUESS = utils.DefaultArch()
DEFAULT_TESTS = ["mjsunit", "fuzz-natives", "cctest", "message", "preparser"]
DEFAULT_TESTS = [
"mjsunit",
"fuzz-natives",
"cctest",
"unittests",
"message",
"preparser"]
TIMEOUT_DEFAULT = 60
TIMEOUT_SCALEFACTOR = {"debug" : 4,
"release" : 1 }