-
Notifications
You must be signed in to change notification settings - Fork 4
/
MemberRestrictionTest.js
230 lines (193 loc) · 6.48 KB
/
MemberRestrictionTest.js
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**
* Tests class builder member restrictions
*
* Copyright (C) 2014 Mike Gerwitz
*
* This file is part of GNU ease.js.
*
* ease.js is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
require( 'common' ).testCase(
{
caseSetUp: function()
{
this.Class = this.require( 'class' );
this.Sut = this.require( 'ClassBuilder' );
},
setUp: function()
{
this.builder = this.Sut(
this.require( 'MemberBuilder' )(),
this.require( 'VisibilityObjectFactoryFactory' )
.fromEnvironment()
);
},
/**
* It's always useful to be able to quickly reference a list of reserved
* members so that an implementer can programatically handle runtime
* cases. It's also useful for testing.
*/
'Can retrieve a list of reserved members': function()
{
var reserved = this.Sut.getReservedMembers();
this.assertOk( reserved instanceof Object,
"Can retrieve hash of reserved members"
);
},
/**
* Ability to alter the reserved members list would permit implementors
* to break compatibility with libraries that use the reserved members
* being added. Furthermore, it could add unintended consequences if a
* reserved member were removed from the list and used. To put it
* simply, it could cause complete and utter chaos. As such, no. No, no,
* no.
*
* It is of course true that future versions of ease.js could add
* additional reserved members, which is why one should never prefix
* their variables in the same manner ease.js does for reserved members.
* But let's leave that to ease.js, shall we?
*/
'Cannot modify internal reserved members list': function()
{
var val = 'foo';
// attempt to add to list
this.Sut.getReservedMembers().foo = val;
this.assertNotEqual(
this.Sut.getReservedMembers().foo,
val,
"Cannot alter internal list of reserved members"
);
},
/**
* This test is to ensure that nobody (a) removes reserved members
* without understanding the consequences or (b) adds reserved members
* without properly documenting them.
*/
'Proper members are reserved': function()
{
var chk = [ '__initProps', 'constructor' ],
i = chk.length,
reserved = this.Sut.getReservedMembers();
while ( i-- )
{
var cur = chk[ i ];
this.assertOk( reserved.hasOwnProperty( cur ),
"Member '" + cur + "' should be reserved"
);
delete reserved[ cur ];
}
// ensure there are no others that we didn't expect
for ( var name in reserved )
{
this.assertFail( "Untested reserved member found: " + name );
}
},
/**
* Ensure that each of the reserved members will throw an exception if
* they are used.
*/
'All reserved members are actually reserved': function()
{
var _self = this,
reserved = this.Sut.getReservedMembers(),
count = 0;
// test each of the reserved members
for ( var name in reserved )
{
// properties
this.assertThrows(
function()
{
var obj = {};
obj[ name ] = '';
_self.Class( obj );
},
Error,
"Reserved members cannot be used in class definitions as " +
"properties"
);
// methods
this.assertThrows(
function()
{
var obj = {};
obj[ name ] = function() {};
_self.Class( obj );
},
Error,
"Reserved members cannot be used in class definitions as " +
"methods"
);
count++;
}
// ensure we weren't provided an empty object
this.assertNotEqual( count, 0,
"Reserved memebers were tested"
);
},
/**
* We want these available for the same reason that we want the
* restricted members available (see above)
*/
'Can retrieve list of forced public methods': function()
{
var pub = this.Sut.getForcedPublicMethods(),
count = 0;
this.assertOk( pub instanceof Object,
"Can retrieve hash of forced-public methods"
);
for ( var name in pub )
{
count++;
}
// ensure we weren't provided an empty object
this.assertNotEqual( count, 0,
"Forced-public method list is not empty"
);
},
/**
* See above. Same reason that we don't want reserved members to be
* modified.
*/
'Cannot modify internal forced public methods list': function()
{
var val = 'foo';
// attempt to add to list
this.Sut.getForcedPublicMethods().foo = val;
this.assertNotEqual(
this.Sut.getForcedPublicMethods().foo,
val,
"Cannot alter internal list of forced-public methods"
);
},
/**
* Ensure that an exception will be thrown for each forced-public method
* that is not declared as public in the class definition.
*/
'All forced public methods are forced to public': function()
{
var _self = this,
pub = this.Sut.getForcedPublicMethods();
// test each of the reserved members
for ( var name in pub )
{
this.assertThrows( function()
{
var obj = {};
obj[ 'private ' + name ] = function() {};
_self.Class( obj );
}, Error, "Forced-public methods must be declared as public" );
}
},
} );