diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index acb6f564ef..e97f9aaafc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -232,6 +232,7 @@ set(TINT_TEST_SRCS ast/struct_member_test.cc ast/struct_member_offset_decoration_test.cc ast/struct_test.cc + ast/switch_statement_test.cc ast/type/alias_type_test.cc ast/type/array_type_test.cc ast/type/bool_type_test.cc diff --git a/src/ast/switch_statement.cc b/src/ast/switch_statement.cc index aabc24292c..3512187d96 100644 --- a/src/ast/switch_statement.cc +++ b/src/ast/switch_statement.cc @@ -37,21 +37,34 @@ SwitchStatement::SwitchStatement( SwitchStatement::~SwitchStatement() = default; bool SwitchStatement::IsValid() const { - return condition_ != nullptr; + if (condition_ == nullptr || !condition_->IsValid()) { + return false; + } + for (const auto& stmt : body_) { + if (stmt == nullptr || !stmt->IsValid()) { + return false; + } + } + return true; } void SwitchStatement::to_str(std::ostream& out, size_t indent) const { make_indent(out, indent); out << "Switch{" << std::endl; condition_->to_str(out, indent + 2); + make_indent(out, indent + 2); out << "{" << std::endl; - for (const auto& stmt : body_) + for (const auto& stmt : body_) { stmt->to_str(out, indent + 4); + } make_indent(out, indent + 2); out << "}" << std::endl; + + make_indent(out, indent); + out << "}" << std::endl; } } // namespace ast diff --git a/src/ast/switch_statement_test.cc b/src/ast/switch_statement_test.cc new file mode 100644 index 0000000000..209f7dad5f --- /dev/null +++ b/src/ast/switch_statement_test.cc @@ -0,0 +1,154 @@ +// Copyright 2020 The Tint Authors. +// +// 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 "src/ast/switch_statement.h" + +#include + +#include "gtest/gtest.h" +#include "src/ast/bool_literal.h" +#include "src/ast/case_statement.h" +#include "src/ast/identifier_expression.h" + +namespace tint { +namespace ast { + +using SwitchStatementTest = testing::Test; + +TEST_F(SwitchStatementTest, Creation) { + auto lit = std::make_unique(true); + auto ident = std::make_unique("ident"); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + + auto ident_ptr = ident.get(); + auto case_ptr = body[0].get(); + + SwitchStatement stmt(std::move(ident), std::move(body)); + EXPECT_EQ(stmt.condition(), ident_ptr); + ASSERT_EQ(stmt.body().size(), 1); + EXPECT_EQ(stmt.body()[0].get(), case_ptr); +} + +TEST_F(SwitchStatementTest, Creation_WithSource) { + auto ident = std::make_unique("ident"); + + SwitchStatement stmt(Source{20, 2}, std::move(ident), + std::vector>()); + auto src = stmt.source(); + EXPECT_EQ(src.line, 20); + EXPECT_EQ(src.column, 2); +} + +TEST_F(SwitchStatementTest, IsSwitch) { + SwitchStatement stmt; + EXPECT_TRUE(stmt.IsSwitch()); +} + +TEST_F(SwitchStatementTest, IsValid) { + auto lit = std::make_unique(true); + auto ident = std::make_unique("ident"); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + + SwitchStatement stmt(std::move(ident), std::move(body)); + EXPECT_TRUE(stmt.IsValid()); +} + +TEST_F(SwitchStatementTest, IsValid_Null_Condition) { + auto lit = std::make_unique(true); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + + SwitchStatement stmt; + stmt.set_body(std::move(body)); + EXPECT_FALSE(stmt.IsValid()); +} + +TEST_F(SwitchStatementTest, IsValid_Invalid_Condition) { + auto lit = std::make_unique(true); + auto ident = std::make_unique(""); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + + SwitchStatement stmt(std::move(ident), std::move(body)); + EXPECT_FALSE(stmt.IsValid()); +} + +TEST_F(SwitchStatementTest, IsValid_Null_BodyStatement) { + auto lit = std::make_unique(true); + auto ident = std::make_unique("ident"); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + body.push_back(nullptr); + + SwitchStatement stmt(std::move(ident), std::move(body)); + EXPECT_FALSE(stmt.IsValid()); +} + +TEST_F(SwitchStatementTest, IsValid_Invalid_BodyStatement) { + auto ident = std::make_unique("ident"); + + std::vector> case_body; + case_body.push_back(nullptr); + + std::vector> body; + body.push_back( + std::make_unique(nullptr, std::move(case_body))); + + SwitchStatement stmt(std::move(ident), std::move(body)); + EXPECT_FALSE(stmt.IsValid()); +} + +TEST_F(SwitchStatementTest, ToStr_Empty) { + auto ident = std::make_unique("ident"); + + SwitchStatement stmt(std::move(ident), {}); + std::ostringstream out; + stmt.to_str(out, 2); + EXPECT_EQ(out.str(), R"( Switch{ + Identifier{ident} + { + } + } +)"); +} + +TEST_F(SwitchStatementTest, ToStr) { + auto lit = std::make_unique(true); + auto ident = std::make_unique("ident"); + std::vector> body; + body.push_back(std::make_unique( + std::move(lit), std::vector>())); + + SwitchStatement stmt(std::move(ident), std::move(body)); + std::ostringstream out; + stmt.to_str(out, 2); + EXPECT_EQ(out.str(), R"( Switch{ + Identifier{ident} + { + Case true{ + } + } + } +)"); +} + +} // namespace ast +} // namespace tint