55 * MIT Licensed
66 */
77
8- import { format , formatProp , convertPropertyName , length } from '../util' ;
8+ import { convertPropertyName , hasOwnProperty } from '../util' ;
9+ import { formatProp } from '../format' ;
10+ import { isEmpty , has as hasKey , get as getValue , size } from '../iterator' ;
911import eql from 'should-equal' ;
1012
1113var aSlice = Array . prototype . slice ;
1214
1315export default function ( should , Assertion ) {
14- var i = format ;
16+ var i = should . format ;
1517 /**
1618 * Asserts given object has some descriptor. **On success it change given object to be value of property**.
1719 *
@@ -227,8 +229,6 @@ export default function(should, Assertion) {
227229
228230 Assertion . alias ( 'length' , 'lengthOf' ) ;
229231
230- var hasOwnProperty = Object . prototype . hasOwnProperty ;
231-
232232 /**
233233 * Asserts given object has own property. **On success it change given object to be value of property**.
234234 *
@@ -250,7 +250,7 @@ export default function(should, Assertion) {
250250 message : description
251251 } ;
252252
253- this . assert ( hasOwnProperty . call ( this . obj , name ) ) ;
253+ this . assert ( hasOwnProperty ( this . obj , name ) ) ;
254254
255255 this . obj = this . obj [ name ] ;
256256 } ) ;
@@ -271,15 +271,7 @@ export default function(should, Assertion) {
271271 */
272272 Assertion . add ( 'empty' , function ( ) {
273273 this . params = { operator : 'to be empty' } ;
274-
275- if ( length ( this . obj ) !== void 0 ) {
276- should ( this . obj ) . have . property ( 'length' , 0 ) ;
277- } else {
278- var obj = Object ( this . obj ) ; // wrap to reference for booleans and numbers
279- for ( var prop in obj ) {
280- should ( this . obj ) . not . have . ownProperty ( prop ) ;
281- }
282- }
274+ this . assert ( isEmpty ( this . obj ) ) ;
283275 } , true ) ;
284276
285277 /**
@@ -289,60 +281,47 @@ export default function(should, Assertion) {
289281 * @alias Assertion#key
290282 * @memberOf Assertion
291283 * @category assertion property
292- * @param {Array| ...string } [keys] Keys to check
284+ * @param {...* } [keys] Keys to check
293285 * @example
294286 *
295287 * ({ a: 10 }).should.have.keys('a');
296288 * ({ a: 10, b: 20 }).should.have.keys('a', 'b');
297- * ({ a: 10, b: 20 }).should.have.keys([ 'a', 'b' ]);
298- * ({}).should.have.keys();
289+ * (new Map([[1, 2]])).should.have.key(1);
299290 */
300291 Assertion . add ( 'keys' , function ( keys ) {
301- if ( arguments . length > 1 ) {
302- keys = aSlice . call ( arguments ) ;
303- } else if ( arguments . length === 1 && typeof keys === 'string' ) {
304- keys = [ keys ] ;
305- } else if ( arguments . length === 0 ) {
306- keys = [ ] ;
307- }
308-
309- keys = keys . map ( String ) ;
292+ keys = aSlice . call ( arguments ) ;
310293
311294 var obj = Object ( this . obj ) ;
312295
313296 // first check if some keys are missing
314- var missingKeys = [ ] ;
315- keys . forEach ( function ( key ) {
316- if ( ! hasOwnProperty . call ( this . obj , key ) ) {
317- missingKeys . push ( formatProp ( key ) ) ;
318- }
319- } , this ) ;
320-
321- // second check for extra keys
322- var extraKeys = [ ] ;
323- Object . keys ( obj ) . forEach ( function ( key ) {
324- if ( keys . indexOf ( key ) < 0 ) {
325- extraKeys . push ( formatProp ( key ) ) ;
326- }
297+ var missingKeys = keys . filter ( function ( key ) {
298+ return ! hasKey ( obj , key ) ;
327299 } ) ;
328300
329- var verb = keys . length === 0 ? 'to be empty' :
330- 'to have ' + ( keys . length === 1 ? 'key ' : 'keys ' ) ;
301+ var verb = 'to have ' + ( keys . length === 1 ? 'key ' : 'keys ' ) ;
331302
332- this . params = { operator : verb + keys . map ( formatProp ) . join ( ', ' ) } ;
303+ this . params = { operator : verb + keys . join ( ', ' ) } ;
333304
334305 if ( missingKeys . length > 0 ) {
335306 this . params . operator += '\n\tmissing keys: ' + missingKeys . join ( ', ' ) ;
336307 }
337308
338- if ( extraKeys . length > 0 ) {
339- this . params . operator += '\n\textra keys: ' + extraKeys . join ( ', ' ) ;
340- }
309+ this . assert ( missingKeys . length === 0 ) ;
310+ } ) ;
311+
312+ Assertion . add ( 'key' , function ( key ) {
313+ this . have . keys ( key ) ;
314+ this . obj = getValue ( this . obj , key ) ;
315+ } ) ;
341316
342- this . assert ( missingKeys . length === 0 && extraKeys . length === 0 ) ;
317+ Assertion . add ( 'value' , function ( key , value ) {
318+ this . have . key ( key ) . which . is . eql ( value ) ;
343319 } ) ;
344320
345- Assertion . alias ( "keys" , "key" ) ;
321+ Assertion . add ( 'size' , function ( s ) {
322+ this . params = { operator : 'to have size ' + s } ;
323+ size ( this . obj ) . should . be . exactly ( s ) ;
324+ } ) ;
346325
347326 /**
348327 * Asserts given object has nested property in depth by path. **On success it change given object to be value of final property**.
0 commit comments