summaryrefslogtreecommitdiff
path: root/spec/ruby/core/module/const_defined_spec.rb
blob: 027cf5a245a55037c68e5b734ff012b0f518e985 (plain)
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
156
157
158
159
160
161
162
163
164
165
166
167
# encoding: utf-8

require_relative '../../spec_helper'
require_relative '../../fixtures/constants'
require_relative 'fixtures/constant_unicode'

describe "Module#const_defined?" do
  it "returns true if the given Symbol names a constant defined in the receiver" do
    ConstantSpecs.const_defined?(:CS_CONST2).should == true
    ConstantSpecs.const_defined?(:ModuleA).should == true
    ConstantSpecs.const_defined?(:ClassA).should == true
    ConstantSpecs::ContainerA.const_defined?(:ChildA).should == true
  end

  it "returns true if the constant is defined in the receiver's superclass" do
    # CS_CONST4 is defined in the superclass of ChildA
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true
  end

  it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do
    # CS_CONST10 is defined in a module included by ChildA
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true
  end

  it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do
    # CS_CONST11 is defined in the module included by ContainerPrepend
    ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true
  end

  it "returns true if the constant is defined in Object and the receiver is a module" do
    # CS_CONST1 is defined in Object
    ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true
  end

  it "returns true if the constant is defined in Object and the receiver is a class that has Object among its ancestors" do
    # CS_CONST1 is defined in Object
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST1).should be_true
  end

  it "returns false if the constant is defined in the receiver's superclass and the inherit flag is false" do
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, false).should be_false
  end

  it "returns true if the constant is defined in the receiver's superclass and the inherit flag is true" do
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, true).should be_true
  end

  it "coerces the inherit flag to a boolean" do
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, nil).should be_false
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4, :true).should be_true
  end

  it "returns true if the given String names a constant defined in the receiver" do
    ConstantSpecs.const_defined?("CS_CONST2").should == true
    ConstantSpecs.const_defined?("ModuleA").should == true
    ConstantSpecs.const_defined?("ClassA").should == true
    ConstantSpecs::ContainerA.const_defined?("ChildA").should == true
  end

  it "returns true when passed a constant name with unicode characters" do
    ConstantUnicodeSpecs.const_defined?("CS_CONSTλ").should be_true
  end

  it "returns true when passed a constant name with EUC-JP characters" do
    str = "CS_CONSTλ".encode("euc-jp")
    ConstantSpecs.const_set str, 1
    ConstantSpecs.const_defined?(str).should be_true
  end

  it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do
    # The following constant isn't defined at all.
    ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4726).should be_false
    # DETACHED_CONSTANT is defined in ConstantSpecs::Detached, which isn't
    # included by or inherited from ParentA
    ConstantSpecs::ParentA.const_defined?(:DETACHED_CONSTANT).should be_false
  end

  it "does not call #const_missing if the constant is not defined in the receiver" do
    ConstantSpecs::ClassA.should_not_receive(:const_missing)
    ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false
  end

  describe "converts the given name to a String using #to_str" do
    it "calls #to_str to convert the given name to a String" do
      name = mock("ClassA")
      name.should_receive(:to_str).and_return("ClassA")
      ConstantSpecs.const_defined?(name).should == true
    end

    it "raises a TypeError if the given name can't be converted to a String" do
      -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError)
      -> { ConstantSpecs.const_defined?([])  }.should raise_error(TypeError)
    end

    it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
      name = mock("classA")
      name.should_receive(:to_str).and_raise(NoMethodError)
      -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError)
    end
  end

  it "special cases Object and checks it's included Modules" do
    Object.const_defined?(:CS_CONST10).should be_true
  end

  it "returns true for toplevel constant when the name begins with '::'" do
    ConstantSpecs.const_defined?("::Array").should be_true
  end

  it "returns true when passed a scoped constant name" do
    ConstantSpecs.const_defined?("ClassC::CS_CONST1").should be_true
  end

  it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is default" do
    ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2").should be_true
  end

  it "returns true when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is true" do
    ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", true).should be_true
  end

  it "returns false when passed a scoped constant name for a constant in the inheritance hierarchy and the inherited flag is false" do
    ConstantSpecs::ClassD.const_defined?("ClassE::CS_CONST2", false).should be_false
  end

  it "returns false when the name begins with '::' and the toplevel constant does not exist" do
    ConstantSpecs.const_defined?("::Name").should be_false
  end

  it "raises a NameError if the name does not start with a capital letter" do
    -> { ConstantSpecs.const_defined? "name" }.should raise_error(NameError)
  end

  it "raises a NameError if the name starts with '_'" do
    -> { ConstantSpecs.const_defined? "__CONSTX__" }.should raise_error(NameError)
  end

  it "raises a NameError if the name starts with '@'" do
    -> { ConstantSpecs.const_defined? "@Name" }.should raise_error(NameError)
  end

  it "raises a NameError if the name starts with '!'" do
    -> { ConstantSpecs.const_defined? "!Name" }.should raise_error(NameError)
  end

  it "returns true or false for the nested name" do
    ConstantSpecs.const_defined?("NotExist::Name").should == false
    ConstantSpecs.const_defined?("::Name").should == false
    ConstantSpecs.const_defined?("::Object").should == true
    ConstantSpecs.const_defined?("ClassA::CS_CONST10").should == true
    ConstantSpecs.const_defined?("ClassA::CS_CONST10_").should == false
  end

  it "raises a NameError if the name contains non-alphabetic characters except '_'" do
    ConstantSpecs.const_defined?("CS_CONSTX").should == false
    -> { ConstantSpecs.const_defined? "Name=" }.should raise_error(NameError)
    -> { ConstantSpecs.const_defined? "Name?" }.should raise_error(NameError)
  end

  it "raises a TypeError if conversion to a String by calling #to_str fails" do
    name = mock('123')
    -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)

    name.should_receive(:to_str).and_return(123)
    -> { ConstantSpecs.const_defined? name }.should raise_error(TypeError)
  end
end