| // Copyright 2017-2020 The Verible 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 "common/text/config_utils.h" |
| |
| #include <cstdint> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/status/status.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/string_view.h" |
| #include "gtest/gtest.h" |
| |
| namespace verible { |
| namespace config { |
| |
| TEST(ConfigUtilsTest, ComplainInvalidParameter) { |
| absl::Status s; |
| // singular ... |
| s = ParseNameValues("baz:123", {{"foo", nullptr}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), |
| "baz: unknown parameter; supported " |
| "parameter is 'foo'"); |
| |
| // plural. |
| s = ParseNameValues("baz:123", {{"foo", nullptr}, {"bar", nullptr}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), |
| "baz: unknown parameter; supported " |
| "parameters are 'foo', 'bar'"); |
| |
| s = ParseNameValues("foo:123", {{"foo", nullptr}, {"bar", nullptr}}); |
| EXPECT_TRUE(s.ok()); |
| } |
| |
| TEST(ConfigUtilsTest, ParseInteger) { |
| absl::Status s; |
| int value = -1; |
| s = ParseNameValues("baz:42", {{"baz", SetInt(&value, 0, 100)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_EQ(value, 42); |
| |
| s = ParseNameValues("baz:fourtytwo", {{"baz", SetInt(&value, 0, 100)}}); |
| EXPECT_FALSE(s.ok()); |
| // would be cool though :) |
| EXPECT_EQ(s.message(), "baz: 'fourtytwo': Cannot parse integer"); |
| |
| s = ParseNameValues("baz:142", {{"baz", SetInt(&value, 0, 100)}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), "baz: 142 out of range [0...100]"); |
| |
| s = ParseNameValues("baz:-1", {{"baz", SetInt(&value, 0, 100)}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), "baz: -1 out of range [0...100]"); |
| |
| s = ParseNameValues("baz:-12345", {{"baz", SetInt(&value)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_EQ(value, -12345); |
| } |
| |
| TEST(ConfigUtilsTest, ParseBool) { |
| absl::Status s; |
| bool value = false; |
| for (auto config : {"baz", "baz:TrUe", "baz:on", "baz:1"}) { |
| s = ParseNameValues(config, {{"baz", SetBool(&value)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_TRUE(value); |
| } |
| |
| for (auto config : {"baz:fAlse", "baz:off", "baz:0"}) { |
| s = ParseNameValues(config, {{"baz", SetBool(&value)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_FALSE(value); |
| } |
| |
| s = ParseNameValues("baz:foobar", {{"baz", SetBool(&value)}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_TRUE( |
| absl::StartsWith(s.message(), "baz: Boolean value should be one of")); |
| } |
| |
| TEST(ConfigUtilsTest, ParseString) { |
| absl::Status s; |
| std::string str; |
| s = ParseNameValues("baz:hello", {{"baz", SetString(&str)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_EQ(str, "hello"); |
| |
| s = ParseNameValues("baz:hello", |
| {{"baz", SetStringOneOf(&str, {"hello", "world"})}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_EQ(str, "hello"); |
| |
| // Selection from multiple strings |
| s = ParseNameValues("baz:greetings", |
| {{"baz", SetStringOneOf(&str, {"hello", "world"})}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), |
| "baz: Value can only be one of ['hello', 'world']; " |
| "got 'greetings'"); |
| |
| // Selection from one string |
| s = ParseNameValues("baz:greetings", |
| {{"baz", SetStringOneOf(&str, {"hello"})}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), "baz: Value can only be 'hello'; got 'greetings'"); |
| } |
| |
| TEST(ConfigUtilsTest, ParseNamedBitmap) { |
| const std::vector<absl::string_view> kBitNames = {"ZERO", "ONE", "TWO"}; |
| const std::pair<absl::string_view, uint32_t> kTestCases[] = { |
| {"baz:ONE", 1 << 1}, |
| {"baz:", 0}, |
| {"baz:ZERO|TWO", (1 << 0) | (1 << 2)}, |
| {"baz:ZERO||TWO", (1 << 0) | (1 << 2)}, // Allowing empty value |
| {"baz:ZERO| |TWO", (1 << 0) | (1 << 2)}, // .. even with space |
| {"baz: ZERO | TWO", (1 << 0) | (1 << 2)}, // Whitespace around ok. |
| {"baz:zErO|TwO", (1 << 0) | (1 << 2)}, // case-insensitive |
| {"baz:TWO|ZERO", (1 << 0) | (1 << 2)}, // Sequence does not matter |
| {"baz:ZERO|ONE|TWO", (1 << 0) | (1 << 1) | (1 << 2)}, |
| }; |
| |
| absl::Status s; |
| for (const auto& testcase : kTestCases) { |
| uint32_t bitmap = 0x12345678; |
| s = ParseNameValues(testcase.first, |
| {{"baz", SetNamedBits(&bitmap, kBitNames)}}); |
| EXPECT_TRUE(s.ok()) << "case: '" << testcase.first << "' ->" << s.message(); |
| EXPECT_EQ(bitmap, testcase.second); |
| } |
| |
| { |
| uint32_t bitmap = 0x12345678; |
| s = ParseNameValues("baz:ONE|invalid", |
| {{"baz", SetNamedBits(&bitmap, kBitNames)}}); |
| EXPECT_FALSE(s.ok()); |
| EXPECT_EQ(s.message(), |
| "baz: 'invalid' is not in the available " |
| "choices {ZERO, ONE, TWO}"); |
| EXPECT_EQ(bitmap, 0x12345678); // on parse failure, variable not modified. |
| } |
| } |
| |
| TEST(ConfigUtilsTest, ParseMultipleParameters) { |
| absl::Status s; |
| int answer; |
| bool panic; |
| s = ParseNameValues("answer:42;panic:off", {{"answer", SetInt(&answer)}, |
| {"panic", SetBool(&panic)}}); |
| EXPECT_TRUE(s.ok()); |
| EXPECT_FALSE(panic); |
| EXPECT_EQ(answer, 42); |
| |
| s = ParseNameValues("answer:43;panic:on", {{"answer", SetInt(&answer)}, |
| {"panic", SetBool(&panic)}}); |
| EXPECT_TRUE(s.ok()) << s.message(); |
| EXPECT_TRUE(panic); |
| EXPECT_EQ(answer, 43); |
| } |
| } // namespace config |
| } // namespace verible |