PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/core/string/gsub_spec.rb

https://bitbucket.org/nicksieger/rubyspec
Ruby | 405 lines | 388 code | 17 blank | 0 comment | 22 complexity | bea93e0bef48b34979852122350c1542 MD5 | raw file
  1. require File.dirname(__FILE__) + '/../../spec_helper'
  2. require File.dirname(__FILE__) + '/fixtures/classes.rb'
  3. describe "String#gsub with pattern and replacement" do
  4. it "doesn't freak out when replacing ^" do
  5. "Text\n".gsub(/^/, ' ').should == " Text\n"
  6. "Text\nFoo".gsub(/^/, ' ').should == " Text\n Foo"
  7. end
  8. it "returns a copy of self with all occurrences of pattern replaced with replacement" do
  9. "hello".gsub(/[aeiou]/, '*').should == "h*ll*"
  10. str = "hello homely world. hah!"
  11. str.gsub(/\Ah\S+\s*/, "huh? ").should == "huh? homely world. hah!"
  12. "hello".gsub(//, ".").should == ".h.e.l.l.o."
  13. end
  14. it "ignores a block if supplied" do
  15. "food".gsub(/f/, "g") { "w" }.should == "good"
  16. end
  17. it "supports \\G which matches at the beginning of the remaining (non-matched) string" do
  18. str = "hello homely world. hah!"
  19. str.gsub(/\Gh\S+\s*/, "huh? ").should == "huh? huh? world. hah!"
  20. end
  21. it "supports /i for ignoring case" do
  22. str = "Hello. How happy are you?"
  23. str.gsub(/h/i, "j").should == "jello. jow jappy are you?"
  24. str.gsub(/H/i, "j").should == "jello. jow jappy are you?"
  25. end
  26. it "doesn't interpret regexp metacharacters if pattern is a string" do
  27. "12345".gsub('\d', 'a').should == "12345"
  28. '\d'.gsub('\d', 'a').should == "a"
  29. end
  30. it "replaces \\1 sequences with the regexp's corresponding capture" do
  31. str = "hello"
  32. str.gsub(/([aeiou])/, '<\1>').should == "h<e>ll<o>"
  33. str.gsub(/(.)/, '\1\1').should == "hheelllloo"
  34. str.gsub(/.(.?)/, '<\0>(\1)').should == "<he>(e)<ll>(l)<o>()"
  35. str.gsub(/.(.)+/, '\1').should == "o"
  36. str = "ABCDEFGHIJKLabcdefghijkl"
  37. re = /#{"(.)" * 12}/
  38. str.gsub(re, '\1').should == "Aa"
  39. str.gsub(re, '\9').should == "Ii"
  40. # Only the first 9 captures can be accessed in MRI
  41. str.gsub(re, '\10').should == "A0a0"
  42. end
  43. it "treats \\1 sequences without corresponding captures as empty strings" do
  44. str = "hello!"
  45. str.gsub("", '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
  46. str.gsub("h", '<\1>').should == "<>ello!"
  47. str.gsub(//, '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
  48. str.gsub(/./, '\1\2\3').should == ""
  49. str.gsub(/.(.{20})?/, '\1').should == ""
  50. end
  51. it "replaces \\& and \\0 with the complete match" do
  52. str = "hello!"
  53. str.gsub("", '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
  54. str.gsub("", '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
  55. str.gsub("he", '<\0>').should == "<he>llo!"
  56. str.gsub("he", '<\&>').should == "<he>llo!"
  57. str.gsub("l", '<\0>').should == "he<l><l>o!"
  58. str.gsub("l", '<\&>').should == "he<l><l>o!"
  59. str.gsub(//, '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
  60. str.gsub(//, '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
  61. str.gsub(/../, '<\0>').should == "<he><ll><o!>"
  62. str.gsub(/../, '<\&>').should == "<he><ll><o!>"
  63. str.gsub(/(.)./, '<\0>').should == "<he><ll><o!>"
  64. end
  65. it "replaces \\` with everything before the current match" do
  66. str = "hello!"
  67. str.gsub("", '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
  68. str.gsub("h", '<\`>').should == "<>ello!"
  69. str.gsub("l", '<\`>').should == "he<he><hel>o!"
  70. str.gsub("!", '<\`>').should == "hello<hello>"
  71. str.gsub(//, '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
  72. str.gsub(/../, '<\`>').should == "<><he><hell>"
  73. end
  74. it "replaces \\' with everything after the current match" do
  75. str = "hello!"
  76. str.gsub("", '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
  77. str.gsub("h", '<\\\'>').should == "<ello!>ello!"
  78. str.gsub("ll", '<\\\'>').should == "he<o!>o!"
  79. str.gsub("!", '<\\\'>').should == "hello<>"
  80. str.gsub(//, '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
  81. str.gsub(/../, '<\\\'>').should == "<llo!><o!><>"
  82. end
  83. it "replaces \\+ with the last paren that actually matched" do
  84. str = "hello!"
  85. str.gsub(/(.)(.)/, '\+').should == "el!"
  86. str.gsub(/(.)(.)+/, '\+').should == "!"
  87. str.gsub(/(.)()/, '\+').should == ""
  88. str.gsub(/(.)(.{20})?/, '<\+>').should == "<h><e><l><l><o><!>"
  89. str = "ABCDEFGHIJKLabcdefghijkl"
  90. re = /#{"(.)" * 12}/
  91. str.gsub(re, '\+').should == "Ll"
  92. end
  93. it "treats \\+ as an empty string if there was no captures" do
  94. "hello!".gsub(/./, '\+').should == ""
  95. end
  96. it "maps \\\\ in replacement to \\" do
  97. "hello".gsub(/./, '\\\\').should == '\\' * 5
  98. end
  99. it "leaves unknown \\x escapes in replacement untouched" do
  100. "hello".gsub(/./, '\\x').should == '\\x' * 5
  101. "hello".gsub(/./, '\\y').should == '\\y' * 5
  102. end
  103. it "leaves \\ at the end of replacement untouched" do
  104. "hello".gsub(/./, 'hah\\').should == 'hah\\' * 5
  105. end
  106. it "taints the result if the original string or replacement is tainted" do
  107. hello = "hello"
  108. hello_t = "hello"
  109. a = "a"
  110. a_t = "a"
  111. empty = ""
  112. empty_t = ""
  113. hello_t.taint; a_t.taint; empty_t.taint
  114. hello_t.gsub(/./, a).tainted?.should == true
  115. hello_t.gsub(/./, empty).tainted?.should == true
  116. hello.gsub(/./, a_t).tainted?.should == true
  117. hello.gsub(/./, empty_t).tainted?.should == true
  118. hello.gsub(//, empty_t).tainted?.should == true
  119. hello.gsub(//.taint, "foo").tainted?.should == false
  120. end
  121. ruby_version_is "1.9" do
  122. it "untrusts the result if the original string or replacement is untrusted" do
  123. hello = "hello"
  124. hello_t = "hello"
  125. a = "a"
  126. a_t = "a"
  127. empty = ""
  128. empty_t = ""
  129. hello_t.untrust; a_t.untrust; empty_t.untrust
  130. hello_t.gsub(/./, a).untrusted?.should == true
  131. hello_t.gsub(/./, empty).untrusted?.should == true
  132. hello.gsub(/./, a_t).untrusted?.should == true
  133. hello.gsub(/./, empty_t).untrusted?.should == true
  134. hello.gsub(//, empty_t).untrusted?.should == true
  135. hello.gsub(//.untrust, "foo").untrusted?.should == false
  136. end
  137. end
  138. it "tries to convert pattern to a string using to_str" do
  139. pattern = mock('.')
  140. def pattern.to_str() "." end
  141. "hello.".gsub(pattern, "!").should == "hello!"
  142. end
  143. it "raises a TypeError when pattern can't be converted to a string" do
  144. lambda { "hello".gsub(:woot, "x") }.should raise_error(TypeError)
  145. lambda { "hello".gsub(?e, "x") }.should raise_error(TypeError)
  146. lambda { "hello".gsub(nil, "x") }.should raise_error(TypeError)
  147. end
  148. it "tries to convert replacement to a string using to_str" do
  149. replacement = mock('hello_replacement')
  150. def replacement.to_str() "hello_replacement" end
  151. "hello".gsub(/hello/, replacement).should == "hello_replacement"
  152. end
  153. it "raises a TypeError when replacement can't be converted to a string" do
  154. lambda { "hello".gsub(/[aeiou]/, :woot) }.should raise_error(TypeError)
  155. lambda { "hello".gsub(/[aeiou]/, ?f) }.should raise_error(TypeError)
  156. lambda { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
  157. end
  158. it "returns subclass instances when called on a subclass" do
  159. StringSpecs::MyString.new("").gsub(//, "").class.should == StringSpecs::MyString
  160. StringSpecs::MyString.new("").gsub(/foo/, "").class.should == StringSpecs::MyString
  161. StringSpecs::MyString.new("foo").gsub(/foo/, "").class.should == StringSpecs::MyString
  162. StringSpecs::MyString.new("foo").gsub("foo", "").class.should == StringSpecs::MyString
  163. end
  164. # Note: $~ cannot be tested because mspec messes with it
  165. it "sets $~ to MatchData of last match and nil when there's none" do
  166. 'hello.'.gsub('hello', 'x')
  167. $~[0].should == 'hello'
  168. 'hello.'.gsub('not', 'x')
  169. $~.should == nil
  170. 'hello.'.gsub(/.(.)/, 'x')
  171. $~[0].should == 'o.'
  172. 'hello.'.gsub(/not/, 'x')
  173. $~.should == nil
  174. end
  175. end
  176. describe "String#gsub with pattern and block" do
  177. it "returns a copy of self with all occurrences of pattern replaced with the block's return value" do
  178. "hello".gsub(/./) { |s| s.succ + ' ' }.should == "i f m m p "
  179. "hello!".gsub(/(.)(.)/) { |*a| a.inspect }.should == '["he"]["ll"]["o!"]'
  180. "hello".gsub('l') { 'x'}.should == 'hexxo'
  181. end
  182. it "sets $~ for access from the block" do
  183. str = "hello"
  184. str.gsub(/([aeiou])/) { "<#{$~[1]}>" }.should == "h<e>ll<o>"
  185. str.gsub(/([aeiou])/) { "<#{$1}>" }.should == "h<e>ll<o>"
  186. str.gsub("l") { "<#{$~[0]}>" }.should == "he<l><l>o"
  187. offsets = []
  188. str.gsub(/([aeiou])/) do
  189. md = $~
  190. md.string.should == str
  191. offsets << md.offset(0)
  192. str
  193. end.should == "hhellollhello"
  194. offsets.should == [[1, 2], [4, 5]]
  195. end
  196. it "restores $~ after leaving the block" do
  197. [/./, "l"].each do |pattern|
  198. old_md = nil
  199. "hello".gsub(pattern) do
  200. old_md = $~
  201. "ok".match(/./)
  202. "x"
  203. end
  204. $~.should == old_md
  205. $~.string.should == "hello"
  206. end
  207. end
  208. it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
  209. 'hello.'.gsub('l') { 'x' }
  210. $~.begin(0).should == 3
  211. $~[0].should == 'l'
  212. 'hello.'.gsub('not') { 'x' }
  213. $~.should == nil
  214. 'hello.'.gsub(/.(.)/) { 'x' }
  215. $~[0].should == 'o.'
  216. 'hello.'.gsub(/not/) { 'x' }
  217. $~.should == nil
  218. end
  219. it "raises a RuntimeError if the string is modified while substituting" do
  220. str = "hello"
  221. lambda { str.gsub(//) { str[0] = 'x' } }.should raise_error(RuntimeError)
  222. end
  223. it "doesn't interpolate special sequences like \\1 for the block's return value" do
  224. repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
  225. "hello".gsub(/(.+)/) { repl }.should == repl
  226. end
  227. it "converts the block's return value to a string using to_s" do
  228. replacement = mock('hello_replacement')
  229. def replacement.to_s() "hello_replacement" end
  230. "hello".gsub(/hello/) { replacement }.should == "hello_replacement"
  231. obj = mock('ok')
  232. def obj.to_s() "ok" end
  233. "hello".gsub(/.+/) { obj }.should == "ok"
  234. end
  235. ruby_version_is "1.9" do
  236. it "untrusts the result if the original string or replacement is untrusted" do
  237. hello = "hello"
  238. hello_t = "hello"
  239. a = "a"
  240. a_t = "a"
  241. empty = ""
  242. empty_t = ""
  243. hello_t.untrust; a_t.untrust; empty_t.untrust
  244. hello_t.gsub(/./) { a }.untrusted?.should == true
  245. hello_t.gsub(/./) { empty }.untrusted?.should == true
  246. hello.gsub(/./) { a_t }.untrusted?.should == true
  247. hello.gsub(/./) { empty_t }.untrusted?.should == true
  248. hello.gsub(//) { empty_t }.untrusted?.should == true
  249. hello.gsub(//.untrust) { "foo" }.untrusted?.should == false
  250. end
  251. end
  252. end
  253. describe "String#gsub! with pattern and replacement" do
  254. it "modifies self in place and returns self" do
  255. a = "hello"
  256. a.gsub!(/[aeiou]/, '*').should equal(a)
  257. a.should == "h*ll*"
  258. end
  259. it "taints self if replacement is tainted" do
  260. a = "hello"
  261. a.gsub!(/./.taint, "foo").tainted?.should == false
  262. a.gsub!(/./, "foo".taint).tainted?.should == true
  263. end
  264. ruby_version_is "1.9" do
  265. it "untrusts self if replacement is untrusted" do
  266. a = "hello"
  267. a.gsub!(/./.untrust, "foo").untrusted?.should == false
  268. a.gsub!(/./, "foo".untrust).untrusted?.should == true
  269. end
  270. end
  271. it "returns nil if no modifications were made" do
  272. a = "hello"
  273. a.gsub!(/z/, '*').should == nil
  274. a.gsub!(/z/, 'z').should == nil
  275. a.should == "hello"
  276. end
  277. it "raises a TypeError when self is frozen" do
  278. s = "hello"
  279. s.freeze
  280. s.gsub!(/ROAR/, "x") # ok
  281. lambda { s.gsub!(/e/, "e") }.should raise_error(TypeError)
  282. lambda { s.gsub!(/[aeiou]/, '*') }.should raise_error(TypeError)
  283. end
  284. end
  285. describe "String#gsub! with pattern and block" do
  286. it "modifies self in place and returns self" do
  287. a = "hello"
  288. a.gsub!(/[aeiou]/) { '*' }.should equal(a)
  289. a.should == "h*ll*"
  290. end
  291. it "taints self if block's result is tainted" do
  292. a = "hello"
  293. a.gsub!(/./.taint) { "foo" }.tainted?.should == false
  294. a.gsub!(/./) { "foo".taint }.tainted?.should == true
  295. end
  296. ruby_version_is "1.9" do
  297. it "untrusts self if block's result is untrusted" do
  298. a = "hello"
  299. a.gsub!(/./.untrust) { "foo" }.untrusted?.should == false
  300. a.gsub!(/./) { "foo".untrust }.untrusted?.should == true
  301. end
  302. end
  303. it "returns nil if no modifications were made" do
  304. a = "hello"
  305. a.gsub!(/z/) { '*' }.should == nil
  306. a.gsub!(/z/) { 'z' }.should == nil
  307. a.should == "hello"
  308. end
  309. it "raises a RuntimeError when self is frozen" do
  310. s = "hello"
  311. s.freeze
  312. s.gsub!(/ROAR/) { "x" } # ok
  313. lambda { s.gsub!(/e/) { "e" } }.should raise_error(RuntimeError)
  314. lambda { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(RuntimeError)
  315. end
  316. end