mediapipe/mediapipe2/framework/tool/validate_name_test.cc
2021-06-10 23:01:19 +00:00

477 lines
19 KiB
C++

// Copyright 2019 The MediaPipe 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 "mediapipe/framework/tool/validate_name.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "mediapipe/framework/calculator.pb.h"
#include "mediapipe/framework/deps/message_matchers.h"
#include "mediapipe/framework/port/gmock.h"
#include "mediapipe/framework/port/gtest.h"
#include "mediapipe/framework/port/status_matchers.h"
namespace mediapipe {
namespace {
TEST(ValidateNameTest, ValidateName) {
MP_EXPECT_OK(tool::ValidateName("humphrey"));
MP_EXPECT_OK(tool::ValidateName("humphrey_bogart"));
MP_EXPECT_OK(tool::ValidateName("humphrey_bogart_1899"));
MP_EXPECT_OK(tool::ValidateName("aa"));
MP_EXPECT_OK(tool::ValidateName("b1"));
MP_EXPECT_OK(tool::ValidateName("_1"));
EXPECT_FALSE(tool::ValidateName("").ok());
EXPECT_FALSE(tool::ValidateName("humphrey bogart").ok());
EXPECT_FALSE(tool::ValidateName("humphreyBogart").ok());
EXPECT_FALSE(tool::ValidateName("humphrey-bogart").ok());
EXPECT_FALSE(tool::ValidateName("humphrey/bogart").ok());
EXPECT_FALSE(tool::ValidateName("humphrey.bogart").ok());
EXPECT_FALSE(tool::ValidateName("humphrey:bogart").ok());
EXPECT_FALSE(tool::ValidateName("1ST").ok());
EXPECT_FALSE(tool::ValidateName("7_ELEVEN").ok());
EXPECT_FALSE(tool::ValidateName("401K").ok());
EXPECT_FALSE(tool::ValidateName("0").ok());
EXPECT_FALSE(tool::ValidateName("1").ok());
EXPECT_FALSE(tool::ValidateName("11").ok());
EXPECT_FALSE(tool::ValidateName("92091").ok());
EXPECT_FALSE(tool::ValidateName("1st").ok());
EXPECT_FALSE(tool::ValidateName("7_eleven").ok());
EXPECT_FALSE(tool::ValidateName("401k").ok());
EXPECT_FALSE(tool::ValidateName("\0ContainsEscapes\t").ok());
}
TEST(ValidateNameTest, ValidateTag) {
MP_EXPECT_OK(tool::ValidateTag("MALE"));
MP_EXPECT_OK(tool::ValidateTag("MALE_ACTOR"));
MP_EXPECT_OK(tool::ValidateTag("ACTOR_1899"));
MP_EXPECT_OK(tool::ValidateTag("AA"));
MP_EXPECT_OK(tool::ValidateTag("B1"));
MP_EXPECT_OK(tool::ValidateTag("_1"));
EXPECT_FALSE(tool::ValidateTag("").ok());
EXPECT_FALSE(tool::ValidateTag("MALE ACTOR").ok());
EXPECT_FALSE(tool::ValidateTag("MALEaCTOR").ok());
EXPECT_FALSE(tool::ValidateTag("MALE-ACTOR").ok());
EXPECT_FALSE(tool::ValidateTag("MALE/ACTOR").ok());
EXPECT_FALSE(tool::ValidateTag("MALE.ACTOR").ok());
EXPECT_FALSE(tool::ValidateTag("MALE:ACTOR").ok());
EXPECT_FALSE(tool::ValidateTag("0").ok());
EXPECT_FALSE(tool::ValidateTag("1").ok());
EXPECT_FALSE(tool::ValidateTag("11").ok());
EXPECT_FALSE(tool::ValidateTag("92091").ok());
EXPECT_FALSE(tool::ValidateTag("1ST").ok());
EXPECT_FALSE(tool::ValidateTag("7_ELEVEN").ok());
EXPECT_FALSE(tool::ValidateTag("401K").ok());
EXPECT_FALSE(tool::ValidateTag("\0ContainsEscapes\t").ok());
}
TEST(ValidateNameTest, ParseTagAndName) {
std::string tag;
std::string name;
tag = "blah";
name = "blah";
MP_EXPECT_OK(tool::ParseTagAndName("MALE:humphrey", &tag, &name));
EXPECT_EQ("MALE", tag);
EXPECT_EQ("humphrey", name);
tag = "blah";
name = "blah";
MP_EXPECT_OK(tool::ParseTagAndName("ACTOR:humphrey_bogart", &tag, &name));
EXPECT_EQ("ACTOR", tag);
EXPECT_EQ("humphrey_bogart", name);
tag = "blah";
name = "blah";
MP_EXPECT_OK(tool::ParseTagAndName("ACTOR_1899:humphrey_1899", &tag, &name));
EXPECT_EQ("ACTOR_1899", tag);
EXPECT_EQ("humphrey_1899", name);
tag = "blah";
name = "blah";
MP_EXPECT_OK(tool::ParseTagAndName("humphrey_bogart", &tag, &name));
EXPECT_EQ("", tag);
EXPECT_EQ("humphrey_bogart", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(tool::ParseTagAndName(":humphrey", &tag, &name).ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(tool::ParseTagAndName("humphrey bogart", &tag, &name).ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(tool::ParseTagAndName("actor:humphrey", &tag, &name).ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
tag = "blah";
name = "blah";
MP_EXPECT_OK(tool::ParseTagAndName("ACTOR:humphrey", &tag, &name));
EXPECT_EQ("ACTOR", tag);
EXPECT_EQ("humphrey", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(tool::ParseTagAndName("ACTOR:HUMPHREY", &tag, &name).ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(tool::ParseTagAndName("MALE:ACTOR:humphrey", &tag, &name).ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
// Test various bad characters.
for (std::string character : {" ", "-", "/", ".", ":"}) {
tag = "blah";
name = "blah";
EXPECT_FALSE(
tool::ParseTagAndName(absl::StrCat("MALE", character, "ACTOR:humphrey"),
&tag, &name)
.ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
tag = "blah";
name = "blah";
EXPECT_FALSE(
tool::ParseTagAndName(
absl::StrCat("ACTOR:humphrey", character, "bogart"), &tag, &name)
.ok());
EXPECT_EQ("", tag);
EXPECT_EQ("", name);
}
}
void TestPassParseTagIndexName(const std::string& tag_index_name,
const std::string& expected_tag,
const int expected_index,
const std::string& expected_name) {
std::string actual_tag = "UNTOUCHED";
int actual_index = -100;
std::string actual_name = "untouched";
MP_ASSERT_OK(tool::ParseTagIndexName(tag_index_name, &actual_tag,
&actual_index, &actual_name))
<< "With tag_index_name " << tag_index_name;
EXPECT_EQ(expected_tag, actual_tag)
<< "With tag_index_name " << tag_index_name;
EXPECT_EQ(expected_index, actual_index)
<< "With tag_index_name " << tag_index_name;
EXPECT_EQ(expected_name, actual_name)
<< "With tag_index_name " << tag_index_name;
}
void TestFailParseTagIndexName(const std::string& tag_index_name) {
std::string actual_tag = "UNTOUCHED";
int actual_index = -100;
std::string actual_name = "untouched";
ASSERT_FALSE(tool::ParseTagIndexName(tag_index_name, &actual_tag,
&actual_index, &actual_name)
.ok())
<< "With tag_index_name " << tag_index_name;
EXPECT_EQ("UNTOUCHED", actual_tag)
<< "With tag_index_name " << tag_index_name;
EXPECT_EQ(-100, actual_index) << "With tag_index_name " << tag_index_name;
EXPECT_EQ("untouched", actual_name)
<< "With tag_index_name " << tag_index_name;
}
TEST(ValidateNameTest, ParseTagIndexName) {
// Success cases.
// Test with tag.
TestPassParseTagIndexName("MALE:humphrey", "MALE", 0, "humphrey");
TestPassParseTagIndexName("ACTOR:humphrey_bogart", "ACTOR", 0,
"humphrey_bogart");
TestPassParseTagIndexName("ACTOR_1899:humphrey_1899", "ACTOR_1899", 0,
"humphrey_1899");
// Test without tag.
TestPassParseTagIndexName("humphrey_bogart", "", -1, "humphrey_bogart");
// Test with index.
TestPassParseTagIndexName("ACTRESS:3:mieko_harada", "ACTRESS", 3,
"mieko_harada");
TestPassParseTagIndexName("ACTRESS:0:mieko_harada", "ACTRESS", 0,
"mieko_harada");
TestPassParseTagIndexName("A1:100:mieko1", "A1", 100, "mieko1");
TestPassParseTagIndexName(
absl::StrCat("A1:", mediapipe::internal::kMaxCollectionItemId, ":mieko1"),
"A1", mediapipe::internal::kMaxCollectionItemId, "mieko1");
// Failure cases.
TestFailParseTagIndexName(""); // Empty name.
TestFailParseTagIndexName("A"); // Upper case name.
TestFailParseTagIndexName("Aa"); // Upper case name.
TestFailParseTagIndexName("aA"); // Upper case name.
TestFailParseTagIndexName("1a"); // Name starts with number.
TestFailParseTagIndexName("1"); // Name is number.
// With tag.
TestFailParseTagIndexName(":name"); // Missing tag.
TestFailParseTagIndexName("A:"); // Missing name.
TestFailParseTagIndexName("a:name"); // Lower case tag.
TestFailParseTagIndexName("Aa:name"); // Lower case tag.
TestFailParseTagIndexName("aA:name"); // Lower case tag.
TestFailParseTagIndexName("1A:name"); // Tag starts with number.
TestFailParseTagIndexName("1:name"); // Tag is number.
// With index.
TestFailParseTagIndexName("1:name"); // Missing tag.
TestFailParseTagIndexName(":1:name"); // Missing tag.
TestFailParseTagIndexName("A:1:"); // Missing name.
TestFailParseTagIndexName("A::name"); // Missing index.
TestFailParseTagIndexName("a:1:name"); // Lower case tag.
TestFailParseTagIndexName("Aa:1:name"); // Lower case tag.
TestFailParseTagIndexName("aA:1:name"); // Lower case tag.
TestFailParseTagIndexName("1A:1:name"); // Tag starts with number.
TestFailParseTagIndexName("1:1:name"); // Tag is number.
TestFailParseTagIndexName("A:1:N"); // Upper case name.
TestFailParseTagIndexName("A:1:nN"); // Upper case name.
TestFailParseTagIndexName("A:1:Nn"); // Upper case name.
TestFailParseTagIndexName("A:1:1name"); // Name starts with number.
TestFailParseTagIndexName("A:1:1"); // Name is number.
TestFailParseTagIndexName("A:-0:name"); // Negative index.
TestFailParseTagIndexName("A:-1:name"); // Negative index.
TestFailParseTagIndexName("A:01:name"); // Leading zero.
TestFailParseTagIndexName("A:00:name"); // Leading zero.
TestFailParseTagIndexName(
absl::StrCat("A:", mediapipe::internal::kMaxCollectionItemId + 1,
":a")); // Too large an index.
// Extra field
TestFailParseTagIndexName("A:1:a:"); // extra field.
TestFailParseTagIndexName(":A:1:a"); // extra field.
TestFailParseTagIndexName("A:1:a:a"); // extra field.
TestFailParseTagIndexName("A:1:a:A"); // extra field.
TestFailParseTagIndexName("A:1:a:1"); // extra field.
// Test various bad characters.
for (char character : {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
'{', '}', '[', ']', '/', '=', '?', '+', '\\', '|',
'-', ';', ':', '\'', '"', ',', '<', '.', '>'}) {
TestFailParseTagIndexName(absl::Substitute("$0", character));
TestFailParseTagIndexName(absl::Substitute("$0a", character));
TestFailParseTagIndexName(absl::Substitute("a$0", character));
TestFailParseTagIndexName(absl::Substitute("$0:a", character));
TestFailParseTagIndexName(absl::Substitute("A$0:a", character));
TestFailParseTagIndexName(absl::Substitute("$0A:a", character));
TestFailParseTagIndexName(absl::Substitute("A:$0:a", character));
TestFailParseTagIndexName(absl::Substitute("A:$01:a", character));
TestFailParseTagIndexName(absl::Substitute("A:1$0:a", character));
TestFailParseTagIndexName(absl::Substitute("A:1:a$0", character));
TestFailParseTagIndexName(absl::Substitute("$0A:1:a", character));
}
}
void TestPassParseTagIndex(const std::string& tag_index,
const std::string& expected_tag,
const int expected_index) {
std::string actual_tag = "UNTOUCHED";
int actual_index = -100;
MP_ASSERT_OK(tool::ParseTagIndex(tag_index, &actual_tag, &actual_index))
<< "With tag_index" << tag_index;
EXPECT_EQ(expected_tag, actual_tag) << "With tag_index " << tag_index;
EXPECT_EQ(expected_index, actual_index) << "With tag_index " << tag_index;
}
void TestFailParseTagIndex(const std::string& tag_index) {
std::string actual_tag = "UNTOUCHED";
int actual_index = -100;
ASSERT_FALSE(tool::ParseTagIndex(tag_index, &actual_tag, &actual_index).ok())
<< "With tag_index " << tag_index;
EXPECT_EQ("UNTOUCHED", actual_tag) << "With tag_index " << tag_index;
EXPECT_EQ(-100, actual_index) << "With tag_index " << tag_index;
}
TEST(ValidateNameTest, ParseTagIndex) {
// Success cases.
TestPassParseTagIndex("", "", 0);
TestPassParseTagIndex("VIDEO:0", "VIDEO", 0);
TestPassParseTagIndex("VIDEO:1", "VIDEO", 1);
TestPassParseTagIndex("AUDIO:2", "AUDIO", 2);
TestPassParseTagIndex(":0", "", 0);
TestPassParseTagIndex(":1", "", 1);
TestPassParseTagIndex(":100", "", 100);
// Failure cases.
TestFailParseTagIndex("a"); // Lower case tag.
TestFailParseTagIndex("Aa"); // Lower case tag.
TestFailParseTagIndex("aA"); // Lower case tag.
TestFailParseTagIndex("1A"); // tag starts with number.
TestFailParseTagIndex("1"); // tag is number.
// Two fields.
TestFailParseTagIndex(":"); // Missing number.
TestFailParseTagIndex(":a"); // lower case number.
TestFailParseTagIndex(":A"); // upper case number.
TestFailParseTagIndex(":-0"); // Negative index.
TestFailParseTagIndex(":-1"); // Negative index.
TestFailParseTagIndex(":01"); // Leading zero.
TestFailParseTagIndex(":00"); // Leading zero.
TestFailParseTagIndex("A:"); // Missing number.
TestFailParseTagIndex("A:a"); // lower case number.
TestFailParseTagIndex("A:A"); // upper case number.
TestFailParseTagIndex("A:-0"); // Negative index.
TestFailParseTagIndex("A:-1"); // Negative index.
TestFailParseTagIndex("A:01"); // Leading zero.
TestFailParseTagIndex("A:00"); // Leading zero.
// Extra field
TestFailParseTagIndex("A:1:"); // extra field.
TestFailParseTagIndex(":A:1"); // extra field.
TestFailParseTagIndex("A:1:2"); // extra field.
TestFailParseTagIndex("A:A:1"); // extra field.
// Test various bad characters.
for (char character : {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
'{', '}', '[', ']', '/', '=', '?', '+', '\\', '|',
'-', ';', ':', '\'', '"', ',', '<', '.', '>'}) {
TestFailParseTagIndex(absl::Substitute("$0", character));
TestFailParseTagIndex(absl::Substitute("$0A", character));
TestFailParseTagIndex(absl::Substitute("A$0", character));
TestFailParseTagIndex(absl::Substitute("$0:1", character));
TestFailParseTagIndex(absl::Substitute("A$0:1", character));
TestFailParseTagIndex(absl::Substitute("$0A:1", character));
TestFailParseTagIndex(absl::Substitute("A:1$0", character));
TestFailParseTagIndex(absl::Substitute("A:$01", character));
}
}
TEST(ValidateNameTest, GetTagAndNameInfo) {
CalculatorGraphConfig::Node node_config1;
CalculatorGraphConfig::Node node_config2;
proto_ns::RepeatedPtrField<std::string>& fields =
*node_config1.mutable_input_stream();
proto_ns::RepeatedPtrField<std::string>& fields_copy =
*node_config2.mutable_input_stream();
// Single input using indexes.
fields.Clear();
fields.Add()->assign("transcoded_input_file");
tool::TagAndNameInfo info;
MP_ASSERT_OK(tool::GetTagAndNameInfo(fields, &info));
ASSERT_EQ(0, info.tags.size());
ASSERT_EQ(1, info.names.size());
EXPECT_EQ(fields.Get(0), info.names[0]);
MP_ASSERT_OK(tool::SetFromTagAndNameInfo(info, &fields_copy));
EXPECT_THAT(node_config2, EqualsProto(node_config1));
// Single input using tags.
fields.Clear();
fields.Add()->assign("FILE:transcoded_input_file");
MP_ASSERT_OK(tool::GetTagAndNameInfo(fields, &info));
ASSERT_EQ(1, info.tags.size());
ASSERT_EQ(1, info.names.size());
EXPECT_EQ("FILE", info.tags[0]);
EXPECT_EQ("transcoded_input_file", info.names[0]);
MP_ASSERT_OK(tool::SetFromTagAndNameInfo(info, &fields_copy));
EXPECT_THAT(node_config2, EqualsProto(node_config1));
// Mixing indexes and tags.
fields.Clear();
fields.Add()->assign("transcoded_input_file");
fields.Add()->assign("FILE:transcoded_input_file");
ASSERT_FALSE(tool::GetTagAndNameInfo(fields, &info).ok());
// Valid configuration with more than one input using tags.
fields.Clear();
fields.Add()->assign("TAG1:input1");
fields.Add()->assign("TAG2:input2");
fields.Add()->assign("TAG3:input3");
fields.Add()->assign("TAG4:input4");
MP_ASSERT_OK(tool::GetTagAndNameInfo(fields, &info));
ASSERT_EQ(4, info.tags.size());
ASSERT_EQ(4, info.names.size());
EXPECT_EQ("TAG1", info.tags[0]);
EXPECT_EQ("TAG2", info.tags[1]);
EXPECT_EQ("TAG3", info.tags[2]);
EXPECT_EQ("TAG4", info.tags[3]);
EXPECT_EQ("input1", info.names[0]);
EXPECT_EQ("input2", info.names[1]);
EXPECT_EQ("input3", info.names[2]);
EXPECT_EQ("input4", info.names[3]);
MP_ASSERT_OK(tool::SetFromTagAndNameInfo(info, &fields_copy));
EXPECT_THAT(node_config2, EqualsProto(node_config1));
// Valid configuration with more than one input using indexes.
fields.Clear();
fields.Add()->assign("input1");
fields.Add()->assign("input2");
fields.Add()->assign("input3");
fields.Add()->assign("input4");
MP_ASSERT_OK(tool::GetTagAndNameInfo(fields, &info));
ASSERT_EQ(0, info.tags.size());
ASSERT_EQ(4, info.names.size());
EXPECT_EQ("input1", info.names[0]);
EXPECT_EQ("input2", info.names[1]);
EXPECT_EQ("input3", info.names[2]);
EXPECT_EQ("input4", info.names[3]);
MP_ASSERT_OK(tool::SetFromTagAndNameInfo(info, &fields_copy));
EXPECT_THAT(node_config2, EqualsProto(node_config1));
// Add an invalid character into the name.
fields.Clear();
fields.Add()->assign("TAG1:input1");
fields.Add()->assign("TAG2:inv*alid");
fields.Add()->assign("TAG3:input3");
fields.Add()->assign("TAG4:input4");
ASSERT_FALSE(tool::GetTagAndNameInfo(fields, &info).ok());
// Add an invalid character into the tag.
fields.Clear();
fields.Add()->assign("TAG1:input1");
fields.Add()->assign("INVA*LID:input2");
fields.Add()->assign("TAG3:input3");
fields.Add()->assign("TAG4:input4");
ASSERT_FALSE(tool::GetTagAndNameInfo(fields, &info).ok());
// Add an invalid character into the name and use indexes.
fields.Clear();
fields.Add()->assign("input1");
fields.Add()->assign("inv*alid");
fields.Add()->assign("input3");
fields.Add()->assign("input4");
ASSERT_FALSE(tool::GetTagAndNameInfo(fields, &info).ok());
info.tags.clear();
info.names.clear();
info.names.push_back("a");
info.tags.push_back("A");
info.tags.push_back("B");
ASSERT_FALSE(tool::SetFromTagAndNameInfo(info, &fields_copy).ok());
info.names.push_back("b");
info.names.push_back("c");
ASSERT_FALSE(tool::SetFromTagAndNameInfo(info, &fields_copy).ok());
info.tags.clear();
info.names.clear();
info.names.push_back("input1");
info.names.push_back("inv*alid");
info.names.push_back("input3");
info.names.push_back("input4");
ASSERT_FALSE(tool::SetFromTagAndNameInfo(info, &fields_copy).ok());
info.tags.clear();
info.names.clear();
info.names.push_back("input1");
info.names.push_back("input2");
info.names.push_back("input3");
info.names.push_back("input4");
info.tags.push_back("INPUT1");
info.tags.push_back("IN*VALID");
info.tags.push_back("INPUT3");
info.tags.push_back("INPUT4");
ASSERT_FALSE(tool::SetFromTagAndNameInfo(info, &fields_copy).ok());
}
} // namespace
} // namespace mediapipe