1Code.require_file("../test_helper.exs", __DIR__) 2 3defmodule ExUnit.DiffTest do 4 use ExUnit.Case, async: true 5 6 alias Inspect.Algebra 7 alias ExUnit.{Assertions, Diff} 8 9 defmodule User do 10 defstruct [:name, :age] 11 end 12 13 defmodule Person do 14 defstruct [:age] 15 end 16 17 defmodule Opaque do 18 defstruct [:data] 19 20 defimpl Inspect do 21 def inspect(%{data: data}, _) when is_tuple(data) or is_map(data), 22 do: "#Opaque<data: #{inspect(data)}>" 23 24 def inspect(_, _), 25 do: "#Opaque<???>" 26 end 27 end 28 29 defmacrop one, do: 1 30 31 defmacrop tuple(a, b) do 32 quote do 33 {unquote(a), unquote(b)} 34 end 35 end 36 37 defmacrop pin_x do 38 x = Macro.var(:x, nil) 39 quote(do: ^unquote(x)) 40 end 41 42 defmacrop assert_diff(expr, expected_binding, pins \\ []) 43 44 defmacrop assert_diff({:=, _, [left, right]}, expected_binding, pins) do 45 left = Assertions.__expand_pattern__(left, __CALLER__) |> Macro.escape() 46 47 quote do 48 assert_diff( 49 unquote(left), 50 unquote(right), 51 unquote(expected_binding), 52 {:match, unquote(pins)} 53 ) 54 end 55 end 56 57 defmacrop assert_diff({op, _, [left, right]}, [], []) when op in [:==, :===] do 58 quote do 59 assert_diff(unquote(left), unquote(right), [], unquote(op)) 60 end 61 end 62 63 defmacrop refute_diff(expr, expected_left, expected_right, pins \\ []) 64 65 defmacrop refute_diff({:=, _, [left, right]}, expected_left, expected_right, pins) do 66 left = Assertions.__expand_pattern__(left, __CALLER__) |> Macro.escape() 67 68 quote do 69 refute_diff( 70 unquote(left), 71 unquote(right), 72 unquote(expected_left), 73 unquote(expected_right), 74 {:match, unquote(pins)} 75 ) 76 end 77 end 78 79 defmacrop refute_diff({op, _, [left, right]}, expected_left, expected_right, []) 80 when op in [:==, :===] do 81 quote do 82 refute_diff( 83 unquote(left), 84 unquote(right), 85 unquote(expected_left), 86 unquote(expected_right), 87 unquote(op) 88 ) 89 end 90 end 91 92 defp refute_diff(left, right, expected_left, expected_right, context) do 93 {diff, _env} = Diff.compute(left, right, context) 94 assert diff.equivalent? == false 95 96 diff_left = to_diff(diff.left, "-") 97 assert diff_left =~ expected_left 98 99 diff_right = to_diff(diff.right, "+") 100 assert diff_right =~ expected_right 101 end 102 103 defp assert_diff(left, right, expected_binding, context) do 104 {diff, env} = Diff.compute(left, right, context) 105 env_binding = for {{name, _}, value} <- env.current_vars, do: {name, value} 106 107 assert diff.equivalent? == true 108 assert env_binding == expected_binding 109 end 110 111 defp to_diff(side, sign) do 112 side 113 |> Diff.to_algebra(&diff_wrapper(&1, sign)) 114 |> Algebra.format(:infinity) 115 |> IO.iodata_to_binary() 116 end 117 118 defp diff_wrapper(doc, side) do 119 Algebra.concat([side, doc, side]) 120 end 121 122 test "atoms" do 123 assert_diff(:a = :a, []) 124 assert_diff(:a = :a, []) 125 assert_diff(:"$a" = :"$a", []) 126 127 refute_diff(:a = :b, "-:a-", "+:b+") 128 refute_diff(:a = :aa, "-:a-", "+:aa+") 129 130 refute_diff(:"$" = :"$a", ~s[-:"$"-], ~s[+:"$a"+]) 131 refute_diff(:"$a" = :"$b", ~s[-:"$a"-], ~s[+:"$b"+]) 132 133 refute_diff(:bar = 42, "-:bar-", "+42+") 134 refute_diff(42 = :bar, "-42-", "+:bar+") 135 136 pins = %{{:a, nil} => :a, {:b, nil} => :b} 137 assert_diff(x = :a, [x: :a], pins) 138 assert_diff(^a = :a, [], pins) 139 assert_diff(^b = :b, [], pins) 140 141 refute_diff(^a = :b, "-^a-", "+:b+", pins) 142 refute_diff(^b = :a, "-^b-", "+:a+", pins) 143 end 144 145 test "pseudo vars" do 146 assert_diff(__MODULE__ = ExUnit.DiffTest, []) 147 refute_diff(__MODULE__ = SomethingElse, "-__MODULE__-", "+SomethingElse+") 148 end 149 150 test "integers" do 151 assert_diff(123 = 123, []) 152 assert_diff(-123 = -123, []) 153 assert_diff(123 = +123, []) 154 assert_diff(+123 = 123, []) 155 156 refute_diff(12 = 13, "1-2-", "1+3+") 157 refute_diff(12345 = 123, "123-45-", "123") 158 refute_diff(123 = 12345, "123", "123+45+") 159 refute_diff(12345 = 345, "-12-345", "345") 160 refute_diff(345 = 12345, "345", "+12+345") 161 refute_diff(123 = -123, "123", "+-+123") 162 refute_diff(-123 = 123, "---123", "123") 163 refute_diff(491_512_235 = 490_512_035, "49-1-512-2-35", "49+0+512+0+35") 164 165 assert_diff(0xF = 15, []) 166 refute_diff(0xF = 16, "1-5-", "1+6+") 167 refute_diff(123 = :a, "-123-", "+:a+") 168 end 169 170 test "floats" do 171 assert_diff(123.0 = 123.0, []) 172 assert_diff(-123.0 = -123.0, []) 173 assert_diff(123.0 = +123.0, []) 174 assert_diff(+123.0 = 123.0, []) 175 176 refute_diff(1.2 = 1.3, "1.-2-", "1.+3+") 177 refute_diff(12.345 = 12.3, "12.3-45-", "12.3") 178 refute_diff(12.3 = 12.345, "12.3", "12.3+45+") 179 refute_diff(123.45 = 3.45, "-12-3.45", "3.45") 180 refute_diff(3.45 = 123.45, "3.45", "+12+3.45") 181 refute_diff(1.23 = -1.23, "1.23", "+-+1.23") 182 refute_diff(-1.23 = 1.23, "---1.23", "1.23") 183 refute_diff(123.0 = :a, "-123.0-", "+:a+") 184 refute_diff(123.0 = 123_512_235, "-123.0-", "+123512235+") 185 end 186 187 test "== / ===" do 188 refute_diff( 189 %{a: 1, b: 2} == %{a: 1.0, b: :two}, 190 "%{a: 1, b: -2-}", 191 "%{a: 1.0, b: +:two+}" 192 ) 193 194 refute_diff( 195 %{a: 1, b: 2} === %{a: 1.0, b: :two}, 196 "%{a: -1-, b: -2-}", 197 "%{a: +1.0+, b: +:two+}" 198 ) 199 end 200 201 test "lists" do 202 assert_diff([] = [], []) 203 204 assert_diff([:a] = [:a], []) 205 assert_diff([:a, :b, :c] = [:a, :b, :c], []) 206 207 refute_diff([] = [:a], "[]", "[+:a+]") 208 refute_diff([:a] = [], "[-:a-]", "[]") 209 refute_diff([:a] = [:b], "[-:a-]", "[+:b+]") 210 refute_diff([:a, :b, :c] = [:a, :b, :x], "[:a, :b, -:c-]", "[:a, :b, +:x+]") 211 refute_diff([:a, :x, :c] = [:a, :b, :c], "[:a, -:x-, :c]", "[:a, +:b+, :c]") 212 refute_diff([:a, :d, :b, :c] = [:a, :b, :c, :d], "[:a, -:d-, :b, :c]", "[:a, :b, :c, +:d+]") 213 214 refute_diff([:a, :b, :c] = [:a, :b, []], "[:a, :b, -:c-]", "[:a, :b, +[]+]") 215 refute_diff([:a, :b, []] = [:a, :b, :c], "[:a, :b, -[]-]", "[:a, :b, +:c+]") 216 refute_diff([:a, :b, :c] = [:a, :b], "[:a, :b, -:c-]", "[:a, :b]") 217 refute_diff([:a, :b] = [:a, :b, :c], "[:a, :b]", "[:a, :b, +:c+]") 218 refute_diff([:a, :b, :c, :d, :e] = [:a, :b], "[:a, :b, -:c-, -:d-, -:e-]", "[:a, :b]") 219 refute_diff([:a, :b] = [:a, :b, :c, :d, :e], "[:a, :b]", "[:a, :b, +:c+, +:d+, +:e+]") 220 221 refute_diff( 222 [:a, [:d, :b, :c]] = [:a, [:b, :c, :d]], 223 "[:a, [-:d-, :b, :c]]", 224 "[:a, [:b, :c, +:d+]]" 225 ) 226 227 refute_diff( 228 [:e, :a, :b, :c, :d] = [:a, :b, :c, :d, :e], 229 "[-:e-, :a, :b, :c, :d]", 230 "[:a, :b, :c, :d, +:e+]" 231 ) 232 233 refute_diff([:a, [:c, :b]] = [:a, [:b, :c]], "[:a, [-:c-, :b]]", "[:a, [:b, +:c+]]") 234 refute_diff(:a = [:a, [:b, :c]], "-:a-", "+[:a, [:b, :c]]+") 235 236 pins = %{{:a, nil} => :a, {:b, nil} => :b, {:list_ab, nil} => [:a, :b]} 237 238 assert_diff(x = [], [x: []], pins) 239 assert_diff(x = [:a, :b], [x: [:a, :b]], pins) 240 assert_diff([x] = [:a], [x: :a], pins) 241 assert_diff([x, :b, :c] = [:a, :b, :c], [x: :a], pins) 242 assert_diff([x, y, z] = [:a, :b, :c], [x: :a, y: :b, z: :c], pins) 243 assert_diff([x, x, :c] = [:a, :a, :c], [x: :a], pins) 244 245 refute_diff([x] = [], "[-x-]", "[]") 246 refute_diff([x, :b, :c] = [:a, :b, :x], "[x, :b, -:c-]", "[:a, :b, +:x+]") 247 refute_diff([x, x, :c] = [:a, :b, :c], "[x, -x-, :c]", "[:a, +:b+, :c]") 248 249 assert_diff(^list_ab = [:a, :b], [], pins) 250 assert_diff([^a, :b, :c] = [:a, :b, :c], [], pins) 251 assert_diff([^a, ^b, :c] = [:a, :b, :c], [], pins) 252 assert_diff([^a, a, :c] = [:a, :b, :c], [a: :b], pins) 253 assert_diff([b, ^b, :c] = [:a, :b, :c], [b: :a], pins) 254 255 refute_diff(^list_ab = [:x, :b], "-^list_ab-", "[+:x+, :b]", pins) 256 refute_diff([^a, :b, :c] = [:a, :b, :x], "[^a, :b, -:c-]", "[:a, :b, +:x+]", pins) 257 refute_diff([:a, ^a, :c] = [:a, :b, :c], "[:a, -^a-, :c]", "[:a, +:b+, :c]", pins) 258 259 refute_diff( 260 [x, :a, :b, :c, :d] = [:a, :b, :c, :d, :e], 261 "[x, -:a-, :b, :c, :d]", 262 "[:a, :b, :c, :d, +:e+]" 263 ) 264 265 refute_diff([:a, :b] = :a, "-[:a, :b]-", "+:a+") 266 refute_diff([:foo] = [:foo, {:a, :b, :c}], "[:foo]", "[:foo, +{:a, :b, :c}+]") 267 end 268 269 test "improper lists" do 270 assert_diff([:a | :b] = [:a | :b], []) 271 assert_diff([:a, :b | :c] = [:a, :b | :c], []) 272 273 refute_diff([:a | :b] = [:b | :a], "[-:a- | -:b-]", "[+:b+ | +:a+]") 274 refute_diff([:a | :b] = [:a | :x], "[:a | -:b-]", "[:a | +:x+]") 275 refute_diff([:a, :b | :c] = [:a, :b | :x], "[:a, :b | -:c-]", "[:a, :b | +:x+]") 276 refute_diff([:a, :x | :c] = [:a, :b | :c], "[:a, -:x- | :c]", "[:a, +:b+ | :c]") 277 refute_diff([:x, :b | :c] = [:a, :b | :c], "[-:x-, :b | :c]", "[+:a+, :b | :c]") 278 refute_diff([:c, :a | :b] = [:a, :b | :c], "[-:c-, :a | -:b-]", "[:a, +:b+ | +:c+]") 279 280 refute_diff( 281 [:a, :c, :x | :b] = [:a, :b, :c | :d], 282 "[:a, :c, -:x- | -:b-]", 283 "[:a, +:b+, :c | +:d+]" 284 ) 285 286 refute_diff([:a | :d] = [:a, :b, :c | :d], "[:a | -:d-]", "[:a, +:b+, +:c+ | +:d+]") 287 288 refute_diff( 289 [[:a | :x], :x | :d] = [[:a | :b], :c | :d], 290 "[[:a | -:x-], -:x- | :d]", 291 "[[:a | +:b+], +:c+ | :d]" 292 ) 293 294 assert_diff([:a | x] = [:a | :b], x: :b) 295 end 296 297 test "proper lists" do 298 assert_diff([:a | [:b]] = [:a, :b], []) 299 assert_diff([:a | [:b, :c]] = [:a, :b, :c], []) 300 301 refute_diff([:a | [:b]] = [:a, :x], "[:a | [-:b-]]", "[:a, +:x+]") 302 303 refute_diff([:a, :b | [:c]] = [:a, :b, :x], "[:a, :b | [-:c-]]", "[:a, :b, +:x+]") 304 refute_diff([:a, :x | [:c]] = [:a, :b, :c], "[:a, -:x- | [:c]]", "[:a, +:b+, :c]") 305 refute_diff([:a | [:b, :c]] = [:a, :b, :x], "[:a | [:b, -:c-]]", "[:a, :b, +:x+]") 306 refute_diff([:a | [:b, :c]] = [:x, :b, :c], "[-:a- | [:b, :c]]", "[+:x+, :b, :c]") 307 308 refute_diff( 309 [:a, :c, :x | [:b, :c]] = [:a, :b, :c, :d, :e], 310 "[:a, -:c-, -:x- | [:b, :c]]", 311 "[:a, :b, :c, +:d+, +:e+]" 312 ) 313 314 refute_diff([:a, :b | [:c]] = [:a, :b], "[:a, :b | [-:c-]]", "[:a, :b]") 315 refute_diff([:a, :b | []] = [:a, :b, :c], "[:a, :b | -[]-]", "[:a, :b, +:c+]") 316 refute_diff([:a, :b | [:c, :d]] = [:a, :b, :c], "[:a, :b | [:c, -:d-]]", "[:a, :b, :c]") 317 refute_diff([:a, :b | [:c, :d]] = [:a], "[:a, -:b- | [-:c-, -:d-]]", "[:a]") 318 319 refute_diff( 320 [:a, [:b, :c] | [:d, :e]] = [:a, [:x, :y], :d, :e], 321 "[:a, [-:b-, -:c-] | [:d, :e]]", 322 "[:a, [+:x+, +:y+], :d, :e]" 323 ) 324 325 refute_diff( 326 [:a, [:b, :c] | [:d, :e]] = [:a, [:x, :c], :d, :e], 327 "[:a, [-:b-, :c] | [:d, :e]]", 328 "[:a, [+:x+, :c], :d, :e]" 329 ) 330 331 assert_diff([:a | x] = [:a, :b], x: [:b]) 332 assert_diff([:a | x] = [:a, :b, :c], x: [:b, :c]) 333 assert_diff([:a | x] = [:a, :b | :c], x: [:b | :c]) 334 335 pins = %{{:list_bc, nil} => [:b, :c]} 336 assert_diff([:a | ^list_bc] = [:a, :b, :c], [], pins) 337 refute_diff([:a | ^list_bc] = [:x, :x, :c], "[-:a- | -^list_bc-]", "[+:x+, +:x+, :c]", pins) 338 refute_diff([:a | ^list_bc] = [:a, :x, :c], "[:a | -^list_bc-]", "[:a, +:x+, :c]", pins) 339 end 340 341 test "concat lists" do 342 assert_diff([:a] ++ [:b] = [:a, :b], []) 343 assert_diff([:a, :b] ++ [] = [:a, :b], []) 344 assert_diff([] ++ [:a, :b] = [:a, :b], []) 345 346 refute_diff([:a, :b] ++ [:c] = [:a, :b], "[:a, :b] ++ [-:c-]", "[:a, :b]") 347 refute_diff([:a, :c] ++ [:b] = [:a, :b], "[:a, -:c-] ++ [:b]", "[:a, :b]") 348 refute_diff([:a] ++ [:b] ++ [:c] = [:a, :b], "[:a] ++ [:b] ++ [-:c-]", "[:a, :b]") 349 350 assert_diff([:a] ++ :b = [:a | :b], []) 351 assert_diff([:a] ++ x = [:a, :b], x: [:b]) 352 353 refute_diff([:a, :b] ++ :c = [:a, :b, :c], "[:a, :b] ++ -:c-", "[:a, :b, +:c+]") 354 refute_diff([:a] ++ [:b] ++ :c = [:a, :b, :c], "[:a] ++ [:b] ++ -:c-", "[:a, :b, +:c+]") 355 refute_diff([:a] ++ [:b] = :a, "-[:a] ++ [:b]-", "+:a+") 356 end 357 358 @a [:a] 359 test "concat lists with module attributes" do 360 assert_diff(@a ++ [:b] = [:a, :b], []) 361 refute_diff(@a ++ [:b] = [:a], "[:a] ++ [-:b-]", "[:a]") 362 refute_diff(@a ++ [:b] = [:b], "[-:a-] ++ [:b]", "[:b]") 363 end 364 365 test "mixed lists" do 366 refute_diff([:a | :b] = [:a, :b], "[:a | -:b-]", "[:a, +:b+]") 367 refute_diff([:a, :b] = [:a | :b], "[:a, -:b-]", "[:a | +:b+]") 368 refute_diff([:a | [:b]] = [:a | :b], "[:a | -[:b]-]", "[:a | +:b+]") 369 refute_diff([:a | [:b | [:c]]] = [:a | :c], "[:a | -[:b | [:c]]-]", "[:a | +:c+]") 370 refute_diff([:a | :b] = [:a, :b, :c], "[:a | -:b-]", "[:a, +:b+, +:c+]") 371 refute_diff([:a, :b, :c] = [:a | :b], "[:a, -:b-, -:c-]", "[:a | +:b+]") 372 373 refute_diff([:a | [:b] ++ [:c]] = [:a, :b], "[:a | [:b] ++ [-:c-]]", "[:a, :b]") 374 375 refute_diff( 376 [:a | [:b] ++ [:c]] ++ [:d | :e] = [:a, :b | :e], 377 "[:a | [:b] ++ [-:c-]] ++ [-:d- | :e]", 378 "[:a, :b | :e]" 379 ) 380 end 381 382 test "lists outside of match context" do 383 refute_diff( 384 [%_{i_will: :fail}, %_{i_will: :fail_too}] = [], 385 "[-%_{i_will: :fail}-, -%_{i_will: :fail_too}-]", 386 "[]" 387 ) 388 389 refute_diff( 390 [:a, {:|, [], [:b, :c]}] == [:a, :b | :c], 391 "[:a, -{:|, [], [:b, :c]}-]", 392 "[:a, +:b+ | +:c+]" 393 ) 394 395 refute_diff([:foo] == [:foo, {:a, :b, :c}], "[:foo]", "[:foo, +{:a, :b, :c}+]") 396 refute_diff([:foo, {:a, :b, :c}] == [:foo], "[:foo, -{:a, :b, :c}-]", "[:foo]") 397 398 refute_diff([:foo] == [:foo | {:a, :b, :c}], "[:foo]", "[:foo | +{:a, :b, :c}+]") 399 refute_diff([:foo | {:a, :b, :c}] == [:foo], "[:foo | -{:a, :b, :c}-]", "[:foo]") 400 refute_diff([:foo] == [{:a, :b, :c} | :foo], "[-:foo-]", "[+{:a, :b, :c}+ | +:foo+]") 401 refute_diff([{:a, :b, :c} | :foo] == [:foo], "[-{:a, :b, :c}- | -:foo-]", "[+:foo+]") 402 end 403 404 test "keyword lists" do 405 assert_diff([file: "nofile", line: 1] = [file: "nofile", line: 1], []) 406 407 refute_diff( 408 [file: "nofile", line: 1] = [file: nil, lime: 1], 409 ~s/[file: -"nofile"-, -line:- 1]/, 410 "[file: +nil+, +lime:+ 1]" 411 ) 412 413 refute_diff( 414 [file: nil, line: 1] = [file: "nofile"], 415 "[file: -nil-, -line: 1-]", 416 ~s/[file: +"nofile"+]/ 417 ) 418 419 refute_diff( 420 ["foo-bar": 1] = [], 421 ~s/[-"foo-bar": 1-]/, 422 "[]" 423 ) 424 425 refute_diff( 426 [file: nil] = [{:line, 1}, {1, :foo}], 427 "[-file:- -nil-]", 428 "[{+:line+, +1+}, +{1, :foo}+]" 429 ) 430 end 431 432 test "tuples" do 433 assert_diff({:a, :b} = {:a, :b}, []) 434 435 refute_diff({:a, :b} = {:a, :x}, "{:a, -:b-}", "{:a, +:x+}") 436 refute_diff({:a, :b} = {:x, :x}, "{-:a-, -:b-}", "{+:x+, +:x+}") 437 refute_diff({:a, :b, :c} = {:a, :b, :x}, "{:a, :b, -:c-}", "{:a, :b, +:x+}") 438 439 refute_diff({:a} = {:a, :b}, "{:a}", "{:a, +:b+}") 440 refute_diff({:a, :b} = {:a}, "{:a, -:b-}", "{:a}") 441 442 refute_diff({:ok, value} = {:error, :fatal}, "{-:ok-, value}", "{+:error+, :fatal}") 443 refute_diff({:a, :b} = :a, "-{:a, :b}-", "+:a+") 444 445 refute_diff({:foo} = {:foo, {:a, :b, :c}}, "{:foo}", "{:foo, +{:a, :b, :c}+}") 446 end 447 448 test "tuples outside of match context" do 449 assert_diff({:a, :b} == {:a, :b}, []) 450 451 refute_diff({:a} == {:a, :b}, "{:a}", "{:a, +:b+}") 452 refute_diff({:a, :b} == {:a}, "{:a, -:b-}", "{:a}") 453 454 refute_diff({:{}, [], [:a]} == {:a}, "{-:{}-, -[]-, -[:a]-}", "{+:a+}") 455 refute_diff({:{}, [], [:a]} == :a, "-{:{}, [], [:a]}-", "+:a+") 456 refute_diff({:a, :b, :c} == {:a, :b, :x}, "{:a, :b, -:c-}", "{:a, :b, +:x+}") 457 458 refute_diff({:foo} == {:foo, {:a, :b, :c}}, "{:foo}", "{:foo, +{:a, :b, :c}+}") 459 refute_diff({:foo, {:a, :b, :c}} == {:foo}, "{:foo, -{:a, :b, :c}-}", "{:foo}") 460 end 461 462 test "maps" do 463 assert_diff(%{a: 1} = %{a: 1}, []) 464 assert_diff(%{a: 1} = %{a: 1, b: 2}, []) 465 assert_diff(%{a: 1, b: 2} = %{a: 1, b: 2}, []) 466 assert_diff(%{b: 2, a: 1} = %{a: 1, b: 2}, []) 467 assert_diff(%{a: 1, b: 2, c: 3} = %{a: 1, b: 2, c: 3}, []) 468 assert_diff(%{c: 3, b: 2, a: 1} = %{a: 1, b: 2, c: 3}, []) 469 470 refute_diff(%{a: 1, b: 2} = %{a: 1}, "%{a: 1, -b: 2-}", "%{a: 1}") 471 refute_diff(%{a: 1, b: 2} = %{a: 1, b: 12}, "%{a: 1, b: 2}", "%{a: 1, b: +1+2}") 472 refute_diff(%{a: 1, b: 2} = %{a: 1, c: 2}, "%{a: 1, -b: 2-}", "%{a: 1, c: 2}") 473 refute_diff(%{a: 1, b: 2, c: 3} = %{a: 1, b: 12}, "%{a: 1, b: 2, -c: 3-}", "%{a: 1, b: +1+2}") 474 refute_diff(%{a: 1, b: 2, c: 3} = %{a: 1, c: 2}, "%{a: 1, c: -3-, -b: 2-}", "%{a: 1, c: +2+}") 475 refute_diff(%{a: 1} = %{a: 2, b: 2, c: 3}, "%{a: -1-}", "%{a: +2+, b: 2, c: 3}") 476 477 refute_diff( 478 %{1 => :a, 2 => :b} = %{1 => :a, 12 => :b}, 479 "%{1 => :a, -2 => :b-}", 480 "%{1 => :a, 12 => :b}" 481 ) 482 483 refute_diff( 484 %{1 => :a, 2 => :b} = %{1 => :a, :b => 2}, 485 "%{1 => :a, -2 => :b-}", 486 "%{1 => :a, :b => 2}" 487 ) 488 489 pins = %{{:a, nil} => :a, {:b, nil} => :b} 490 assert_diff(%{^a => 1} = %{a: 1}, [], pins) 491 assert_diff(%{^a => x} = %{a: 1}, [x: 1], pins) 492 493 refute_diff(%{^a => 1, :a => 2} = %{a: 1}, "%{^a => 1, -:a => 2-}", "%{a: 1}", pins) 494 495 refute_diff( 496 %{^a => x, ^b => x} = %{a: 1, b: 2}, 497 "%{^a => x, ^b => -x-}", 498 "%{a: 1, b: +2+}", 499 pins 500 ) 501 502 refute_diff(%{a: 1} = :a, "-%{a: 1}-", "+:a+") 503 end 504 505 test "maps as pinned map value" do 506 user = %{"id" => 13, "name" => "john"} 507 508 notification = %{ 509 "user" => user, 510 "subtitle" => "foo" 511 } 512 513 assert_diff( 514 %{ 515 "user" => ^user, 516 "subtitle" => "foo" 517 } = notification, 518 [], 519 %{{:user, nil} => user} 520 ) 521 522 refute_diff( 523 %{ 524 "user" => ^user, 525 "subtitle" => "bar" 526 } = notification, 527 ~s|%{"subtitle" => "-bar-", "user" => ^user}|, 528 ~s|%{"subtitle" => "+foo+", "user" => %{"id" => 13, "name" => "john"}}|, 529 %{{:user, nil} => user} 530 ) 531 end 532 533 test "maps outside match context" do 534 assert_diff(%{a: 1} == %{a: 1}, []) 535 assert_diff(%{a: 1, b: 2} == %{a: 1, b: 2}, []) 536 assert_diff(%{b: 2, a: 1} == %{a: 1, b: 2}, []) 537 assert_diff(%{a: 1, b: 2, c: 3} == %{a: 1, b: 2, c: 3}, []) 538 assert_diff(%{c: 3, b: 2, a: 1} == %{a: 1, b: 2, c: 3}, []) 539 540 refute_diff(%{a: 1} == %{a: 1, b: 2}, "%{a: 1}", "%{a: 1, +b: 2+}") 541 refute_diff(%{a: 1, b: 2} == %{a: 1}, "%{a: 1, -b: 2-}", "%{a: 1}") 542 refute_diff(%{a: 1, b: 12} == %{a: 1, b: 2}, "%{a: 1, b: -1-2}", "%{a: 1, b: 2}") 543 refute_diff(%{a: 1, b: 2} == %{a: 1, b: 12}, "%{a: 1, b: 2}", "%{a: 1, b: +1+2}") 544 refute_diff(%{a: 1, b: 2} == %{a: 1, c: 2}, "%{a: 1, -b: 2-}", "%{a: 1, +c: 2+}") 545 end 546 547 test "structs" do 548 assert_diff(%User{age: 16} = %User{age: 16}, []) 549 assert_diff(%{age: 16, __struct__: User} = %User{age: 16}, []) 550 551 refute_diff( 552 %User{age: 16} = %User{age: 21}, 553 "%ExUnit.DiffTest.User{age: 1-6-}", 554 "%ExUnit.DiffTest.User{age: +2+1, name: nil}" 555 ) 556 557 refute_diff( 558 %User{age: 16} = %Person{age: 21}, 559 "%-ExUnit.DiffTest.User-{age: 1-6-}", 560 "%+ExUnit.DiffTest.Person+{age: +2+1}" 561 ) 562 563 refute_diff( 564 %User{age: 16} = %Person{age: 21}, 565 "%-ExUnit.DiffTest.User-{age: 1-6-}", 566 "%+ExUnit.DiffTest.Person+{age: +2+1}" 567 ) 568 569 refute_diff( 570 %User{age: 16} = %{age: 16}, 571 "%-ExUnit.DiffTest.User-{age: 16}", 572 "%{age: 16}" 573 ) 574 575 refute_diff( 576 %User{age: 16} = %{age: 21}, 577 "%-ExUnit.DiffTest.User-{age: 1-6-}", 578 "%{age: +2+1}" 579 ) 580 581 refute_diff( 582 %{age: 16, __struct__: Person} = %User{age: 16}, 583 "%-ExUnit.DiffTest.Person-{age: 16}", 584 "%+ExUnit.DiffTest.User+{age: 16, name: nil}" 585 ) 586 587 pins = %{{:twenty_one, nil} => 21} 588 assert_diff(%User{age: ^twenty_one} = %User{age: 21}, [], pins) 589 assert_diff(%User{age: age} = %User{age: 21}, [age: 21], pins) 590 refute_diff(%User{age: 21} = :a, "-%ExUnit.DiffTest.User{age: 21}-", "+:a+", pins) 591 end 592 593 test "structs outside of match context" do 594 assert_diff(%User{age: 16} == %User{age: 16}, []) 595 assert_diff(%{age: 16, __struct__: User, name: nil} == %User{age: 16}, []) 596 597 refute_diff( 598 %User{age: 16} == %{age: 16}, 599 "%-ExUnit.DiffTest.User-{age: 16, -name: nil-}", 600 "%{age: 16}" 601 ) 602 603 refute_diff( 604 %User{age: 16} == %User{age: 21}, 605 "%ExUnit.DiffTest.User{age: 1-6-, name: nil}", 606 "%ExUnit.DiffTest.User{age: +2+1, name: nil}" 607 ) 608 609 refute_diff( 610 %User{age: 16} == %Person{age: 21}, 611 "%-ExUnit.DiffTest.User-{age: 1-6-, -name: nil-}", 612 "%+ExUnit.DiffTest.Person+{age: +2+1}" 613 ) 614 end 615 616 test "structs with inspect" do 617 refute_diff( 618 ~D[2017-10-01] = ~D[2017-10-02], 619 ~s/-~D[2017-10-01]-/, 620 "~D[2017-10-0+2+]" 621 ) 622 623 refute_diff( 624 "2017-10-01" = ~D[2017-10-02], 625 ~s/-"2017-10-01"-/, 626 "+~D[2017-10-02]+" 627 ) 628 629 refute_diff( 630 ~D[2017-10-02] = "2017-10-01", 631 ~s/-~D[2017-10-02]-/, 632 ~s/+"2017-10-01"+/ 633 ) 634 end 635 636 test "structs with missing keys on match" do 637 struct = %User{ 638 age: ~U[2020-07-30 13:49:59.253158Z] 639 } 640 641 assert_diff(%User{age: %DateTime{}} = struct, []) 642 643 refute_diff( 644 %User{age: %Date{}} = struct, 645 ~s/%ExUnit.DiffTest.User{age: %-Date-{}}/, 646 ~s/%ExUnit.DiffTest.User{age: %+DateTime+{calendar: Calendar.ISO, day: 30, hour: 13, microsecond: {253158, 6}, minute: 49, month: 7, second: 59, std_offset: 0, time_zone: "Etc\/UTC", utc_offset: 0, year: 2020, zone_abbr: "UTC"}, name: nil}/ 647 ) 648 649 refute_diff( 650 %{age: %Date{}} = struct, 651 ~s/%{age: %-Date-{}}/, 652 ~s/%ExUnit.DiffTest.User{age: %+DateTime+{calendar: Calendar.ISO, day: 30, hour: 13, microsecond: {253158, 6}, minute: 49, month: 7, second: 59, std_offset: 0, time_zone: "Etc\/UTC", utc_offset: 0, year: 2020, zone_abbr: "UTC"}, name: nil}/ 653 ) 654 end 655 656 test "structs with inspect outside match context" do 657 refute_diff( 658 ~D[2017-10-01] == ~D[2017-10-02], 659 "~D[2017-10-0-1-]", 660 "~D[2017-10-0+2+]" 661 ) 662 663 refute_diff( 664 "2017-10-01" == ~D[2017-10-02], 665 ~s/-"2017-10-01"-/, 666 "+~D[2017-10-02]+" 667 ) 668 669 refute_diff( 670 ~D[2017-10-02] == "2017-10-01", 671 ~s/-~D[2017-10-02]-/, 672 ~s/+"2017-10-01"+/ 673 ) 674 end 675 676 test "structs with same inspect but different inside match" do 677 refute_diff( 678 %Opaque{data: 1} = %Opaque{data: 2}, 679 "%ExUnit.DiffTest.Opaque{data: -1-}", 680 "%ExUnit.DiffTest.Opaque{data: +2+}" 681 ) 682 683 refute_diff( 684 %Opaque{data: %{hello: :world}} = %Opaque{data: %{hello: "world"}}, 685 "#Opaque<data: %{hello: -:-world}>", 686 "#Opaque<data: %{hello: +\"+world+\"+}>" 687 ) 688 end 689 690 test "structs with same inspect but different outside match" do 691 refute_diff( 692 %Opaque{data: 1} == %Opaque{data: 2}, 693 "%ExUnit.DiffTest.Opaque{data: -1-}", 694 "%ExUnit.DiffTest.Opaque{data: +2+}" 695 ) 696 697 refute_diff( 698 %Opaque{data: %{hello: :world}} == %Opaque{data: %{hello: "world"}}, 699 "#Opaque<data: %{hello: -:-world}>", 700 "#Opaque<data: %{hello: +\"+world+\"+}>" 701 ) 702 end 703 704 test "structs with inspect in a list" do 705 refute_diff( 706 Enum.sort([~D[2019-03-31], ~D[2019-04-01]]) == [~D[2019-03-31], ~D[2019-04-01]], 707 "[-~D[2019-04-01]-, ~D[2019-03-31]]", 708 "[~D[2019-03-31], +~D[2019-04-01]+]" 709 ) 710 end 711 712 test "structs with matched type" do 713 pins = %{{:type, nil} => User, {:age, nil} => 33} 714 715 # pin on __struct__ 716 assert_diff( 717 %{__struct__: ^type, age: ^age, name: "john"} = %User{name: "john", age: 33}, 718 [], 719 pins 720 ) 721 722 refute_diff( 723 %{__struct__: ^type, age: ^age, name: "john"} = %User{name: "jane", age: 33}, 724 "%{__struct__: ^type, age: ^age, name: \"j-oh-n\"}", 725 "%ExUnit.DiffTest.User{age: 33, name: \"j+a+n+e+\"}", 726 pins 727 ) 728 729 refute_diff( 730 %{__struct__: ^type, age: ^age, name: "john"} = %User{name: "john", age: 35}, 731 "%{__struct__: ^type, age: -^age-, name: \"john\"}", 732 "%ExUnit.DiffTest.User{age: 3+5+, name: \"john\"}", 733 pins 734 ) 735 736 refute_diff( 737 %{__struct__: ^type, age: ^age, name: "john"} = ~D[2020-01-01], 738 "%{__struct__: -^type-, -age: ^age-, -name: \"john\"-}", 739 "%+Date+{calendar: Calendar.ISO, day: 1, month: 1, year: 2020}", 740 pins 741 ) 742 743 # pin on % 744 assert_diff( 745 %^type{age: ^age, name: "john"} = %User{name: "john", age: 33}, 746 [], 747 pins 748 ) 749 750 refute_diff( 751 %^type{age: ^age, name: "john"} = %User{name: "jane", age: 33}, 752 "%{__struct__: ^type, age: ^age, name: \"j-oh-n\"}", 753 "%ExUnit.DiffTest.User{age: 33, name: \"j+a+n+e+\"}", 754 pins 755 ) 756 757 refute_diff( 758 %^type{age: ^age, name: "john"} = %User{name: "john", age: 35}, 759 "%{__struct__: ^type, age: -^age-, name: \"john\"}", 760 "%ExUnit.DiffTest.User{age: 3+5+, name: \"john\"}", 761 pins 762 ) 763 764 refute_diff( 765 %^type{age: ^age, name: "john"} = ~D[2020-01-01], 766 "%{__struct__: -^type-, -age: ^age-, -name: \"john\"-}", 767 "%+Date+{calendar: Calendar.ISO, day: 1, month: 1, year: 2020}", 768 pins 769 ) 770 end 771 772 test "invalid structs" do 773 refute_diff( 774 %{__struct__: Unknown} = %{}, 775 "%{-__struct__: Unknown-}", 776 "%{}" 777 ) 778 779 refute_diff( 780 %{__struct__: Date, unknown: :field} = %{}, 781 "%{-__struct__: Date-, -unknown: :field-}", 782 "%{}" 783 ) 784 end 785 786 test "maps and structs with escaped values" do 787 refute_diff( 788 %User{age: {1, 2, 3}} = %User{age: {1, 2, 4}}, 789 "%ExUnit.DiffTest.User{age: {1, 2, -3-}}", 790 "%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}" 791 ) 792 793 refute_diff( 794 %User{age: {1, 2, 3}, name: name} = %User{age: {1, 2, 4}}, 795 "%ExUnit.DiffTest.User{age: {1, 2, -3-}, name: name}", 796 "%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}" 797 ) 798 799 refute_diff( 800 %User{name: :foo} = %User{name: :bar, age: {1, 2, 3}}, 801 "%ExUnit.DiffTest.User{name: -:foo-}", 802 "%ExUnit.DiffTest.User{name: +:bar+, age: {1, 2, 3}}" 803 ) 804 805 refute_diff( 806 %User{age: {1, 2, 3}} == %User{age: {1, 2, 4}}, 807 "%ExUnit.DiffTest.User{age: {1, 2, -3-}, name: nil}", 808 "%ExUnit.DiffTest.User{age: {1, 2, +4+}, name: nil}" 809 ) 810 811 refute_diff( 812 %User{age: {1, 2, 4}} == %User{age: {1, 2, 3}}, 813 "%ExUnit.DiffTest.User{age: {1, 2, -4-}, name: nil}", 814 "%ExUnit.DiffTest.User{age: {1, 2, +3+}, name: nil}" 815 ) 816 817 refute_diff( 818 %{name: :foo} == %{name: :foo, age: {1, 2, 3}}, 819 "%{name: :foo}", 820 "%{name: :foo, +age: {1, 2, 3}+}" 821 ) 822 823 refute_diff( 824 %{name: :foo, age: {1, 2, 3}} == %{name: :foo}, 825 "%{name: :foo, -age: {1, 2, 3}-}", 826 "%{name: :foo}" 827 ) 828 end 829 830 test "strings" do 831 assert_diff("" = "", []) 832 assert_diff("fox hops over the dog" = "fox hops over the dog", []) 833 834 refute_diff("fox" = "foo", "fo-x-", "fo+o+") 835 836 refute_diff( 837 "fox hops over \"the dog" = "fox jumps over the lazy cat", 838 ~s/"fox -ho-ps over -\\\"-the -dog-"/, 839 ~s/"fox + jum+ps over the + lazy cat+"/ 840 ) 841 842 refute_diff( 843 "short" = "really long string that should not emit diff against short", 844 ~s/"-short-"/, 845 ~s/"+really long string that should not emit diff against short+"/ 846 ) 847 848 refute_diff("foo" = :a, ~s/-"foo"-/, "+:a+") 849 end 850 851 test "strings outside match context" do 852 assert_diff("" == "", []) 853 assert_diff("fox hops over the dog" == "fox hops over the dog", []) 854 refute_diff("fox" == "foo", "fo-x-", "fo+o+") 855 856 refute_diff( 857 "{\"foo\":1,\"barbaz\":[1,2,3]}" == "4", 858 ~s/"-{\\\"foo\\\":1,\\\"barbaz\\\":[1,2,3]}-"/, 859 ~s/"+4+"/ 860 ) 861 end 862 863 test "concat binaries" do 864 assert_diff("fox hops" <> " over the dog" = "fox hops over the dog", []) 865 assert_diff("fox hops " <> "over " <> "the dog" = "fox hops over the dog", []) 866 867 refute_diff( 868 "fox hops" <> " under the dog" = "fox hops over the dog", 869 ~s/"fox hops" <> " -und-er the dog"/, 870 ~s/"fox hops +ov+er the dog"/ 871 ) 872 873 refute_diff( 874 "fox hops over" <> " the dog" = "fox hops over", 875 ~s/"fox hops over" <> "- the dog-"/, 876 ~s/"fox hops over"/ 877 ) 878 879 refute_diff( 880 "fox hops" <> " over the dog" = "fox", 881 ~s/"-fox hops-" <> "- over the dog-"/, 882 ~s/"+fox+"/ 883 ) 884 885 refute_diff( 886 "fox" <> " hops" = "fox h", 887 ~s/"fox" <> " h-ops-"/, 888 ~s/"fox h"/ 889 ) 890 891 refute_diff( 892 "fox hops " <> "hover " <> "the dog" = "fox hops over the dog", 893 ~s/"fox hops " <> "-h-over " <> "the dog"/, 894 ~s/"fox hops over the dog"/ 895 ) 896 897 refute_diff("fox" <> " hops" = :a, ~s/-"fox" <> " hops"-/, "+:a+") 898 end 899 900 test "concat binaries with pin" do 901 pins = %{{:x, nil} => " over the dog"} 902 903 assert_diff("fox hops" <> x = "fox hops over the dog", x: " over the dog") 904 assert_diff("fox hops " <> "over " <> x = "fox hops over the dog", x: "the dog") 905 assert_diff("fox hops" <> ^x = "fox hops over the dog", [], pins) 906 907 refute_diff( 908 "fox hops " <> "hover " <> x = "fox hops over the dog", 909 ~s/"fox hops " <> "-h-over " <> x/, 910 ~s/"fox hops over +t+he dog"/ 911 ) 912 913 refute_diff( 914 "fox hops " <> "hover " <> ^x = "fox hops over the dog", 915 ~s/"fox hops " <> "-h-over " <> -^x-/, 916 ~s/"fox hops over +t+he dog"/, 917 pins 918 ) 919 end 920 921 test "concat binaries with specifiers" do 922 input = "foobar" 923 924 refute_diff( 925 <<trap::binary-size(3)>> <> "baz" = input, 926 "-<<trap::binary-size(3)>> <> \"baz\"-", 927 "+\"foobar\"+" 928 ) 929 end 930 931 test "underscore" do 932 assert_diff(_ = :a, []) 933 assert_diff({_, _} = {:a, :b}, []) 934 935 refute_diff({_, :a} = {:b, :b}, "{_, -:a-}", "{:b, +:b+}") 936 end 937 938 test "macros" do 939 assert_diff(one() = 1, []) 940 assert_diff(tuple(x, x) = {1, 1}, x: 1) 941 942 refute_diff(one() = 2, "-one()-", "+2+") 943 refute_diff(tuple(x, x) = {1, 2}, "-tuple(x, x)-", "{1, +2+}") 944 945 pins = %{{:x, nil} => 1} 946 assert_diff(pin_x() = 1, [], pins) 947 refute_diff(pin_x() = 2, "-pin_x()-", "+2+", pins) 948 end 949 950 test "guards" do 951 assert_diff((x when x == 0) = 0, x: 0) 952 assert_diff((x when x == 0 and is_integer(x)) = 0, x: 0) 953 assert_diff((x when x == 0 or x == 1) = 0, x: 0) 954 assert_diff((x when x == 0 when x == 1) = 0, x: 0) 955 assert_diff((x when one() == 1) = 0, x: 0) 956 957 refute_diff((x when x == 1) = 0, "x when -x == 1-", "0") 958 refute_diff((x when x == 0 and x == 1) = 0, "x when x == 0 and -x == 1-", "0") 959 refute_diff((x when x == 1 and x == 2) = 0, "x when -x == 1- and -x == 2-", "0") 960 refute_diff((x when x == 1 or x == 2) = 0, "x when -x == 1- or -x == 2-", "0") 961 refute_diff((x when x == 1 when x == 2) = 0, "x when -x == 1- when -x == 2-", "0") 962 refute_diff((x when x in [1, 2]) = 0, "x when -x in [1, 2]-", "0") 963 refute_diff(({:ok, x} when x == 1) = :error, "-{:ok, x}- when x == 1", "+:error+") 964 end 965 966 test "charlists" do 967 refute_diff( 968 'fox hops over \'the dog' = 'fox jumps over the lazy cat', 969 "'fox -ho-ps over -\\'-the -dog-'", 970 "'fox +jum+ps over the +lazy cat+'" 971 ) 972 973 refute_diff({[], :ok} = {[], [], :ok}, "{[], -:ok-}", "{[], +[]+, +:ok+}") 974 refute_diff({[], :ok} = {'foo', [], :ok}, "{'--', -:ok-}", "{'+foo+', +[]+, +:ok+}") 975 refute_diff({'foo', :ok} = {[], [], :ok}, "{'-foo-', -:ok-}", "{'++', +[]+, +:ok+}") 976 refute_diff({'foo', :ok} = {'bar', [], :ok}, "{'-foo-', -:ok-}", "{'+bar+', +[]+, +:ok+}") 977 end 978 979 test "refs" do 980 ref1 = make_ref() 981 ref2 = make_ref() 982 983 inspect_ref1 = inspect(ref1) 984 inspect_ref2 = inspect(ref2) 985 986 assert_diff(ref1 == ref1, []) 987 assert_diff({ref1, ref2} == {ref1, ref2}, []) 988 989 refute_diff(ref1 == ref2, "-#{inspect_ref1}-", "+#{inspect_ref2}+") 990 991 refute_diff( 992 {ref1, ref2} == {ref2, ref1}, 993 "{-#{inspect_ref1}-, -#{inspect_ref2}-}", 994 "{+#{inspect_ref2}+, +#{inspect_ref1}+}" 995 ) 996 997 refute_diff( 998 {ref1, ref2} == ref1, 999 "-{#{inspect_ref1}, #{inspect_ref2}}-", 1000 "+#{inspect_ref1}+" 1001 ) 1002 1003 refute_diff( 1004 ref1 == {ref1, ref2}, 1005 "-#{inspect_ref1}-", 1006 "+{#{inspect_ref1}, #{inspect_ref2}}+" 1007 ) 1008 1009 refute_diff(ref1 == :a, "-#{inspect_ref1}-", "+:a+") 1010 refute_diff({ref1, ref2} == :a, "-{#{inspect_ref1}, #{inspect_ref2}}", "+:a+") 1011 refute_diff(%{ref1 => ref2} == :a, "-%{#{inspect_ref1} => #{inspect_ref2}}", "+:a+") 1012 1013 refute_diff( 1014 %Opaque{data: ref1} == :a, 1015 "-#Opaque<???>-", 1016 "+:a+" 1017 ) 1018 end 1019 1020 test "pids" do 1021 pid = self() 1022 inspect_pid = inspect(pid) 1023 1024 assert_diff(pid == pid, []) 1025 assert_diff({pid, pid} == {pid, pid}, []) 1026 1027 refute_diff(pid == :a, "-#{inspect_pid}-", "+:a+") 1028 refute_diff({pid, pid} == :a, "-{#{inspect_pid}, #{inspect_pid}}", "+:a+") 1029 1030 refute_diff({pid, :a} == {:a, pid}, "{-#{inspect_pid}-, -:a-}", "{+:a+, +#{inspect_pid}+}") 1031 refute_diff(%{pid => pid} == :a, "-%{#{inspect_pid} => #{inspect_pid}}", "+:a+") 1032 1033 refute_diff( 1034 %Opaque{data: pid} == :a, 1035 "-#Opaque<???>-", 1036 "+:a+" 1037 ) 1038 end 1039 1040 test "functions" do 1041 identity = & &1 1042 inspect = inspect(identity) 1043 1044 assert_diff(identity == identity, []) 1045 assert_diff({identity, identity} == {identity, identity}, []) 1046 1047 refute_diff(identity == :a, "-#{inspect}-", "+:a+") 1048 refute_diff({identity, identity} == :a, "-{#{inspect}, #{inspect}}", "+:a+") 1049 1050 refute_diff({identity, :a} == {:a, identity}, "{-#{inspect}-, -:a-}", "{+:a+, +#{inspect}+}") 1051 1052 refute_diff(%{identity => identity} == :a, "-%{#{inspect} => #{inspect}}", "+:a+") 1053 1054 refute_diff( 1055 %Opaque{data: identity} == :a, 1056 "-#Opaque<???>-", 1057 "+:a+" 1058 ) 1059 end 1060 1061 test "not supported" do 1062 refute_diff( 1063 <<147, 1, 2, 31>> = <<193, 1, 31>>, 1064 "-<<147, 1, 2, 31>>-", 1065 "+<<193, 1, 31>>+" 1066 ) 1067 end 1068end 1069