1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/TextUtils.h"
6 #include "mozilla/Utf8.h"
10 #include "js/CharacterEncoding.h"
11 #include "js/CompilationAndEvaluation.h" // JS::Compile
12 #include "js/Exception.h"
13 #include "js/friend/ErrorMessages.h" // JSMSG_*
14 #include "js/SourceText.h"
15 #include "jsapi-tests/tests.h"
16 #include "util/Text.h"
17 #include "vm/ErrorReporting.h"
19 using mozilla::IsAsciiHexDigit
;
20 using mozilla::Utf8Unit
;
22 BEGIN_TEST(testEmptyWindow
) { return testUtf8() && testUtf16(); }
25 // Bad unit with nothing before it.
26 static const char badLeadingUnit
[] = "\x80";
27 CHECK(testOmittedWindow(badLeadingUnit
, JSMSG_BAD_LEADING_UTF8_UNIT
, "0x80"));
29 // Bad unit at start of a fresh line.
30 static const char badStartingFreshLine
[] = "var x = 5;\n\x98";
31 CHECK(testOmittedWindow(badStartingFreshLine
, JSMSG_BAD_LEADING_UTF8_UNIT
,
34 // Bad trailing unit in initial code point.
35 static const char badTrailingUnit
[] = "\xD8\x20";
36 CHECK(testOmittedWindow(badTrailingUnit
, JSMSG_BAD_TRAILING_UTF8_UNIT
,
39 // Bad trailing unit at start of a fresh line.
40 static const char badTrailingUnitFreshLine
[] = "var x = 5;\n\xD8\x20";
41 CHECK(testOmittedWindow(badTrailingUnitFreshLine
,
42 JSMSG_BAD_TRAILING_UTF8_UNIT
, "0xD8 0x20"));
44 // Overlong in initial code point.
45 static const char overlongInitial
[] = "\xC0\x80";
46 CHECK(testOmittedWindow(overlongInitial
, JSMSG_FORBIDDEN_UTF8_CODE_POINT
,
49 // Overlong at start of a fresh line.
50 static const char overlongFreshLine
[] = "var x = 5;\n\xC0\x81";
51 CHECK(testOmittedWindow(overlongFreshLine
, JSMSG_FORBIDDEN_UTF8_CODE_POINT
,
54 // Not-enough in initial code point.
55 static const char notEnoughInitial
[] = "\xF0";
57 testOmittedWindow(notEnoughInitial
, JSMSG_NOT_ENOUGH_CODE_UNITS
, "0xF0"));
59 // Not-enough at start of a fresh line.
60 static const char notEnoughFreshLine
[] = "var x = 5;\n\xF0";
61 CHECK(testOmittedWindow(notEnoughFreshLine
, JSMSG_NOT_ENOUGH_CODE_UNITS
,
68 // Bad unit with nothing before it.
69 static const char16_t badLeadingUnit
[] = u
"\xDFFF";
70 CHECK(testOmittedWindow(badLeadingUnit
, JSMSG_ILLEGAL_CHARACTER
));
72 // Bad unit at start of a fresh line.
73 static const char16_t badStartingFreshLine
[] = u
"var x = 5;\n\xDFFF";
74 CHECK(testOmittedWindow(badStartingFreshLine
, JSMSG_ILLEGAL_CHARACTER
));
79 static bool startsWith(const char* str
, const char* prefix
) {
80 return std::strncmp(prefix
, str
, strlen(prefix
)) == 0;
83 static bool equals(const char* str
, const char* expected
) {
84 return std::strcmp(str
, expected
) == 0;
87 JSScript
* compile(const char16_t
* chars
, size_t len
) {
88 JS::SourceText
<char16_t
> source
;
90 source
.init(cx
, chars
, len
, JS::SourceOwnership::Borrowed
));
92 JS::CompileOptions
options(cx
);
93 return JS::Compile(cx
, options
, source
);
96 JSScript
* compile(const char* chars
, size_t len
) {
97 JS::SourceText
<Utf8Unit
> source
;
99 source
.init(cx
, chars
, len
, JS::SourceOwnership::Borrowed
));
101 JS::CompileOptions
options(cx
);
102 return JS::Compile(cx
, options
, source
);
105 template <typename CharT
, size_t N
>
106 bool testOmittedWindow(const CharT (&chars
)[N
], unsigned expectedErrorNumber
,
107 const char* badCodeUnits
= nullptr) {
108 JS::Rooted
<JSScript
*> script(cx
, compile(chars
, N
- 1));
111 JS::ExceptionStack
exnStack(cx
);
112 CHECK(JS::StealPendingExceptionStack(cx
, &exnStack
));
114 JS::ErrorReportBuilder
report(cx
);
115 CHECK(report
.init(cx
, exnStack
, JS::ErrorReportBuilder::WithSideEffects
));
117 const auto* errorReport
= report
.report();
119 CHECK(errorReport
->errorNumber
== expectedErrorNumber
);
121 if (const auto& notes
= errorReport
->notes
) {
122 CHECK(sizeof(CharT
) == 1);
123 CHECK(badCodeUnits
!= nullptr);
125 auto iter
= notes
->begin();
126 CHECK(iter
!= notes
->end());
128 const char* noteMessage
= (*iter
)->message().c_str();
130 // The prefix ought always be the same.
131 static constexpr char expectedPrefix
[] =
132 "the code units comprising this invalid code point were: ";
133 constexpr size_t expectedPrefixLen
= js_strlen(expectedPrefix
);
135 CHECK(startsWith(noteMessage
, expectedPrefix
));
137 // The end of the prefix is the bad code units.
138 CHECK(equals(noteMessage
+ expectedPrefixLen
, badCodeUnits
));
141 CHECK(iter
== notes
->end());
143 CHECK(sizeof(CharT
) == 2);
145 // UTF-16 encoding "errors" are not categorical errors, so the errors
146 // are just of the invalid-character sort, without an accompanying note
147 // spelling out a series of invalid code units.
148 CHECK(!badCodeUnits
);
151 CHECK(!errorReport
->linebuf());
155 END_TEST(testEmptyWindow
)