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
|