[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/aitech-lab/uap-cpp/master/UaParserTest.cpp [Back]  [Original]

#include 
#include 

#include "UaParser.h"
#include "internal/AlternativeExpander.h"
#include "internal/Pattern.h"
#include "internal/ReplaceTemplate.h"
#include "internal/SnippetIndex.h"
#ifdef WITH_MT_TEST
#include 
#endif  // WITH_MT_TEST

namespace {

const std::string UA_CORE_DIR = "./uap-core";

const uap_cpp::UserAgentParser g_ua_parser(UA_CORE_DIR + "/regexes.yaml");

TEST(UserAgentParser, basic) {
  const auto uagent = g_ua_parser.parse(
      "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) "
      "AppleWebKit/534.46 "
      "(KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3");
  ASSERT_EQ("Mobile Safari", uagent.browser.family);
  ASSERT_EQ("5", uagent.browser.major);
  ASSERT_EQ("1", uagent.browser.minor);
  ASSERT_EQ("", uagent.browser.patch);
  ASSERT_EQ("Mobile Safari 5.1.0", uagent.browser.toString());
  ASSERT_EQ("5.1.0", uagent.browser.toVersionString());

  ASSERT_EQ("iOS", uagent.os.family);
  ASSERT_EQ("5", uagent.os.major);
  ASSERT_EQ("1", uagent.os.minor);
  ASSERT_EQ("1", uagent.os.patch);
  ASSERT_EQ("iOS 5.1.1", uagent.os.toString());
  ASSERT_EQ("5.1.1", uagent.os.toVersionString());

  ASSERT_EQ("Mobile Safari 5.1.0/iOS 5.1.1", uagent.toFullString());

  ASSERT_EQ("iPhone", uagent.device.family);

  ASSERT_FALSE(uagent.isSpider());
}

TEST(UserAgentParser, DeviceTypeMobile) {
  EXPECT_TRUE(uap_cpp::UserAgentParser::device_type(
                  "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) "
                  "AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 "
                  "Mobile/9B206 Safari/7534.48.3") ==
              uap_cpp::DeviceType::kMobile);
  EXPECT_TRUE(
      uap_cpp::UserAgentParser::device_type(
          "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-J330FN Build/R16NW) "
          "AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/7.2 "
          "Chrome/11.1.1111.111 Mobile Safari/537.36") ==
      uap_cpp::DeviceType::kMobile);
}

TEST(UserAgentParser, DeviceTypeTablet) {
  EXPECT_TRUE(uap_cpp::UserAgentParser::device_type(
                  "Mozilla/5.0 (Linux; U; en-us; KFTT Build/IML74K) "
                  "AppleWebKit/535.19 (KHTML, like Gecko) Silk/2.0 "
                  "Safari/535.19 Silk-Accelerated=false") ==
              uap_cpp::DeviceType::kTablet);
  EXPECT_TRUE(
      uap_cpp::UserAgentParser::device_type(
          "Mozilla/5.0 (Linux; Android 9; SHT-AL09 Build/HUAWEISHT-AL09; wv) "
          "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 "
          "Chrome/79.0.3945.136 Safari/537.36") ==
      uap_cpp::DeviceType::kTablet);
}

TEST(UserAgentParser, DeviceTypeDesktop) {
  ASSERT_TRUE(
      uap_cpp::UserAgentParser::device_type(
          "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.4 (KHTML, like "
          "Gecko) Chrome/98 Safari/537.4 (StatusCake)") ==
      uap_cpp::DeviceType::kDesktop);
}

TEST(UserAgentParser, DeviceTypeMobileOrTablet) {
  const auto test_cases = YAML::LoadFile("./test_device_type_mobile.yaml");
  for (const auto& test : test_cases) {
    const auto device_type =
        uap_cpp::UserAgentParser::device_type(test.as());
    ASSERT_TRUE(device_type == uap_cpp::DeviceType::kMobile ||
                device_type == uap_cpp::DeviceType::kTablet);
  }
}

bool has_field(const YAML::Node& root, const std::string& fname) {
  const auto& yaml_field = root[fname];
  return yaml_field.IsDefined();
}

std::string string_field(const YAML::Node& root, const std::string& fname) {
  const auto& yaml_field = root[fname];
  return yaml_field.IsNull() ? "" : yaml_field.as();
}

void test_browser_or_os(const std::string file_path, const bool browser) {
  auto root = YAML::LoadFile(file_path);
  const auto& test_cases = root["test_cases"];
  for (const auto& test : test_cases) {
    const auto major = string_field(test, "major");
    const auto minor = string_field(test, "minor");
    const auto patch = string_field(test, "patch");
    const bool has_patch_minor = has_field(test, "patch_minor");
    const auto patch_minor =
        has_patch_minor ? string_field(test, "patch_minor") : "";
    const auto family = string_field(test, "family");
    const auto unparsed = string_field(test, "user_agent_string");
    const auto uagent = g_ua_parser.parse(unparsed);
    const auto& agent = browser ? uagent.browser : uagent.os;

    EXPECT_EQ(major, agent.major);
    EXPECT_EQ(minor, agent.minor);
    EXPECT_EQ(patch, agent.patch);
    if (has_patch_minor && !browser) {
      EXPECT_EQ(patch_minor, agent.patch_minor);
    }
    EXPECT_EQ(family, agent.family);
  }
}

void test_device(const std::string file_path) {
  auto root = YAML::LoadFile(file_path);
  const auto& test_cases = root["test_cases"];
  for (const auto& test : test_cases) {
    const auto unparsed = string_field(test, "user_agent_string");
    const auto uagent = g_ua_parser.parse(unparsed);
    const auto family = string_field(test, "family");
    const auto brand = string_field(test, "brand");
    const auto model = string_field(test, "model");

    EXPECT_EQ(family, uagent.device.family);
    EXPECT_EQ(brand, uagent.device.brand);
    EXPECT_EQ(model, uagent.device.model);
  }
}

TEST(OsVersion, test_os) {
  test_browser_or_os(UA_CORE_DIR + "/tests/test_os.yaml", false);
}

TEST(OsVersion, test_ua) {
  test_browser_or_os(UA_CORE_DIR + "/tests/test_ua.yaml", true);
}

TEST(BrowserVersion, firefox_user_agent_strings) {
  test_browser_or_os(
      UA_CORE_DIR + "/test_resources/firefox_user_agent_strings.yaml", true);
}

TEST(BrowserVersion, opera_mini_user_agent_strings) {
  test_browser_or_os(
      UA_CORE_DIR + "/test_resources/opera_mini_user_agent_strings.yaml", true);
}

TEST(BrowserVersion, pgts_browser_list) {
  test_browser_or_os(UA_CORE_DIR + "/test_resources/pgts_browser_list.yaml",
                     true);
}

TEST(OsVersion, additional_os_tests) {
  test_browser_or_os(UA_CORE_DIR + "/test_resources/additional_os_tests.yaml",
                     false);
}

TEST(BrowserVersion, podcasting_user_agent_strings) {
  test_browser_or_os(
      UA_CORE_DIR + "/test_resources/podcasting_user_agent_strings.yaml", true);
}

TEST(DeviceFamily, test_device) {
  test_device(UA_CORE_DIR + "/tests/test_device.yaml");
}

#ifdef WITH_MT_TEST
namespace {

void do_multithreaded_test(const std::function& work) {
  static constexpr int NUM_WORKERS = 4;

  std::vector workers;
  for (int i = 0; i < NUM_WORKERS; ++i) {
    workers.push_back(std::async(std::launch::async, [&work]() { work(); }));
  }
  for (auto& worker : workers) {
    worker.wait();
  }
}

}  // namespace

TEST(OsVersion, test_os_mt) {
  do_multithreaded_test(
      [] { test_browser_or_os(UA_CORE_DIR + "/tests/test_os.yaml", false); });
}

TEST(OsVersion, test_ua_mt) {
  do_multithreaded_test(
      [] { test_browser_or_os(UA_CORE_DIR + "/tests/test_ua.yaml", true); });
}

TEST(BrowserVersion, firefox_user_agent_strings_mt) {
  do_multithreaded_test([] {
    test_browser_or_os(
        UA_CORE_DIR + "/test_resources/firefox_user_agent_strings.yaml", true);
  });
}

TEST(BrowserVersion, opera_mini_user_agent_strings_mt) {
  do_multithreaded_test([] {
    test_browser_or_os(
        UA_CORE_DIR + "/test_resources/opera_mini_user_agent_strings.yaml",
        true);
  });
}

TEST(BrowserVersion, pgts_browser_list_mt) {
  do_multithreaded_test([] {
    test_browser_or_os(UA_CORE_DIR + "/test_resources/pgts_browser_list.yaml",
                       true);
  });
}

TEST(OsVersion, additional_os_tests_mt) {
  do_multithreaded_test([] {
    test_browser_or_os(UA_CORE_DIR + "/test_resources/additional_os_tests.yaml",
                       false);
  });
}

TEST(BrowserVersion, podcasting_user_agent_strings_mt) {
  do_multithreaded_test([] {
    test_browser_or_os(
        UA_CORE_DIR + "/test_resources/podcasting_user_agent_strings.yaml",
        true);
  });
}

TEST(DeviceFamily, test_device_mt) {
  do_multithreaded_test(
      [] { test_device(UA_CORE_DIR + "/tests/test_device.yaml"); });
}
#endif  // WITH_MT_TEST

void test_snippets(const std::string& expression,
                   std::vector should_match) {
  uap_cpp::SnippetIndex index;
  auto snippet_set = index.registerSnippets(expression);
  auto snippet_string_map = index.getRegisteredSnippets();

  std::vector snippet_strings;
  for (auto snippetId : snippet_set) {
    auto it = snippet_string_map.find(snippetId);
    ASSERT_NE(it, snippet_string_map.end());
    snippet_strings.emplace_back(it->second);
  }

  EXPECT_EQ(snippet_strings, should_match);
}

TEST(SnippetIndex, snippets) {
  test_snippets("foo.bar", {"foo", "bar"});
  test_snippets("foodbar", {"foodbar"});
  test_snippets("food?bar", {"foo", "bar"});
  test_snippets("foo.?bar", {"foo", "bar"});
  test_snippets("foo\\.bar", {"foo", ".bar"});
  test_snippets("(foo)", {"foo"});
  test_snippets("toto(foo|bar)tata", {"toto", "tata"});
  test_snippets("toto(foo)tata", {"toto", "foo", "tata"});
  test_snippets("toto(foo)?tata", {"toto", "tata"});
  test_snippets("toto(foo)*tata", {"toto", "tata"});
  test_snippets("toto(foo){0,10}tata", {"toto", "tata"});
  test_snippets("toto(foo){0,}tata", {"toto", "tata"});
  test_snippets("toto(foo){1,10}tata", {"toto", "foo", "tata"});
  test_snippets("toto(foo){1,}tata", {"toto", "foo", "tata"});
  test_snippets("foo[abc]bar", {"foo", "bar"});
  test_snippets("foo[abc]+bar", {"foo", "bar"});
  test_snippets("foo|bar", {});
  test_snippets("foo[|]bar", {"foo", "bar"});
  test_snippets("[(foo)]bar", {"bar"});
  test_snippets("[]foo]bar", {"bar"});
  test_snippets("(foo[abc)])bar", {"foo", "bar"});
  test_snippets("(foo(abc))bar", {"foo", "abc", "bar"});
  test_snippets("Foo.bAR", {"foo", "bar"});
  test_snippets("/(\\d+)\\.?foo(\\d+)", {"foo"});
  test_snippets("(?:foo|bar);.*(baz)/(\\d+)\\.(\\d+)", {"baz"});
}

void test_expand(const std::string& expression,
                 std::vector should_match) {
  EXPECT_EQ(uap_cpp::AlternativeExpander::expand(expression), should_match);
}

TEST(AlternativeExpander, expansions) {
  test_expand("a", {"a"});
  test_expand("(a)", {"(a)"});
  test_expand("(a|b)", {"(a)", "(b)"});
  test_expand("(?:a|b)", {"(?:a)", "(?:b)"});
  test_expand("(a|b)?", {"(a|b)?"});
  test_expand("(a|b)+", {"(a)+", "(b)+"});
  test_expand("(a|b)*", {"(a|b)*"});
  test_expand("(a|b){0,2}", {"(a|b){0,2}"});
  test_expand("a|b", {"a", "b"});
  test_expand("x(a|b)y", {"x(a)y", "x(b)y"});
  test_expand("(a|b)yz", {"(a)yz", "(b)yz"});
  test_expand("xa|by", {"xa", "by"});
  test_expand("(a|b)(c|d)", {"(a)(c)", "(a)(d)", "(b)(c)", "(b)(d)"});
  test_expand("(a(b|c)|d)", {"(a(b))", "(a(c))", "(d)"});
  test_expand("(a", {"(a"});
  test_expand("(a|b", {"(a|b"});
  test_expand("((a", {"((a"});
  test_expand("((a|b", {"((a|b"});
  test_expand("(a((a|b", {"(a((a|b"});
  test_expand("[ab]", {"[ab]"});
  test_expand("[(|)]", {"[(|)]"});
  test_expand("[(a|a)]", {"[(a|a)]"});
  test_expand("a(|)b", {"a()b", "a()b"});
  test_expand("([ab]|[bc])", {"([ab])", "([bc])"});
  test_expand("[[](a|b)", {"[[](a)", "[[](b)"});
  test_expand("[]abc](a|b)", {"[]abc](a)", "[]abc](b)"});
}

std::string match_and_expand(const std::string& expression,
                             const std::string& input_string,
                             const std::string& replace_template) {
  uap_cpp::Pattern p(expression);
  uap_cpp::Match m;
  if (p.match(input_string, m)) {
    return uap_cpp::ReplaceTemplate(replace_template).expand(m);
  }
  return "";
}

TEST(ReplaceTemplate, expansions) {
  EXPECT_EQ(match_and_expand("something", "other", "foo"), "");
  EXPECT_EQ(match_and_expand("something", "something", "foo"), "foo");
  EXPECT_EQ(match_and_expand("some(thing)", "something", "no$1"), "nothing");
  EXPECT_EQ(match_and_expand("so([Mm])eth(ing)", "that's something!", "$1$2$3"),
            "ming");
  EXPECT_EQ(match_and_expand("([^ ]+) (.+)", "a b", "$2-$1"), "b-a");
}
}  // namespace

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Web Proxy Viewer  |  New URL  |  Original Page