1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00
jashkenas--coffeescript/test/regexps.coffee
Simon Lydell 72ceec5680 Fix #3795: Never generate invalid strings and regexes
- Invalid `\x` and `\u` escapes now throw errors.
- U+2028 and U+2029 (which JavaScript treats as newline characters) are now
  escaped to `\u2028` and `\u2029`, respectively.
- Octal escapes are now forbidden not only in strings, but in regexes as well.
- `\0` escapes are now escaped if needed (so that they do not form an octal
  literal by mistake). Note that `\01` is an octal escape in a regex, while `\1`
  is a backreference. (Added a test for backreferences while at it.)
- Fixed a bug where newlines in strings weren't removed if preceded by an
  escaped character.
2015-02-05 17:23:03 +01:00

288 lines
5.5 KiB
CoffeeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Regular Expression Literals
# ---------------------------
# TODO: add method invocation tests: /regex/.toString()
# * Regexen
# * Heregexen
test "basic regular expression literals", ->
ok 'a'.match(/a/)
ok 'a'.match /a/
ok 'a'.match(/a/g)
ok 'a'.match /a/g
test "division is not confused for a regular expression", ->
# Any spacing around the slash is allowed when it cannot be a regex.
eq 2, 4 / 2 / 1
eq 2, 4/2/1
eq 2, 4/ 2 / 1
eq 2, 4 /2 / 1
eq 2, 4 / 2/ 1
eq 2, 4 / 2 /1
eq 2, 4 /2/ 1
a = (regex) -> regex.test 'a b c'
a.valueOf = -> 4
b = 2
g = 1
eq 2, a / b/g
eq 2, a/ b/g
eq 2, a / b/ g
eq 2, a / b/g # Tabs.
eq 2, a / b/g # Non-breaking spaces.
eq true, a /b/g
# Use parentheses to disambiguate.
eq true, a(/ b/g)
eq true, a(/ b/)
eq true, a (/ b/)
# Escape to disambiguate.
eq true, a /\ b/g
eq false, a /\ b/g
eq true, a /\ b/
obj = method: -> 2
two = 2
eq 2, (obj.method()/two + obj.method()/two)
i = 1
eq 2, (4)/2/i
eq 1, i/i/i
a = ''
a += ' ' until / /.test a
eq a, ' '
a = if /=/.test '=' then yes else no
eq a, yes
a = if !/=/.test '=' then yes else no
eq a, no
#3182:
match = 'foo=bar'.match /=/
eq match[0], '='
#3410:
ok ' '.match(/ /)[0] is ' '
test "division vs regex after a callable token", ->
b = 2
g = 1
r = (r) -> r.test 'b'
a = 4
eq 2, a / b/g
eq 2, a/b/g
eq 2, a/ b/g
eq true, r /b/g
eq 2, (1 + 3) / b/g
eq 2, (1 + 3)/b/g
eq 2, (1 + 3)/ b/g
eq true, (r) /b/g
eq 2, [4][0] / b/g
eq 2, [4][0]/b/g
eq 2, [4][0]/ b/g
eq true, [r][0] /b/g
eq 0.5, 4? / b/g
eq 0.5, 4?/b/g
eq 0.5, 4?/ b/g
eq true, r? /b/g
(->
eq 2, @ / b/g
eq 2, @/b/g
eq 2, @/ b/g
).call 4
(->
eq true, @ /b/g
).call r
(->
eq 2, this / b/g
eq 2, this/b/g
eq 2, this/ b/g
).call 4
(->
eq true, this /b/g
).call r
class A
p: (regex) -> if regex then r regex else 4
class B extends A
p: ->
eq 2, super / b/g
eq 2, super/b/g
eq 2, super/ b/g
eq true, super /b/g
new B().p()
test "always division and never regex after some tokens", ->
b = 2
g = 1
eq 2, 4 / b/g
eq 2, 4/b/g
eq 2, 4/ b/g
eq 2, 4 /b/g
eq 2, "4" / b/g
eq 2, "4"/b/g
eq 2, "4"/ b/g
eq 2, "4" /b/g
eq 20, "4#{0}" / b/g
eq 20, "4#{0}"/b/g
eq 20, "4#{0}"/ b/g
eq 20, "4#{0}" /b/g
ok isNaN /a/ / b/g
ok isNaN /a/i / b/g
ok isNaN /a//b/g
ok isNaN /a/i/b/g
ok isNaN /a// b/g
ok isNaN /a/i/ b/g
ok isNaN /a/ /b/g
ok isNaN /a/i /b/g
eq 0.5, true / b/g
eq 0.5, true/b/g
eq 0.5, true/ b/g
eq 0.5, true /b/g
eq 0, false / b/g
eq 0, false/b/g
eq 0, false/ b/g
eq 0, false /b/g
eq 0, null / b/g
eq 0, null/b/g
eq 0, null/ b/g
eq 0, null /b/g
ok isNaN undefined / b/g
ok isNaN undefined/b/g
ok isNaN undefined/ b/g
ok isNaN undefined /b/g
ok isNaN {a: 4} / b/g
ok isNaN {a: 4}/b/g
ok isNaN {a: 4}/ b/g
ok isNaN {a: 4} /b/g
o = prototype: 4
eq 2, o:: / b/g
eq 2, o::/b/g
eq 2, o::/ b/g
eq 2, o:: /b/g
i = 4
eq 2.0, i++ / b/g
eq 2.5, i++/b/g
eq 3.0, i++/ b/g
eq 3.5, i++ /b/g
eq 4.0, i-- / b/g
eq 3.5, i--/b/g
eq 3.0, i--/ b/g
eq 2.5, i-- /b/g
test "compound division vs regex", ->
c = 4
i = 2
a = 10
b = a /= c / i
eq a, 5
a = 10
b = a /= c /i
eq a, 5
a = 10
b = a /= c /i # Tabs.
eq a, 5
a = 10
b = a /= c /i # Non-breaking spaces.
eq a, 5
a = 10
b = a/= c /i
eq a, 5
a = 10
b = a/=c/i
eq a, 5
a = (regex) -> regex.test '=C '
b = a /=c /i
eq b, true
a = (regex) -> regex.test '= C '
# Use parentheses to disambiguate.
b = a(/= c /i)
eq b, true
b = a(/= c /)
eq b, false
b = a (/= c /)
eq b, false
# Escape to disambiguate.
b = a /\= c /i
eq b, true
b = a /\= c /
eq b, false
test "#764: regular expressions should be indexable", ->
eq /0/['source'], ///#{0}///['source']
test "#584: slashes are allowed unescaped in character classes", ->
ok /^a\/[/]b$/.test 'a//b'
test "does not allow to escape newlines", ->
throws -> CoffeeScript.compile '/a\\\nb/'
# Heregexe(n|s)
test "a heregex will ignore whitespace and comments", ->
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
^ I'm \x20+ [a] \s+
Heregex? / // # or not
///gim + ''
test "an empty heregex will compile to an empty, non-capturing group", ->
eq /(?:)/ + '', /// /// + ''
eq /(?:)/ + '', ////// + ''
test "heregex starting with slashes", ->
ok /////a/\////.test ' //a// '
test '#2388: `///` in heregex interpolations', ->
ok ///a#{///b///}c///.test ' /a/b/c/ '
ws = ' \t'
scan = (regex) -> regex.exec('\t foo')[0]
eq '/\t /', /// #{scan /// [#{ws}]* ///} /// + ''
test "regexes are not callable", ->
throws -> CoffeeScript.compile '/a/()'
throws -> CoffeeScript.compile '///a#{b}///()'
throws -> CoffeeScript.compile '/a/ 1'
throws -> CoffeeScript.compile '///a#{b}/// 1'
throws -> CoffeeScript.compile '''
/a/
k: v
'''
throws -> CoffeeScript.compile '''
///a#{b}///
k: v
'''
test "backreferences", ->
ok /(a)(b)\2\1/.test 'abba'
test "#3795: Escape otherwise invalid characters", ->
ok (//).test '\u2028'
ok (//).test '\u2029'
ok ///\///.test '\u2028'
ok ///\///.test '\u2029'
ok ///ab///.test 'ab' # The space is U+2028.
ok ///ab///.test 'ab' # The space is U+2029.
ok ///\0
1///.test '\x001'
a = 'a'
ok ///#{a}b///.test 'ab' # The space is U+2028.
ok ///#{a}b///.test 'ab' # The space is U+2029.
ok ///#{a}\///.test 'a\u2028'
ok ///#{a}\///.test 'a\u2029'
ok ///#{a}\0
1///.test 'a\x001'