utils_spec.rb 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. require 'rails_helper'
  2. describe Utils do
  3. describe "#unindent" do
  4. it "unindents to the level of the greatest consistant indention" do
  5. expect(Utils.unindent(<<-MD)).to eq("Hello World")
  6. Hello World
  7. MD
  8. expect(Utils.unindent(<<-MD)).to eq("Hello World\nThis is\nnot indented")
  9. Hello World
  10. This is
  11. not indented
  12. MD
  13. expect(Utils.unindent(<<-MD)).to eq("Hello World\n This is\n indented\nthough")
  14. Hello World
  15. This is
  16. indented
  17. though
  18. MD
  19. expect(Utils.unindent("Hello\n I am indented")).to eq("Hello\n I am indented")
  20. a = " Events will have the fields you specified. Your options look like:\n\n {\n \"url\": {\n \"css\": \"#comic img\",\n \"value\": \"@src\"\n },\n \"title\": {\n \"css\": \"#comic img\",\n \"value\": \"@title\"\n }\n }\"\n"
  21. expect(Utils.unindent(a)).to eq("Events will have the fields you specified. Your options look like:\n\n {\n \"url\": {\n\"css\": \"#comic img\",\n\"value\": \"@src\"\n },\n \"title\": {\n\"css\": \"#comic img\",\n\"value\": \"@title\"\n }\n }\"")
  22. end
  23. end
  24. describe "#interpolate_jsonpaths" do
  25. let(:payload) { { :there => { :world => "WORLD" }, :works => "should work" } }
  26. it "interpolates jsonpath expressions between matching <>'s" do
  27. expect(Utils.interpolate_jsonpaths("hello <$.there.world> this <escape works>", payload)).to eq("hello WORLD this should+work")
  28. end
  29. it "optionally supports treating values that start with '$' as raw JSONPath" do
  30. expect(Utils.interpolate_jsonpaths("$.there.world", payload)).to eq("$.there.world")
  31. expect(Utils.interpolate_jsonpaths("$.there.world", payload, :leading_dollarsign_is_jsonpath => true)).to eq("WORLD")
  32. end
  33. end
  34. describe "#recursively_interpolate_jsonpaths" do
  35. it "interpolates all string values in a structure" do
  36. struct = {
  37. :int => 5,
  38. :string => "this <escape $.works>",
  39. :array => ["<works>", "now", "<$.there.world>"],
  40. :deep => {
  41. :string => "hello <there.world>",
  42. :hello => :world
  43. }
  44. }
  45. data = { :there => { :world => "WORLD" }, :works => "should work" }
  46. expect(Utils.recursively_interpolate_jsonpaths(struct, data)).to eq({
  47. :int => 5,
  48. :string => "this should+work",
  49. :array => ["should work", "now", "WORLD"],
  50. :deep => {
  51. :string => "hello WORLD",
  52. :hello => :world
  53. }
  54. })
  55. end
  56. end
  57. describe "#value_at" do
  58. it "returns the value at a JSON path" do
  59. expect(Utils.value_at({ :foo => { :bar => :baz }}.to_json, "foo.bar")).to eq("baz")
  60. expect(Utils.value_at({ :foo => { :bar => { :bing => 2 } }}, "foo.bar.bing")).to eq(2)
  61. expect(Utils.value_at({ :foo => { :bar => { :bing => 2 } }}, "foo.bar[?(@.bing == 2)].bing")).to eq(2)
  62. end
  63. it "returns nil when the path cannot be followed" do
  64. expect(Utils.value_at({ :foo => { :bar => :baz }}, "foo.bing")).to be_nil
  65. end
  66. end
  67. describe "#values_at" do
  68. it "returns arrays of matching values" do
  69. expect(Utils.values_at({ :foo => { :bar => :baz }}, "foo.bar")).to eq(%w[baz])
  70. expect(Utils.values_at({ :foo => [ { :bar => :baz }, { :bar => :bing } ]}, "foo[*].bar")).to eq(%w[baz bing])
  71. expect(Utils.values_at({ :foo => [ { :bar => :baz }, { :bar => :bing } ]}, "foo[*].bar")).to eq(%w[baz bing])
  72. end
  73. it "should allow escaping" do
  74. expect(Utils.values_at({ :foo => { :bar => "escape this!?" }}, "escape $.foo.bar")).to eq(["escape+this%21%3F"])
  75. end
  76. end
  77. describe "#jsonify" do
  78. it "escapes </script> tags in the output JSON" do
  79. cleaned_json = Utils.jsonify(:foo => "bar", :xss => "</script><script>alert('oh no!')</script>")
  80. expect(cleaned_json).not_to include("</script>")
  81. expect(cleaned_json).to include('\\u003c/script\\u003e')
  82. end
  83. it "html_safes the output unless :skip_safe is passed in" do
  84. expect(Utils.jsonify({:foo => "bar"})).to be_html_safe
  85. expect(Utils.jsonify({:foo => "bar"}, :skip_safe => false)).to be_html_safe
  86. expect(Utils.jsonify({:foo => "bar"}, :skip_safe => true)).not_to be_html_safe
  87. end
  88. end
  89. describe "#pretty_jsonify" do
  90. it "escapes </script> tags in the output JSON" do
  91. cleaned_json = Utils.pretty_jsonify(:foo => "bar", :xss => "</script><script>alert('oh no!')</script>")
  92. expect(cleaned_json).not_to include("</script>")
  93. expect(cleaned_json).to include("<\\/script>")
  94. end
  95. end
  96. describe "#sort_tuples!" do
  97. let(:tuples) {
  98. time = Time.now
  99. [
  100. [2, "a", time - 1], # 0
  101. [2, "b", time - 1], # 1
  102. [1, "b", time - 1], # 2
  103. [1, "b", time], # 3
  104. [1, "a", time], # 4
  105. [2, "a", time + 1], # 5
  106. [2, "a", time], # 6
  107. ]
  108. }
  109. it "sorts tuples like arrays by default" do
  110. expected = tuples.values_at(4, 2, 3, 0, 6, 5, 1)
  111. Utils.sort_tuples!(tuples)
  112. expect(tuples).to eq expected
  113. end
  114. it "sorts tuples in order specified: case 1" do
  115. # order by x1 asc, x2 desc, c3 asc
  116. orders = [false, true, false]
  117. expected = tuples.values_at(2, 3, 4, 1, 0, 6, 5)
  118. Utils.sort_tuples!(tuples, orders)
  119. expect(tuples).to eq expected
  120. end
  121. it "sorts tuples in order specified: case 2" do
  122. # order by x1 desc, x2 asc, c3 desc
  123. orders = [true, false, true]
  124. expected = tuples.values_at(5, 6, 0, 1, 4, 3, 2)
  125. Utils.sort_tuples!(tuples, orders)
  126. expect(tuples).to eq expected
  127. end
  128. it "always succeeds in sorting even if it finds pairs of incomparable objects" do
  129. time = Time.now
  130. tuples = [
  131. [2, "a", time - 1], # 0
  132. [1, "b", nil], # 1
  133. [1, "b", time], # 2
  134. ["2", nil, time], # 3
  135. [1, nil, time], # 4
  136. [nil, "a", time + 1], # 5
  137. [2, "a", time], # 6
  138. ]
  139. orders = [true, false, true]
  140. expected = tuples.values_at(3, 6, 0, 4, 2, 1, 5)
  141. Utils.sort_tuples!(tuples, orders)
  142. expect(tuples).to eq expected
  143. end
  144. end
  145. context "#parse_duration" do
  146. it "works with correct arguments" do
  147. expect(Utils.parse_duration('2.days')).to eq(2.days)
  148. expect(Utils.parse_duration('2.seconds')).to eq(2)
  149. expect(Utils.parse_duration('2')).to eq(2)
  150. end
  151. it "returns nil when passed nil" do
  152. expect(Utils.parse_duration(nil)).to be_nil
  153. end
  154. it "warns and returns nil when not parseable" do
  155. mock(STDERR).puts("WARNING: Invalid duration format: 'bogus'")
  156. expect(Utils.parse_duration('bogus')).to be_nil
  157. end
  158. end
  159. context "#if_present" do
  160. it "returns nil when passed nil" do
  161. expect(Utils.if_present(nil, :to_i)).to be_nil
  162. end
  163. it "calls the specified method when the argument is present" do
  164. argument = mock()
  165. mock(argument).to_i { 1 }
  166. expect(Utils.if_present(argument, :to_i)).to eq(1)
  167. end
  168. end
  169. end