File: test_cref_map.rb

package info (click to toggle)
ruby-zeitwerk 2.7.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 732 kB
  • sloc: ruby: 6,240; makefile: 4
file content (155 lines) | stat: -rw-r--r-- 3,794 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# frozen_string_literal: true

require "test_helper"

class TestCrefMap < Minitest::Test
  def setup
    @map = Zeitwerk::Cref::Map.new

    @m = Module.new
    @cref_mx = Zeitwerk::Cref.new(@m, :X)
    @cref_my = Zeitwerk::Cref.new(@m, :Y)

    @n = Module.new
    @cref_nx = Zeitwerk::Cref.new(@n, :X)
    @cref_ny = Zeitwerk::Cref.new(@n, :Y)
  end

  def initialize_map
    @map[@cref_mx] = "mx"
    @map[@cref_my] = "my"
    @map[@cref_nx] = "nx"
    @map[@cref_ny] = "ny"
  end

  test "initially empty" do
    assert @map.empty?
  end

  test "[]= sets a value, [] reads it back" do
    initialize_map

    assert_equal "mx", @map[@cref_mx]
    assert_equal "my", @map[@cref_my]
    assert_equal "nx", @map[@cref_nx]
    assert_equal "ny", @map[@cref_ny]
  end

  test "[] returns nil if the value does not exist" do
    assert_nil @map[@cref_mx]
  end

  test "get_or_set returns the value if the key exists" do
    @map[@cref_mx] = "mx"

    assert_equal "mx", @map.get_or_set(@cref_mx) { "not-mx" }
  end

  test "get_or_set sets the value if the key does not exist" do
    assert_same false, @map.get_or_set(@cref_mx) { false }
    assert_same false, @map[@cref_mx]
  end

  test "delete removes and returns an existing value" do
    initialize_map

    assert_equal "mx", @map.delete(@cref_mx)
    assert_nil @map[@cref_mx]
    assert_equal "my", @map.delete(@cref_my)
    assert_nil @map[@cref_my]
    assert_equal "nx", @map.delete(@cref_nx)
    assert_nil @map[@cref_nx]
    assert_equal "ny", @map.delete(@cref_ny)
    assert_nil @map[@cref_ny]

    assert @map.empty?
  end

  test "delete returns nil if the cref is not present" do
    @map[@cref_mx] = "mx"

    assert_nil @map.delete(@cref_my)
    assert_nil @map.delete(@cref_nx)
  end

  test "delete_mod_cname removes and returns an existing value" do
    @map[@cref_mx] = "mx"

    assert_equal "mx", @map.delete_mod_cname(@m, :X)
    assert @map.empty?
  end

  test "delete_mod_cname returns nil if the cref is not present" do
    assert_nil @map.delete_mod_cname(@m, :X)
  end

  test "delete_by_value removes all cnames with the given value" do
    @map[@cref_mx] = 0
    @map[@cref_my] = 1
    @map[@cref_nx] = 0
    @map[@cref_ny] = 1

    @map.delete_by_value(0)

    assert_nil @map[@cref_mx]
    assert_equal 1, @map[@cref_my]
    assert_nil @map[@cref_nx]
    assert_equal 1, @map[@cref_ny]
  end

  test "each_key does not yield if the map is empty" do
    yielded = false
    @map.each_key { yielded = true }
    assert !yielded
  end

  test "each_key yields all keys in an undefined order" do
    initialize_map

    keys = []
    @map.each_key { |key| keys << [key.mod, key.cname] }

    assert_equal 4, keys.size

    assert keys.include?([@m, :X])
    assert keys.include?([@m, :Y])
    assert keys.include?([@n, :X])
    assert keys.include?([@n, :Y])
  end

  test "clear empties the map" do
    initialize_map

    @map.clear
    assert @map.empty?
  end

  # See https://github.com/fxn/zeitwerk/issues/188.
  test "the map is robust to hash overrides" do
    # This module is not hashable because the `hash` method has been overridden
    # to mean something else. In particular, it has even a different arity.
    m = Module.new do
      def self.hash(_) = nil
    end

    assert_raises(ArgumentError, 'wrong number of arguments (given 0, expected 1)') do
      { m => 0 }
    end

    n = Module.new do
      def self.hash(_) = nil
    end

    # This map is designed to be able to use class and module objects as keys
    # even if they are not technically hashable.
    map = Zeitwerk::Cref::Map.new
    cref_m = Zeitwerk::Cref.new(m, :X)
    cref_n = Zeitwerk::Cref.new(n, :X)

    map[cref_m] = 0
    map[cref_n] = 1

    assert_equal 0, map[cref_m]
    assert_equal 1, map[cref_n]
  end
end