ns_regular_expression_unittest.mm 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/strings/sys_string_conversions.h"
  5. #import "testing/gtest_mac.h"
  6. #include "testing/platform_test.h"
  7. #if !defined(__has_feature) || !__has_feature(objc_arc)
  8. #error "This file requires ARC support."
  9. #endif
  10. // Chromium code relies on NSRegularExpression class to match regular
  11. // expressions. Any subtle changes in behavior can lead to hard to diagnose
  12. // problems. This files tests how NSRegularExpression handles various regular
  13. // expression features.
  14. namespace {
  15. // Checks that capture groups from |testString| substituted into
  16. // |templateString| matches |expected|.
  17. void ExpectRegexMatched(NSRegularExpression* regex,
  18. NSString* testString,
  19. NSString* templateString,
  20. NSString* expected) {
  21. NSRange testRange = NSMakeRange(0, [testString length]);
  22. NSString* outputString =
  23. [regex stringByReplacingMatchesInString:testString
  24. options:0
  25. range:testRange
  26. withTemplate:templateString];
  27. EXPECT_TRUE(outputString && [outputString isEqualToString:expected])
  28. << "ExpectRegexMatched: '" << base::SysNSStringToUTF8(expected) << "' != "
  29. << (!outputString ? "(nil)"
  30. : "'" + base::SysNSStringToUTF8(outputString) + "'");
  31. }
  32. // Checks that |testString| is not matched by |regex|.
  33. void ExpectRegexNotMatched(NSRegularExpression* regex, NSString* testString) {
  34. __block BOOL matched = NO;
  35. NSRange testRange = NSMakeRange(0, [testString length]);
  36. [regex enumerateMatchesInString:testString
  37. options:0
  38. range:testRange
  39. usingBlock:^(NSTextCheckingResult* result,
  40. NSMatchingFlags flags, BOOL* stop) {
  41. if (NSEqualRanges([result range], testRange)) {
  42. *stop = YES;
  43. matched = YES;
  44. }
  45. }];
  46. EXPECT_FALSE(matched) << "ExpectRegexNotMatched: '"
  47. << base::SysNSStringToUTF8(testString) << "' "
  48. << "pattern:"
  49. << base::SysNSStringToUTF8([regex pattern]);
  50. }
  51. // Returns an autoreleased NSRegularExpression object from the regular
  52. // expression |pattern|.
  53. NSRegularExpression* MakeRegularExpression(NSString* pattern) {
  54. NSError* error = nil;
  55. return [NSRegularExpression regularExpressionWithPattern:pattern
  56. options:0
  57. error:&error];
  58. }
  59. using NSRegularExpressionTest = PlatformTest;
  60. TEST_F(NSRegularExpressionTest, TestSimpleRegex) {
  61. NSRegularExpression* regex = MakeRegularExpression(@"foo(.*)bar(.*)");
  62. ExpectRegexMatched(regex, @"fooONEbarTWO", @"first $1, second $2",
  63. @"first ONE, second TWO");
  64. }
  65. TEST_F(NSRegularExpressionTest, TestComplexRegex) {
  66. NSString* expression = @"^http[s]?://"
  67. "(?:"
  68. "(?:youtu\\.be/)|"
  69. "(?:.*\\.youtube\\.com/watch\\?v=)|"
  70. "(?:.*\\.youtube\\.com/index\\?)"
  71. ")"
  72. "([^&]*)[\\&]?(?:.*)$";
  73. NSString* templateString = @"vnd.youtube://$1";
  74. NSString* expectedOutput = @"vnd.youtube://ndRXe3tTnsA";
  75. NSRegularExpression* regex = MakeRegularExpression(expression);
  76. ExpectRegexMatched(regex, @"http://youtu.be/ndRXe3tTnsA", templateString,
  77. expectedOutput);
  78. ExpectRegexMatched(regex, @"http://www.youtube.com/watch?v=ndRXe3tTnsA",
  79. templateString, expectedOutput);
  80. ExpectRegexNotMatched(regex, @"http://www.google.com");
  81. ExpectRegexNotMatched(regex, @"http://www.youtube.com/embed/GkOZ8DfO248");
  82. }
  83. TEST_F(NSRegularExpressionTest, TestSimpleAlternation) {
  84. // This test verifies how NSRegularExpression works.
  85. // Regex 'ab|c' matches 'ab', 'ac', or 'c'. Does not match 'abc', 'a', or 'b'.
  86. NSRegularExpression* regex = MakeRegularExpression(@"^ab|c$");
  87. ExpectRegexMatched(regex, @"ab", @"$0", @"ab");
  88. ExpectRegexMatched(regex, @"c", @"$0", @"c");
  89. ExpectRegexMatched(regex, @"ac", @"$0", @"ac");
  90. ExpectRegexNotMatched(regex, @"abc");
  91. ExpectRegexNotMatched(regex, @"a");
  92. ExpectRegexNotMatched(regex, @"b");
  93. // Tests for '(?:ab)|(?:c)', which is slightly different from 'ab|c'.
  94. regex = MakeRegularExpression(@"^(?:ab)|(?:c)$");
  95. ExpectRegexMatched(regex, @"ab", @"$0", @"ab");
  96. ExpectRegexMatched(regex, @"c", @"$0", @"c");
  97. ExpectRegexNotMatched(regex, @"ac");
  98. ExpectRegexNotMatched(regex, @"abc");
  99. // This other regex: 'a(b|c)' matches either 'ab' or 'ac'.
  100. regex = MakeRegularExpression(@"^a(?:b|c)$");
  101. ExpectRegexMatched(regex, @"ab", @"$0", @"ab");
  102. ExpectRegexMatched(regex, @"ac", @"$0", @"ac");
  103. ExpectRegexNotMatched(regex, @"a");
  104. ExpectRegexNotMatched(regex, @"abc");
  105. }
  106. TEST_F(NSRegularExpressionTest, TestUberCaptureGroup) {
  107. // The absence of an uber-capture group caused NSRegularExpression to crash on
  108. // iOS 5.x. This tests to make sure that it is not happening on iOS 6+
  109. // environments.
  110. NSRegularExpression* regex = MakeRegularExpression(@"^(ab|cd|ef)ghij$");
  111. ExpectRegexMatched(regex, @"abghij", @"$0", @"abghij");
  112. ExpectRegexMatched(regex, @"cdghij", @"$0", @"cdghij");
  113. ExpectRegexMatched(regex, @"efghij", @"$0", @"efghij");
  114. ExpectRegexNotMatched(regex, @"abcdefghij");
  115. regex = MakeRegularExpression(@"^ab|cd|efghij$");
  116. ExpectRegexMatched(regex, @"ab", @"$0", @"ab");
  117. ExpectRegexMatched(regex, @"cd", @"$0", @"cd");
  118. ExpectRegexMatched(regex, @"efghij", @"$0", @"efghij");
  119. ExpectRegexNotMatched(regex, @"abcdefghij");
  120. ExpectRegexNotMatched(regex, @"abghij");
  121. ExpectRegexNotMatched(regex, @"cdghij");
  122. }
  123. } // namespace