summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/xml/xpath_functions_test.cc
blob: 794e042b911d0ddb730e7a804c812aca544a0315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/xml/xpath_functions.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/xml/xpath_expression_node.h"  // EvaluationContext
#include "third_party/blink/renderer/core/xml/xpath_predicate.h"  // Number, StringExpression
#include "third_party/blink/renderer/core/xml/xpath_value.h"
#include "third_party/blink/renderer/platform/heap/handle.h"  // HeapVector, Member, etc.
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"

#include <cmath>
#include <limits>

namespace blink {

namespace {

class XPathContext {
  STACK_ALLOCATED();

 public:
  XPathContext()
      : document_(Document::CreateForTest()),
        context_(*document_, had_type_conversion_error_) {}

  xpath::EvaluationContext& Context() { return context_; }
  Document& GetDocument() { return *document_; }

 private:
  Document* const document_;
  bool had_type_conversion_error_ = false;
  xpath::EvaluationContext context_;
};

using XPathArguments = HeapVector<Member<xpath::Expression>>;

static String Substring(XPathArguments& args) {
  XPathContext xpath;
  xpath::Expression* call = xpath::CreateFunction("substring", args);
  xpath::Value result = call->Evaluate(xpath.Context());
  return result.ToString();
}

static String Substring(const char* string, double pos) {
  XPathArguments args;
  args.push_back(MakeGarbageCollected<xpath::StringExpression>(string));
  args.push_back(MakeGarbageCollected<xpath::Number>(pos));
  return Substring(args);
}

static String Substring(const char* string, double pos, double len) {
  XPathArguments args;
  args.push_back(MakeGarbageCollected<xpath::StringExpression>(string));
  args.push_back(MakeGarbageCollected<xpath::Number>(pos));
  args.push_back(MakeGarbageCollected<xpath::Number>(len));
  return Substring(args);
}

}  // namespace

TEST(XPathFunctionsTest, substring_specExamples) {
  EXPECT_EQ(" car", Substring("motor car", 6.0))
      << "should select characters staring at position 6 to the end";
  EXPECT_EQ("ada", Substring("metadata", 4.0, 3.0))
      << "should select characters at 4 <= position < 7";
  EXPECT_EQ("234", Substring("123456", 1.5, 2.6))
      << "should select characters at 2 <= position < 5";
  EXPECT_EQ("12", Substring("12345", 0.0, 3.0))
      << "should select characters at 0 <= position < 3; note the first "
         "position is 1 so this is characters in position 1 and 2";
  EXPECT_EQ("", Substring("12345", 5.0, -3.0))
      << "no characters should have 5 <= position < 2";
  EXPECT_EQ("1", Substring("12345", -3.0, 5.0))
      << "should select characters at -3 <= position < 2; since the first "
         "position is 1, this is the character at position 1";
  EXPECT_EQ("", Substring("12345", NAN, 3.0))
      << "should select no characters since NaN <= position is always false";
  EXPECT_EQ("", Substring("12345", 1.0, NAN))
      << "should select no characters since position < 1. + NaN is always "
         "false";
  EXPECT_EQ("12345",
            Substring("12345", -42, std::numeric_limits<double>::infinity()))
      << "should select characters at -42 <= position < Infinity, which is all "
         "of them";
  EXPECT_EQ("", Substring("12345", -std::numeric_limits<double>::infinity(),
                          std::numeric_limits<double>::infinity()))
      << "since -Inf+Inf is NaN, should select no characters since position "
         "< NaN is always false";
}

TEST(XPathFunctionsTest, substring_emptyString) {
  EXPECT_EQ("", Substring("", 0.0, 1.0))
      << "substring of an empty string should be the empty string";
}

TEST(XPathFunctionsTest, substring) {
  EXPECT_EQ("hello", Substring("well hello there", 6.0, 5.0));
}

TEST(XPathFunctionsTest, substring_negativePosition) {
  EXPECT_EQ("hello", Substring("hello, world!", -4.0, 10.0))
      << "negative start positions should impinge on the result length";
  // Try to underflow the length adjustment for negative positions.
  EXPECT_EQ("",
            Substring("hello", std::numeric_limits<int32_t>::min() + 1, 1.0));
}

TEST(XPathFunctionsTest, substring_negativeLength) {
  EXPECT_EQ("", Substring("hello, world!", 1.0, -3.0))
      << "negative lengths should result in an empty string";

  EXPECT_EQ("", Substring("foo", std::numeric_limits<int32_t>::min(), 1.0))
      << "large (but long representable) negative position should result in "
      << "an empty string";
}

TEST(XPathFunctionsTest, substring_extremePositionLength) {
  EXPECT_EQ("", Substring("no way", 1e100, 7.0))
      << "extremely large positions should result in the empty string";

  EXPECT_EQ("no way", Substring("no way", -1e200, 1e300))
      << "although these indices are not representable as long, this should "
      << "produce the string because indices are computed as doubles";
}

}  // namespace blink