| /* |
| * Copyright 2023 WebAssembly Community Group participants |
| * |
| * 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 <set> |
| #include <string> |
| #include <vector> |
| |
| #include "support/dfa_minimization.h" |
| #include "gtest/gtest.h" |
| |
| using namespace wasm; |
| |
| using State = DFA::State<std::string>; |
| using Graph = std::vector<std::vector<State>>; |
| using Results = std::vector<std::vector<std::string>>; |
| using SetResults = std::set<std::set<std::string>>; |
| |
| // We don't care about order between or within the output partitions. |
| SetResults settify(const Results& vecs) { |
| SetResults sets; |
| for (const auto& vec : vecs) { |
| sets.emplace(vec.begin(), vec.end()); |
| } |
| return sets; |
| } |
| |
| // Check that the same values appear in the input and output and that each value |
| // appears once. |
| void validate(const Graph& graph, const Results& results) { |
| std::set<std::string> inputVals; |
| for (const auto& partition : graph) { |
| for (const auto& state : partition) { |
| bool inserted = inputVals.insert(state.val).second; |
| ASSERT_TRUE(inserted); |
| } |
| } |
| |
| std::set<std::string> outputVals; |
| for (const auto& partition : results) { |
| for (const auto& val : partition) { |
| ASSERT_NE(inputVals.find(val), inputVals.end()); |
| ASSERT_TRUE(outputVals.insert(val).second); |
| } |
| } |
| |
| ASSERT_EQ(outputVals.size(), inputVals.size()); |
| } |
| |
| TEST(DFATest, Empty) { |
| Graph graph = {}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), SetResults{}); |
| } |
| |
| TEST(DFATest, Singleton) { |
| Graph graph = {{{"A", {}}}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), SetResults{{"A"}}); |
| } |
| |
| TEST(DFATest, CyclePartitioned) { |
| // The partitions are already maximally refined, so shouldn't change. |
| State a{"A", {"B"}}; |
| State b{"B", {"C"}}; |
| State c{"C", {"A"}}; |
| Graph graph = {{a}, {b}, {c}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), (SetResults{{"A"}, {"B"}, {"C"}})); |
| } |
| |
| TEST(DFATest, CycleGrouped) { |
| // All the states are identical, so the the partition shouldn't change. |
| State a{"A", {"B"}}; |
| State b{"B", {"C"}}; |
| State c{"C", {"A"}}; |
| Graph graph = {{a, b, c}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), (SetResults{{"A", "B", "C"}})); |
| } |
| |
| TEST(DFATest, CycleRefined) { |
| // A and B are distinguishable, so the partitions should be refined. |
| State a{"A", {"B"}}; |
| State b{"B", {"C"}}; |
| State c{"C", {"A"}}; |
| Graph graph = {{a, b}, {c}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), (SetResults{{"A"}, {"B"}, {"C"}})); |
| } |
| |
| TEST(DFATest, ChainZip) { |
| // Chain A->B->C->D is identical to chain W->X->Y->Z. |
| State a{"A", {"B"}}, w{"W", {"X"}}; |
| State b{"B", {"C"}}, x{"X", {"Y"}}; |
| State c{"C", {"D"}}, y{"Y", {"Z"}}; |
| State d{"D", {}}, z{"Z", {}}; |
| Graph graph = {{a, b, c, d, w, x, y, z}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ(settify(results), |
| (SetResults{{"A", "W"}, {"B", "X"}, {"C", "Y"}, {"D", "Z"}})); |
| } |
| |
| TEST(DFATest, ChainUnzip) { |
| // Chain A->B->C->D looks a lot like chain W->X->Y->Z, but since Z is |
| // distinguishable, the full chains end up being separated. |
| State a{"A", {"B"}}, w{"W", {"X"}}; |
| State b{"B", {"C"}}, x{"X", {"Y"}}; |
| State c{"C", {"D"}}, y{"Y", {"Z"}}; |
| State d{"D", {}}, z{"Z", {}}; |
| Graph graph = {{a, b, c, d, w, x, y}, {z}}; |
| auto results = DFA::refinePartitions(graph); |
| validate(graph, results); |
| EXPECT_EQ( |
| settify(results), |
| (SetResults{{"A"}, {"W"}, {"B"}, {"X"}, {"C"}, {"Y"}, {"D"}, {"Z"}})); |
| } |