test.js 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. 'use strict'
  2. var expect = require('chai').expect,
  3. objectPath = require('./index.js')
  4. function getTestObj () {
  5. return {
  6. a: 'b',
  7. b: {
  8. c: [],
  9. d: ['a', 'b'],
  10. e: [{}, {f: 'g'}],
  11. f: 'i'
  12. }
  13. }
  14. }
  15. describe('get', function () {
  16. it('should return the value using unicode key', function () {
  17. var obj = {
  18. '15\u00f8C': {
  19. '3\u0111': 1
  20. }
  21. }
  22. expect(objectPath.get(obj, '15\u00f8C.3\u0111')).to.be.equal(1)
  23. expect(objectPath.get(obj, ['15\u00f8C', '3\u0111'])).to.be.equal(1)
  24. })
  25. it('should return the value using dot in key', function () {
  26. var obj = {
  27. 'a.b': {
  28. 'looks.like': 1
  29. }
  30. }
  31. expect(objectPath.get(obj, 'a.b.looks.like')).to.be.equal(void 0)
  32. expect(objectPath.get(obj, ['a.b', 'looks.like'])).to.be.equal(1)
  33. })
  34. it('should return the value under shallow object', function () {
  35. var obj = getTestObj()
  36. expect(objectPath.get(obj, 'a')).to.be.equal('b')
  37. expect(objectPath.get(obj, ['a'])).to.be.equal('b')
  38. })
  39. it('should work with number path', function () {
  40. var obj = getTestObj()
  41. expect(objectPath.get(obj.b.d, 0)).to.be.equal('a')
  42. expect(objectPath.get(obj.b, 0)).to.be.equal(void 0)
  43. })
  44. it('should return the value under deep object', function () {
  45. var obj = getTestObj()
  46. expect(objectPath.get(obj, 'b.f')).to.be.equal('i')
  47. expect(objectPath.get(obj, ['b', 'f'])).to.be.equal('i')
  48. })
  49. it('should return the value under array', function () {
  50. var obj = getTestObj()
  51. expect(objectPath.get(obj, 'b.d.0')).to.be.equal('a')
  52. expect(objectPath.get(obj, ['b', 'd', 0])).to.be.equal('a')
  53. })
  54. it('should return the value under array deep', function () {
  55. var obj = getTestObj()
  56. expect(objectPath.get(obj, 'b.e.1.f')).to.be.equal('g')
  57. expect(objectPath.get(obj, ['b', 'e', 1, 'f'])).to.be.equal('g')
  58. })
  59. it('should return undefined for missing values under object', function () {
  60. var obj = getTestObj()
  61. expect(objectPath.get(obj, 'a.b')).to.not.exist
  62. expect(objectPath.get(obj, ['a', 'b'])).to.not.exist
  63. })
  64. it('should return undefined for missing values under array', function () {
  65. var obj = getTestObj()
  66. expect(objectPath.get(obj, 'b.d.5')).to.not.exist
  67. expect(objectPath.get(obj, ['b', 'd', '5'])).to.not.exist
  68. })
  69. it('should return the value under integer-like key', function () {
  70. var obj = {'1a': 'foo'}
  71. expect(objectPath.get(obj, '1a')).to.be.equal('foo')
  72. expect(objectPath.get(obj, ['1a'])).to.be.equal('foo')
  73. })
  74. it('should return the default value when the key doesnt exist', function () {
  75. var obj = {'1a': 'foo'}
  76. expect(objectPath.get(obj, '1b', null)).to.be.equal(null)
  77. expect(objectPath.get(obj, ['1b'], null)).to.be.equal(null)
  78. })
  79. it('should return the default value when path is empty', function () {
  80. var obj = {'1a': 'foo'}
  81. expect(objectPath.get(obj, '', null)).to.be.deep.equal({'1a': 'foo'})
  82. expect(objectPath.get(obj, [])).to.be.deep.equal({'1a': 'foo'})
  83. expect(objectPath.get({}, ['1'])).to.be.equal(undefined)
  84. })
  85. it('should return the default value when object is null or undefined', function () {
  86. expect(objectPath.get(null, 'test', 'a')).to.be.deep.equal('a')
  87. expect(objectPath.get(undefined, 'test', 'a')).to.be.deep.equal('a')
  88. })
  89. it(
  90. 'should not fail on an object with a null prototype',
  91. function assertSuccessForObjWithNullProto () {
  92. var foo = 'FOO'
  93. var objWithNullProto = Object.create(null)
  94. objWithNullProto.foo = foo
  95. expect(objectPath.get(objWithNullProto, 'foo')).to.equal(foo)
  96. }
  97. )
  98. it('should skip non own properties', function () {
  99. var Base = function (enabled) {
  100. }
  101. Base.prototype = {
  102. one: {
  103. two: true
  104. }
  105. }
  106. var Extended = function () {
  107. Base.call(this, true)
  108. }
  109. Extended.prototype = Object.create(Base.prototype)
  110. var extended = new Extended()
  111. expect(objectPath.get(extended, ['one', 'two'])).to.be.equal(undefined)
  112. extended.enabled = true
  113. expect(objectPath.get(extended, 'enabled')).to.be.equal(true)
  114. expect(objectPath.get(extended, 'one')).to.be.equal(undefined)
  115. })
  116. it('[security] should not get magic properties in default mode', function () {
  117. expect(objectPath.get({}, '__proto__')).to.be.undefined
  118. expect(objectPath.get({}, [['__proto__']])).to.be.undefined
  119. function Clazz() {}
  120. Clazz.prototype.test = []
  121. expect(objectPath.get(new Clazz(), '__proto__')).to.be.undefined
  122. expect(objectPath.get(new Clazz(), [['__proto__']])).to.be.undefined
  123. expect(objectPath.get(new Clazz(), ['constructor', 'prototype'])).to.be.undefined
  124. })
  125. it('[security] should not get magic properties in inheritedProps mode', function () {
  126. expect(function() {
  127. objectPath.withInheritedProps.get({}, '__proto__')
  128. }).to.throw('For security reasons')
  129. expect(function() {
  130. objectPath.withInheritedProps.get({}, [['__proto__']])
  131. }).to.throw('For security reasons')
  132. function Clazz() {}
  133. Clazz.prototype.test = 'original'
  134. expect(function() {
  135. objectPath.withInheritedProps.get(new Clazz(), '__proto__')
  136. }).to.throw('For security reasons')
  137. expect(function() {
  138. objectPath.withInheritedProps.get(new Clazz(), [['__proto__']])
  139. }).to.throw('For security reasons')
  140. expect(function() {
  141. objectPath.withInheritedProps.get(new Clazz(), ['constructor', 'prototype'])
  142. }).to.throw('For security reasons')
  143. })
  144. })
  145. describe('set', function () {
  146. it('should set the value using unicode key', function () {
  147. var obj = {
  148. '15\u00f8C': {
  149. '3\u0111': 1
  150. }
  151. }
  152. objectPath.set(obj, '15\u00f8C.3\u0111', 2)
  153. expect(objectPath.get(obj, '15\u00f8C.3\u0111')).to.be.equal(2)
  154. objectPath.set(obj, '15\u00f8C.3\u0111', 3)
  155. expect(objectPath.get(obj, ['15\u00f8C', '3\u0111'])).to.be.equal(3)
  156. })
  157. it('should set the value using dot in key', function () {
  158. var obj = {
  159. 'a.b': {
  160. 'looks.like': 1
  161. }
  162. }
  163. objectPath.set(obj, ['a.b', 'looks.like'], 2)
  164. expect(objectPath.get(obj, ['a.b', 'looks.like'])).to.be.equal(2)
  165. })
  166. it('should set value under shallow object', function () {
  167. var obj = getTestObj()
  168. objectPath.set(obj, 'c', {m: 'o'})
  169. expect(obj).to.include.nested.property('c.m', 'o')
  170. obj = getTestObj()
  171. objectPath.set(obj, ['c'], {m: 'o'})
  172. expect(obj).to.include.nested.property('c.m', 'o')
  173. })
  174. it('should set value using number path', function () {
  175. var obj = getTestObj()
  176. objectPath.set(obj.b.d, 0, 'o')
  177. expect(obj).to.have.nested.property('b.d.0', 'o')
  178. })
  179. it('should set value under deep object', function () {
  180. var obj = getTestObj()
  181. objectPath.set(obj, 'b.c', 'o')
  182. expect(obj).to.have.nested.property('b.c', 'o')
  183. obj = getTestObj()
  184. objectPath.set(obj, ['b', 'c'], 'o')
  185. expect(obj).to.have.nested.property('b.c', 'o')
  186. })
  187. it('should set value under array', function () {
  188. var obj = getTestObj()
  189. objectPath.set(obj, 'b.e.1.g', 'f')
  190. expect(obj).to.have.nested.property('b.e.1.g', 'f')
  191. obj = getTestObj()
  192. objectPath.set(obj, ['b', 'e', 1, 'g'], 'f')
  193. expect(obj).to.have.nested.property('b.e.1.g', 'f')
  194. obj = {}
  195. objectPath.set(obj, 'b.0', 'a')
  196. objectPath.set(obj, 'b.1', 'b')
  197. expect(obj.b).to.be.deep.equal(['a', 'b'])
  198. })
  199. it('should create intermediate objects', function () {
  200. var obj = getTestObj()
  201. objectPath.set(obj, 'c.d.e.f', 'l')
  202. expect(obj).to.have.nested.property('c.d.e.f', 'l')
  203. obj = getTestObj()
  204. objectPath.set(obj, ['c', 'd', 'e', 'f'], 'l')
  205. expect(obj).to.have.nested.property('c.d.e.f', 'l')
  206. })
  207. it('should create intermediate arrays', function () {
  208. var obj = getTestObj()
  209. objectPath.set(obj, 'c.0.1.m', 'l')
  210. expect(obj.c).to.be.an('array')
  211. expect(obj.c[0]).to.be.an('array')
  212. expect(obj).to.have.nested.property('c.0.1.m', 'l')
  213. obj = getTestObj()
  214. objectPath.set(obj, ['c', '0', 1, 'm'], 'l')
  215. expect(obj.c).to.be.an('object')
  216. expect(obj.c[0]).to.be.an('array')
  217. expect(obj).to.have.nested.property('c.0.1.m', 'l')
  218. })
  219. it('should set value under integer-like key', function () {
  220. var obj = getTestObj()
  221. objectPath.set(obj, '1a', 'foo')
  222. expect(obj).to.have.nested.property('1a', 'foo')
  223. obj = getTestObj()
  224. objectPath.set(obj, ['1a'], 'foo')
  225. expect(obj).to.have.nested.property('1a', 'foo')
  226. })
  227. it('should set value under empty array', function () {
  228. var obj = []
  229. objectPath.set(obj, [0], 'foo')
  230. expect(obj[0]).to.be.equal('foo')
  231. obj = []
  232. objectPath.set(obj, '0', 'foo')
  233. expect(obj[0]).to.be.equal('foo')
  234. })
  235. it('[security] should not set magic properties in default mode', function () {
  236. objectPath.set({}, '__proto__.injected', 'this is bad')
  237. expect(Object.prototype.injected).to.be.undefined
  238. objectPath.set({}, [['__proto__'], 'injected'], 'this is bad')
  239. expect(Object.prototype.injected).to.be.undefined
  240. objectPath.set({}, ['__proto__'], {})
  241. expect(Object.prototype.toString).to.be.a('function')
  242. function Clazz() {}
  243. Clazz.prototype.test = 'original'
  244. objectPath.set({}, ['__proto__'], {test: 'this is bad'})
  245. expect(Clazz.prototype.test).to.be.equal('original')
  246. objectPath.set(new Clazz(), '__proto__.test', 'this is bad')
  247. expect(Clazz.prototype.test).to.be.equal('original')
  248. objectPath.set(new Clazz(), [['__proto__'], 'test'], 'this is bad')
  249. expect(Clazz.prototype.test).to.be.equal('original')
  250. objectPath.set(new Clazz(), 'constructor.prototype.test', 'this is bad')
  251. expect(Clazz.prototype.test).to.be.equal('original')
  252. })
  253. it('[security] should throw an exception if trying to set magic properties in inheritedProps mode', function () {
  254. expect(function() {
  255. objectPath.withInheritedProps.set({}, '__proto__.injected', 'this is bad')
  256. expect(Object.prototype.injected).to.be.undefined
  257. }).to.throw('For security reasons')
  258. expect(function() {
  259. objectPath.withInheritedProps.set({}, [['__proto__'], 'injected'], 'this is bad')
  260. expect(Object.prototype.injected).to.be.undefined
  261. }).to.throw('For security reasons')
  262. function Clazz() {}
  263. Clazz.prototype.test = 'original'
  264. expect(function() {
  265. objectPath.withInheritedProps.set(new Clazz(), '__proto__.test', 'this is bad')
  266. expect(Clazz.prototype.test).to.be.equal('original')
  267. }).to.throw('For security reasons')
  268. expect(function() {
  269. objectPath.withInheritedProps.set(new Clazz(), 'constructor.prototype.test', 'this is bad')
  270. expect(Clazz.prototype.test).to.be.equal('original')
  271. }).to.throw('For security reasons')
  272. expect(function() {
  273. objectPath.withInheritedProps.set({}, 'constructor.prototype.injected', 'this is OK')
  274. expect(Object.prototype.injected).to.be.undefined
  275. }).to.throw('For security reasons')
  276. expect(function() {
  277. objectPath.withInheritedProps.set({}, [['constructor'], 'prototype', 'injected'], 'this is bad')
  278. expect(Object.prototype.injected).to.be.undefined
  279. }).to.throw('For security reasons')
  280. })
  281. })
  282. describe('push', function () {
  283. it('should push value to existing array using unicode key', function () {
  284. var obj = getTestObj()
  285. objectPath.push(obj, 'b.\u1290c', 'l')
  286. expect(obj).to.have.nested.property('b.\u1290c.0', 'l')
  287. objectPath.push(obj, ['b', '\u1290c'], 'l')
  288. expect(obj).to.have.nested.property('b.\u1290c.1', 'l')
  289. })
  290. it('should push value to existing array using dot key', function () {
  291. var obj = getTestObj()
  292. objectPath.push(obj, ['b', 'z.d'], 'l')
  293. expect(objectPath.get(obj, ['b', 'z.d', 0])).to.be.equal('l')
  294. })
  295. it('should push value to existing array', function () {
  296. var obj = getTestObj()
  297. objectPath.push(obj, 'b.c', 'l')
  298. expect(obj).to.have.nested.property('b.c.0', 'l')
  299. obj = getTestObj()
  300. objectPath.push(obj, ['b', 'c'], 'l')
  301. expect(obj).to.have.nested.property('b.c.0', 'l')
  302. })
  303. it('should push value to new array', function () {
  304. var obj = getTestObj()
  305. objectPath.push(obj, 'b.h', 'l')
  306. expect(obj).to.have.nested.property('b.h.0', 'l')
  307. obj = getTestObj()
  308. objectPath.push(obj, ['b', 'h'], 'l')
  309. expect(obj).to.have.nested.property('b.h.0', 'l')
  310. })
  311. it('should push value to existing array using number path', function () {
  312. var obj = getTestObj()
  313. objectPath.push(obj.b.e, 0, 'l')
  314. expect(obj).to.have.nested.property('b.e.0.0', 'l')
  315. })
  316. it('[security] should not push within prototype properties in default mode', function () {
  317. function Clazz() {}
  318. Clazz.prototype.test = []
  319. objectPath.push(new Clazz(), '__proto__.test', 'pushed')
  320. expect(Clazz.prototype.test).to.be.deep.equal([])
  321. objectPath.push(new Clazz(), [['__proto__'], 'test'], 'pushed')
  322. expect(Clazz.prototype.test).to.be.deep.equal([])
  323. objectPath.push(new Clazz(), 'constructor.prototype.test', 'pushed')
  324. expect(Clazz.prototype.test).to.be.deep.equal([])
  325. })
  326. it('[security] should not push within prototype properties in inheritedProps mode', function () {
  327. function Clazz() {}
  328. Clazz.prototype.test = []
  329. expect(function() {
  330. objectPath.withInheritedProps.push(new Clazz(), '__proto__.test', 'pushed')
  331. expect(Clazz.prototype.test).to.be.deep.equal([])
  332. }).to.throw('For security reasons')
  333. expect(function() {
  334. objectPath.withInheritedProps.push(new Clazz(), [['__proto__'], 'test'], 'pushed')
  335. expect(Clazz.prototype.test).to.be.deep.equal([])
  336. }).to.throw('For security reasons')
  337. expect(function() {
  338. objectPath.withInheritedProps.push(new Clazz(), 'constructor.prototype.test', 'pushed')
  339. expect(Clazz.prototype.test).to.be.deep.equal([])
  340. }).to.throw('For security reasons')
  341. })
  342. })
  343. describe('ensureExists', function () {
  344. it('should create the path if it does not exists', function () {
  345. var obj = getTestObj()
  346. var oldVal = objectPath.ensureExists(obj, 'b.g.1.l', 'test')
  347. expect(oldVal).to.not.exist
  348. expect(obj).to.have.nested.property('b.g.1.l', 'test')
  349. oldVal = objectPath.ensureExists(obj, 'b.g.1.l', 'test1')
  350. expect(oldVal).to.be.equal('test')
  351. expect(obj).to.have.nested.property('b.g.1.l', 'test')
  352. oldVal = objectPath.ensureExists(obj, 'b.\u8210', 'ok')
  353. expect(oldVal).to.not.exist
  354. expect(obj).to.have.nested.property('b.\u8210', 'ok')
  355. oldVal = objectPath.ensureExists(obj, ['b', 'dot.dot'], 'ok')
  356. expect(oldVal).to.not.exist
  357. expect(objectPath.get(obj, ['b', 'dot.dot'])).to.be.equal('ok')
  358. })
  359. it('should return the object if path is empty', function () {
  360. var obj = getTestObj()
  361. expect(objectPath.ensureExists(obj, [], 'test')).to.have.property('a', 'b')
  362. })
  363. it('Issue #26', function () {
  364. var any = {}
  365. objectPath.ensureExists(any, ['1', '1'], {})
  366. expect(any).to.be.an('object')
  367. expect(any[1]).to.be.an('object')
  368. expect(any[1][1]).to.be.an('object')
  369. })
  370. it('[security] should not set magic properties in default mode', function () {
  371. objectPath.ensureExists({}, '__proto__.injected', 'this is bad')
  372. expect(Object.prototype.injected).to.be.undefined
  373. objectPath.ensureExists({}, [['__proto__'], 'injected'], 'this is bad')
  374. expect(Object.prototype.injected).to.be.undefined
  375. objectPath.ensureExists({}, ['__proto__'], {})
  376. expect(Object.prototype.toString).to.be.a('function')
  377. function Clazz() {}
  378. Clazz.prototype.test = 'original'
  379. objectPath.ensureExists({}, ['__proto__'], {test: 'this is bad'})
  380. expect(Clazz.prototype.test).to.be.equal('original')
  381. objectPath.ensureExists(new Clazz(), '__proto__.test', 'this is bad')
  382. expect(Clazz.prototype.test).to.be.equal('original')
  383. objectPath.ensureExists(new Clazz(), [['__proto__'], 'test'], 'this is bad')
  384. expect(Clazz.prototype.test).to.be.equal('original')
  385. objectPath.ensureExists(new Clazz(), 'constructor.prototype.test', 'this is bad')
  386. expect(Clazz.prototype.test).to.be.equal('original')
  387. })
  388. it('[security] should throw an exception if trying to set magic properties in inheritedProps mode', function () {
  389. expect(function() {objectPath.withInheritedProps.ensureExists({}, '__proto__.injected', 'this is bad')})
  390. .to.throw('For security reasons')
  391. expect(Object.prototype.injected).to.be.undefined
  392. expect(function() {
  393. objectPath.withInheritedProps.ensureExists({}, [['__proto__'], 'injected'], 'this is bad')
  394. expect(Object.prototype.injected).to.be.undefined
  395. }).to.throw('For security reasons')
  396. function Clazz() {}
  397. Clazz.prototype.test = 'original'
  398. expect(function() {
  399. objectPath.withInheritedProps.ensureExists(new Clazz(), '__proto__.test', 'this is bad')
  400. expect(Clazz.prototype.test).to.be.equal('original')
  401. }).to.throw('For security reasons')
  402. expect(function() {
  403. objectPath.withInheritedProps.ensureExists(new Clazz(), 'constructor.prototype.test', 'this is bad')
  404. expect(Clazz.prototype.test).to.be.equal('original')
  405. }).to.throw('For security reasons')
  406. expect(function() {
  407. objectPath.withInheritedProps.ensureExists({}, 'constructor.prototype.injected', 'this is OK')
  408. expect(Object.prototype.injected).to.be.undefined
  409. }).to.throw('For security reasons')
  410. expect(function() {
  411. objectPath.withInheritedProps.ensureExists({}, [['constructor'], 'prototype', 'injected'], 'this is bad')
  412. expect(Object.prototype.injected).to.be.undefined
  413. }).to.throw('For security reasons')
  414. })
  415. })
  416. describe('coalesce', function () {
  417. it('should return the first non-undefined value', function () {
  418. var obj = {
  419. should: {have: 'prop'}
  420. }
  421. expect(objectPath.coalesce(obj, [
  422. 'doesnt.exist',
  423. ['might', 'not', 'exist'],
  424. 'should.have'
  425. ])).to.equal('prop')
  426. })
  427. it('should work with falsy values (null, 0, \'\', false)', function () {
  428. var obj = {
  429. is: {
  430. false: false,
  431. null: null,
  432. empty: '',
  433. zero: 0
  434. }
  435. }
  436. expect(objectPath.coalesce(obj, [
  437. 'doesnt.exist',
  438. 'is.zero'
  439. ])).to.equal(0)
  440. expect(objectPath.coalesce(obj, [
  441. 'doesnt.exist',
  442. 'is.false'
  443. ])).to.equal(false)
  444. expect(objectPath.coalesce(obj, [
  445. 'doesnt.exist',
  446. 'is.null'
  447. ])).to.equal(null)
  448. expect(objectPath.coalesce(obj, [
  449. 'doesnt.exist',
  450. 'is.empty'
  451. ])).to.equal('')
  452. })
  453. it('returns defaultValue if no paths found', function () {
  454. var obj = {
  455. doesnt: 'matter'
  456. }
  457. expect(objectPath.coalesce(obj, ['some.inexistant', 'path', ['on', 'object']], 'false')).to.equal('false')
  458. })
  459. it('works with unicode and dot keys', function () {
  460. var obj = {
  461. '\u7591': true,
  462. 'dot.dot': false
  463. }
  464. expect(objectPath.coalesce(obj, ['1', '\u7591', 'a.b'])).to.equal(true)
  465. expect(objectPath.coalesce(obj, ['1', ['dot.dot'], '\u7591'])).to.equal(false)
  466. })
  467. })
  468. describe('empty', function () {
  469. it('should ignore invalid arguments safely', function () {
  470. var obj = {}
  471. expect(objectPath.empty()).to.equal(void 0)
  472. expect(objectPath.empty(obj, 'path')).to.equal(void 0)
  473. expect(objectPath.empty(obj, '')).to.equal(void 0)
  474. obj.path = true
  475. expect(objectPath.empty(obj, 'inexistant')).to.equal(void 0)
  476. expect(objectPath.empty(null, 'path')).to.equal(void 0)
  477. expect(objectPath.empty(void 0, 'path')).to.equal(void 0)
  478. })
  479. it('should empty each path according to their types', function () {
  480. function Instance () {
  481. this.notOwn = true
  482. }
  483. /*istanbul ignore next: not part of code */
  484. Instance.prototype.test = function () {
  485. }
  486. /*istanbul ignore next: not part of code */
  487. Instance.prototype.arr = []
  488. var
  489. obj = {
  490. string: 'some string',
  491. array: ['some', 'array', [1, 2, 3]],
  492. number: 21,
  493. boolean: true,
  494. object: {
  495. some: 'property',
  496. sub: {
  497. 'property': true
  498. },
  499. nullProp: null,
  500. undefinedProp: void 0
  501. },
  502. instance: new Instance()
  503. }
  504. /*istanbul ignore next: not part of code */
  505. obj['function'] = function () {
  506. }
  507. objectPath.empty(obj, ['array', '2'])
  508. expect(obj.array[2]).to.deep.equal([])
  509. objectPath.empty(obj, 'object.sub')
  510. expect(obj.object.sub).to.deep.equal({})
  511. objectPath.empty(obj, 'object.nullProp')
  512. expect(obj.object.nullProp).to.equal(null)
  513. objectPath.empty(obj, 'object.undefinedProp')
  514. expect(obj.object.undefinedProp).to.equal(void 0)
  515. expect(obj.object).to.have.property('undefinedProp')
  516. objectPath.empty(obj, 'object.notAProp')
  517. expect(obj.object.notAProp).to.equal(void 0)
  518. expect(obj.object).to.not.have.property('notAProp')
  519. objectPath.empty(obj, 'instance.test')
  520. //instance.test is not own property, so it shouldn't be emptied
  521. expect(obj.instance.test).to.be.a('function')
  522. expect(Instance.prototype.test).to.be.a('function')
  523. objectPath.empty(obj, 'string')
  524. objectPath.empty(obj, 'number')
  525. objectPath.empty(obj, 'boolean')
  526. objectPath.empty(obj, 'function')
  527. objectPath.empty(obj, 'array')
  528. objectPath.empty(obj, 'object')
  529. objectPath.empty(obj, 'instance')
  530. expect(obj.string).to.equal('')
  531. expect(obj.array).to.deep.equal([])
  532. expect(obj.number).to.equal(0)
  533. expect(obj.boolean).to.equal(false)
  534. expect(obj.object).to.deep.equal({})
  535. expect(obj.instance.notOwn).to.be.an('undefined')
  536. expect(obj.instance.arr).to.be.an('array')
  537. expect(obj['function']).to.equal(null)
  538. })
  539. it('[security] should not empty prototype properties in default mode', function () {
  540. function Clazz() {}
  541. Clazz.prototype.test = 'original'
  542. objectPath.empty(new Clazz(), '__proto__')
  543. expect(Clazz.prototype.test).to.be.equal('original')
  544. objectPath.empty(new Clazz(), [['__proto__']])
  545. expect(Clazz.prototype.test).to.be.equal('original')
  546. objectPath.empty(new Clazz(), 'constructor.prototype')
  547. expect(Clazz.prototype.test).to.be.equal('original')
  548. })
  549. it('[security] should throw an exception if trying to delete prototype properties in inheritedProps mode', function () {
  550. function Clazz() {}
  551. Clazz.prototype.test = 'original'
  552. expect(function() {
  553. objectPath.withInheritedProps.empty(new Clazz(), '__proto__')
  554. expect(Clazz.prototype.test).to.be.equal('original')
  555. }).to.throw('For security reasons')
  556. expect(function() {
  557. objectPath.withInheritedProps.empty(new Clazz(), 'constructor.prototype')
  558. expect(Clazz.prototype.test).to.be.equal('original')
  559. }).to.throw('For security reasons')
  560. expect(function() {
  561. objectPath.withInheritedProps.empty({}, [['constructor'], 'prototype'])
  562. expect(Clazz.prototype.test).to.be.equal('original')
  563. }).to.throw('For security reasons')
  564. })
  565. })
  566. describe('del', function () {
  567. it('should work with number path', function () {
  568. var obj = getTestObj()
  569. objectPath.del(obj.b.d, 1)
  570. expect(obj.b.d).to.deep.equal(['a'])
  571. })
  572. it('should remove null and undefined props (but not explode on nested)', function () {
  573. var obj = {nullProp: null, undefinedProp: void 0}
  574. expect(obj).to.have.property('nullProp')
  575. expect(obj).to.have.property('undefinedProp')
  576. objectPath.del(obj, 'nullProp.foo')
  577. objectPath.del(obj, 'undefinedProp.bar')
  578. expect(obj).to.have.property('nullProp')
  579. expect(obj).to.have.property('undefinedProp')
  580. expect(obj).to.deep.equal({nullProp: null, undefinedProp: void 0})
  581. objectPath.del(obj, 'nullProp')
  582. objectPath.del(obj, 'undefinedProp')
  583. expect(obj).to.not.have.property('nullProp')
  584. expect(obj).to.not.have.property('undefinedProp')
  585. expect(obj).to.deep.equal({})
  586. })
  587. it('should delete deep paths', function () {
  588. var obj = getTestObj()
  589. expect(objectPath.del(obj)).to.be.equal(obj)
  590. objectPath.set(obj, 'b.g.1.0', 'test')
  591. objectPath.set(obj, 'b.g.1.1', 'test')
  592. objectPath.set(obj, 'b.h.az', 'test')
  593. objectPath.set(obj, 'b.\ubeef', 'test')
  594. objectPath.set(obj, ['b', 'dot.dot'], 'test')
  595. expect(obj).to.have.nested.property('b.g.1.0', 'test')
  596. expect(obj).to.have.nested.property('b.g.1.1', 'test')
  597. expect(obj).to.have.nested.property('b.h.az', 'test')
  598. expect(obj).to.have.nested.property('b.\ubeef', 'test')
  599. objectPath.del(obj, 'b.h.az')
  600. expect(obj).to.not.have.nested.property('b.h.az')
  601. expect(obj).to.have.nested.property('b.h')
  602. objectPath.del(obj, 'b.g.1.1')
  603. expect(obj).to.not.have.nested.property('b.g.1.1')
  604. expect(obj).to.have.nested.property('b.g.1.0', 'test')
  605. objectPath.del(obj, 'b.\ubeef')
  606. expect(obj).to.not.have.nested.property('b.\ubeef')
  607. objectPath.del(obj, ['b', 'dot.dot'])
  608. expect(objectPath.get(obj, ['b', 'dot.dot'])).to.be.equal(void 0)
  609. objectPath.del(obj, ['b', 'g', '1', '0'])
  610. expect(obj).to.not.have.nested.property('b.g.1.0')
  611. expect(obj).to.have.nested.property('b.g.1')
  612. expect(objectPath.del(obj, ['b'])).to.not.have.nested.property('b.g')
  613. expect(obj).to.be.deep.equal({'a': 'b'})
  614. })
  615. it('should remove items from existing array', function () {
  616. var obj = getTestObj()
  617. objectPath.del(obj, 'b.d.0')
  618. expect(obj.b.d).to.have.length(1)
  619. expect(obj.b.d).to.be.deep.equal(['b'])
  620. objectPath.del(obj, 'b.d.0')
  621. expect(obj.b.d).to.have.length(0)
  622. expect(obj.b.d).to.be.deep.equal([])
  623. })
  624. it('[security] should not delete prototype properties in default mode', function () {
  625. objectPath.del({}, '__proto__.valueOf')
  626. expect(Object.prototype.valueOf).to.be.a('function')
  627. objectPath.del({}, [['__proto__'], 'valueOf'])
  628. expect(Object.prototype.valueOf).to.be.a('function')
  629. function Clazz() {}
  630. Clazz.prototype.test = 'original'
  631. objectPath.del(new Clazz(), '__proto__.test')
  632. expect(Clazz.prototype.test).to.be.equal('original')
  633. objectPath.del(new Clazz(), [['__proto__'], 'test'])
  634. expect(Clazz.prototype.test).to.be.equal('original')
  635. objectPath.del(new Clazz(), 'constructor.prototype.test')
  636. expect(Clazz.prototype.test).to.be.equal('original')
  637. })
  638. it('[security] should throw an exception if trying to delete prototype properties in inheritedProps mode', function () {
  639. expect(function() {
  640. objectPath.withInheritedProps.del({}, '__proto__.valueOf')
  641. expect(Object.prototype.valueOf).to.be.a('function')
  642. }).to.throw('For security reasons')
  643. expect(function() {
  644. objectPath.withInheritedProps.del({}, [['__proto__'], 'valueOf'])
  645. expect(Object.prototype.valueOf).to.be.a('function')
  646. }).to.throw('For security reasons')
  647. function Clazz() {}
  648. Clazz.prototype.test = 'original'
  649. expect(function() {
  650. objectPath.withInheritedProps.del(new Clazz(), '__proto__.test')
  651. expect(Clazz.prototype.test).to.be.equal('original')
  652. }).to.throw('For security reasons')
  653. expect(function() {
  654. objectPath.withInheritedProps.del(new Clazz(), 'constructor.prototype.test', 'this is bad')
  655. expect(Clazz.prototype.test).to.be.equal('original')
  656. }).to.throw('For security reasons')
  657. expect(function() {
  658. objectPath.withInheritedProps.del({}, [['constructor'], 'prototype', 'test'])
  659. expect(Clazz.prototype.test).to.be.equal('original')
  660. }).to.throw('For security reasons')
  661. })
  662. })
  663. describe('insert', function () {
  664. it('should insert value into existing array', function () {
  665. var obj = getTestObj()
  666. objectPath.insert(obj, 'b.c', 'asdf')
  667. expect(obj).to.have.nested.property('b.c.0', 'asdf')
  668. expect(obj).to.not.have.nested.property('b.c.1')
  669. })
  670. it('should create intermediary array', function () {
  671. var obj = getTestObj()
  672. objectPath.insert(obj, 'b.c.0', 'asdf')
  673. expect(obj).to.have.nested.property('b.c.0.0', 'asdf')
  674. })
  675. it('should insert in another index', function () {
  676. var obj = getTestObj()
  677. objectPath.insert(obj, 'b.d', 'asdf', 1)
  678. expect(obj).to.have.nested.property('b.d.1', 'asdf')
  679. expect(obj).to.have.nested.property('b.d.0', 'a')
  680. expect(obj).to.have.nested.property('b.d.2', 'b')
  681. })
  682. it('should handle sparse array', function () {
  683. var obj = getTestObj()
  684. obj.b.d = new Array(4)
  685. obj.b.d[0] = 'a'
  686. obj.b.d[1] = 'b'
  687. objectPath.insert(obj, 'b.d', 'asdf', 3)
  688. expect(obj.b.d).to.have.members([
  689. 'a',
  690. 'b',
  691. ,
  692. ,
  693. 'asdf'
  694. ])
  695. })
  696. it('[security] should not insert within prototype properties in default mode', function () {
  697. function Clazz() {}
  698. Clazz.prototype.test = []
  699. objectPath.insert(new Clazz(), '__proto__.test', 'inserted', 0)
  700. expect(Clazz.prototype.test).to.be.deep.equal([])
  701. objectPath.insert(new Clazz(), [['__proto__'], 'test'], 'inserted', 0)
  702. expect(Clazz.prototype.test).to.be.deep.equal([])
  703. objectPath.insert(new Clazz(), 'constructor.prototype.test', 'inserted', 0)
  704. expect(Clazz.prototype.test).to.be.deep.equal([])
  705. })
  706. it('[security] should not insert within prototype properties in inheritedProps mode', function () {
  707. function Clazz() {}
  708. Clazz.prototype.test = []
  709. expect(function() {
  710. objectPath.withInheritedProps.insert(new Clazz(), '__proto__.test', 'inserted', 0)
  711. expect(Clazz.prototype.test).to.be.deep.equal([])
  712. }).to.throw('For security reasons')
  713. expect(function() {
  714. objectPath.withInheritedProps.insert(new Clazz(), [['__proto__'], 'test'], 'inserted', 0)
  715. expect(Clazz.prototype.test).to.be.deep.equal([])
  716. }).to.throw('For security reasons')
  717. expect(function() {
  718. objectPath.withInheritedProps.insert(new Clazz(), 'constructor.prototype.test', 'inserted', 0)
  719. expect(Clazz.prototype.test).to.be.deep.equal([])
  720. }).to.throw('For security reasons')
  721. expect(function() {
  722. objectPath.withInheritedProps.insert(new Clazz().constructor, 'prototype.test', 'inserted', 0)
  723. expect(Clazz.prototype.test).to.be.deep.equal([])
  724. }).to.throw('For security reasons')
  725. })
  726. })
  727. describe('has', function () {
  728. it('should return false for empty object', function () {
  729. expect(objectPath.has({}, 'a')).to.be.equal(false)
  730. })
  731. it('should handle empty paths properly', function () {
  732. var obj = getTestObj()
  733. expect(objectPath.has(obj, '')).to.be.equal(false)
  734. expect(objectPath.has(obj, [''])).to.be.equal(false)
  735. obj[''] = 1
  736. expect(objectPath.has(obj, '')).to.be.equal(true)
  737. expect(objectPath.has(obj, [''])).to.be.equal(true)
  738. expect(objectPath.has(obj, [])).to.be.equal(true)
  739. expect(objectPath.has(null, [])).to.be.equal(false)
  740. })
  741. it('should test under shallow object', function () {
  742. var obj = getTestObj()
  743. expect(objectPath.has(obj, 'a')).to.be.equal(true)
  744. expect(objectPath.has(obj, ['a'])).to.be.equal(true)
  745. expect(objectPath.has(obj, 'z')).to.be.equal(false)
  746. expect(objectPath.has(obj, ['z'])).to.be.equal(false)
  747. })
  748. it('should work with number path', function () {
  749. var obj = getTestObj()
  750. expect(objectPath.has(obj.b.d, 0)).to.be.equal(true)
  751. expect(objectPath.has(obj.b, 0)).to.be.equal(false)
  752. expect(objectPath.has(obj.b.d, 10)).to.be.equal(false)
  753. expect(objectPath.has(obj.b, 10)).to.be.equal(false)
  754. })
  755. it('should test under deep object', function () {
  756. var obj = getTestObj()
  757. expect(objectPath.has(obj, 'b.f')).to.be.equal(true)
  758. expect(objectPath.has(obj, ['b', 'f'])).to.be.equal(true)
  759. expect(objectPath.has(obj, 'b.g')).to.be.equal(false)
  760. expect(objectPath.has(obj, ['b', 'g'])).to.be.equal(false)
  761. })
  762. it('should test value under array', function () {
  763. var obj = {
  764. b: ['a']
  765. }
  766. obj.b[3] = {o: 'a'}
  767. expect(objectPath.has(obj, 'b.0')).to.be.equal(true)
  768. expect(objectPath.has(obj, 'b.1')).to.be.equal(true)
  769. expect(objectPath.has(obj, 'b.3.o')).to.be.equal(true)
  770. expect(objectPath.has(obj, 'b.3.qwe')).to.be.equal(false)
  771. expect(objectPath.has(obj, 'b.4')).to.be.equal(false)
  772. })
  773. it('should test the value under array deep', function () {
  774. var obj = getTestObj()
  775. expect(objectPath.has(obj, 'b.e.1.f')).to.be.equal(true)
  776. expect(objectPath.has(obj, ['b', 'e', 1, 'f'])).to.be.equal(true)
  777. expect(objectPath.has(obj, 'b.e.1.f.g.h.i')).to.be.equal(false)
  778. expect(objectPath.has(obj, ['b', 'e', 1, 'f', 'g', 'h', 'i'])).to.be.equal(false)
  779. })
  780. it('should test the value under integer-like key', function () {
  781. var obj = {'1a': 'foo'}
  782. expect(objectPath.has(obj, '1a')).to.be.equal(true)
  783. expect(objectPath.has(obj, ['1a'])).to.be.equal(true)
  784. })
  785. it('should distinct nonexistent key and key = undefined', function () {
  786. var obj = {}
  787. expect(objectPath.has(obj, 'key')).to.be.equal(false)
  788. obj.key = undefined
  789. expect(objectPath.has(obj, 'key')).to.be.equal(true)
  790. })
  791. it('should work with deep undefined/null values', function () {
  792. var obj = {}
  793. expect(objectPath.has(obj, 'missing.test')).to.be.equal(false)
  794. obj.missing = null
  795. expect(objectPath.has(obj, 'missing.test')).to.be.equal(false)
  796. obj.sparseArray = [1, undefined, 3]
  797. expect(objectPath.has(obj, 'sparseArray.1.test')).to.be.equal(false)
  798. })
  799. })
  800. describe('bind object', function () {
  801. // just get one scenario from each feature, so whole functionality is proxied well
  802. it('should return the value under shallow object', function () {
  803. var obj = getTestObj()
  804. var model = objectPath(obj)
  805. expect(model.get('a')).to.be.equal('b')
  806. expect(model.get(['a'])).to.be.equal('b')
  807. })
  808. it('should set value under shallow object', function () {
  809. var obj = getTestObj()
  810. var model = objectPath(obj)
  811. model.set('c', {m: 'o'})
  812. expect(obj).to.have.nested.property('c.m', 'o')
  813. obj = getTestObj()
  814. model = objectPath(obj)
  815. model.set(['c'], {m: 'o'})
  816. expect(obj).to.have.nested.property('c.m', 'o')
  817. })
  818. it('should push value to existing array', function () {
  819. var obj = getTestObj()
  820. var model = objectPath(obj)
  821. model.push('b.c', 'l')
  822. expect(obj).to.have.nested.property('b.c.0', 'l')
  823. obj = getTestObj()
  824. model = objectPath(obj)
  825. model.push(['b', 'c'], 'l')
  826. expect(obj).to.have.nested.property('b.c.0', 'l')
  827. })
  828. it('should create the path if it does not exists', function () {
  829. var obj = getTestObj()
  830. var model = objectPath(obj)
  831. var oldVal = model.ensureExists('b.g.1.l', 'test')
  832. expect(oldVal).to.not.exist
  833. expect(obj).to.have.nested.property('b.g.1.l', 'test')
  834. oldVal = model.ensureExists('b.g.1.l', 'test1')
  835. expect(oldVal).to.be.equal('test')
  836. expect(obj).to.have.nested.property('b.g.1.l', 'test')
  837. })
  838. it('should return the first non-undefined value', function () {
  839. var obj = {
  840. should: {have: 'prop'}
  841. }
  842. var model = objectPath(obj)
  843. expect(model.coalesce([
  844. 'doesnt.exist',
  845. ['might', 'not', 'exist'],
  846. 'should.have'
  847. ])).to.equal('prop')
  848. })
  849. it('should empty each path according to their types', function () {
  850. function Instance () {
  851. this.notOwn = true
  852. }
  853. /*istanbul ignore next: not part of code */
  854. Instance.prototype.test = function () {
  855. }
  856. /*istanbul ignore next: not part of code */
  857. Instance.prototype.arr = []
  858. var
  859. obj = {
  860. string: 'some string',
  861. array: ['some', 'array', [1, 2, 3]],
  862. number: 21,
  863. boolean: true,
  864. object: {
  865. some: 'property',
  866. sub: {
  867. 'property': true
  868. }
  869. },
  870. instance: new Instance()
  871. }
  872. /*istanbul ignore next: not part of code */
  873. obj['function'] = function () {
  874. }
  875. var model = objectPath(obj)
  876. model.empty(['array', '2'])
  877. expect(obj.array[2]).to.deep.equal([])
  878. model.empty('object.sub')
  879. expect(obj.object.sub).to.deep.equal({})
  880. model.empty('instance.test')
  881. //instance.test is not own property so it shouldn't be emptied
  882. expect(obj.instance.test).to.be.a('function')
  883. expect(Instance.prototype.test).to.be.a('function')
  884. model.empty('string')
  885. model.empty('number')
  886. model.empty('boolean')
  887. model.empty('function')
  888. model.empty('array')
  889. model.empty('object')
  890. model.empty('instance')
  891. expect(obj.string).to.equal('')
  892. expect(obj.array).to.deep.equal([])
  893. expect(obj.number).to.equal(0)
  894. expect(obj.boolean).to.equal(false)
  895. expect(obj.object).to.deep.equal({})
  896. expect(obj.instance.notOwn).to.be.an('undefined')
  897. expect(obj.instance.arr).to.be.an('array')
  898. expect(obj['function']).to.equal(null)
  899. })
  900. it('should delete deep paths', function () {
  901. var obj = getTestObj()
  902. var model = objectPath(obj)
  903. expect(model.del()).to.be.equal(obj)
  904. model.set('b.g.1.0', 'test')
  905. model.set('b.g.1.1', 'test')
  906. model.set('b.h.az', 'test')
  907. expect(obj).to.have.nested.property('b.g.1.0', 'test')
  908. expect(obj).to.have.nested.property('b.g.1.1', 'test')
  909. expect(obj).to.have.nested.property('b.h.az', 'test')
  910. model.del('b.h.az')
  911. expect(obj).to.not.have.nested.property('b.h.az')
  912. expect(obj).to.have.nested.property('b.h')
  913. model.del('b.g.1.1')
  914. expect(obj).to.not.have.nested.property('b.g.1.1')
  915. expect(obj).to.have.nested.property('b.g.1.0', 'test')
  916. model.del(['b', 'g', '1', '0'])
  917. expect(obj).to.not.have.nested.property('b.g.1.0')
  918. expect(obj).to.have.nested.property('b.g.1')
  919. expect(model.del(['b'])).to.not.have.nested.property('b.g')
  920. expect(obj).to.be.deep.equal({'a': 'b'})
  921. })
  922. it('should insert value into existing array', function () {
  923. var obj = getTestObj()
  924. var model = objectPath(obj)
  925. model.insert('b.c', 'asdf')
  926. expect(obj).to.have.nested.property('b.c.0', 'asdf')
  927. expect(obj).to.not.have.nested.property('b.c.1')
  928. })
  929. it('should test under shallow object', function () {
  930. var obj = getTestObj()
  931. var model = objectPath(obj)
  932. expect(model.has('a')).to.be.equal(true)
  933. expect(model.has(['a'])).to.be.equal(true)
  934. expect(model.has('z')).to.be.equal(false)
  935. expect(model.has(['z'])).to.be.equal(false)
  936. })
  937. })
  938. describe('Don\'t access not own properties [default]', function () {
  939. it('should not get a not own property', function () {
  940. var Obj = function () {
  941. }
  942. Obj.prototype.notOwn = {a: 'a'}
  943. var obj = new Obj()
  944. expect(objectPath.get(obj, 'notOwn')).to.be.undefined
  945. })
  946. it('should set a not own property on the instance (not the prototype)', function () {
  947. var proto = {
  948. notOwn: {}
  949. }
  950. var obj = Object.create(proto)
  951. objectPath.set(obj, 'notOwn.test', 'a')
  952. expect(obj.notOwn.test).to.be.equal('a')
  953. expect(proto.notOwn).to.be.deep.equal({})
  954. })
  955. it('has should return false on a not own property', function () {
  956. var proto = {
  957. notOwn: {a: 'a'}
  958. }
  959. var obj = Object.create(proto)
  960. expect(objectPath.has(obj, 'notOwn')).to.be.false
  961. expect(objectPath.has(obj, 'notOwn.a')).to.be.false
  962. })
  963. it('empty should not empty on a not own property', function () {
  964. var proto = {
  965. notOwn: {a: 'a'}
  966. }
  967. var obj = Object.create(proto)
  968. objectPath.empty(obj, 'notOwn')
  969. expect(proto.notOwn).to.be.deep.equal({a: 'a'})
  970. expect(obj.notOwn).to.be.deep.equal({a: 'a'})
  971. })
  972. it('del should not delete not own property', function () {
  973. var proto = {
  974. notOwn: {a: 'a'}
  975. }
  976. var obj = Object.create(proto)
  977. objectPath.del(obj, 'notOwn.a')
  978. expect(proto.notOwn).to.be.deep.equal({a: 'a'})
  979. //expect(obj.notOwn).to.be.deep.equal({a: 'a'});
  980. //objectPath.del(obj, 'notOwn');
  981. //expect(proto).to.be.deep.equal({notOwn: {a: 'a'}});
  982. //expect(obj).to.be.deep.equal({notOwn: {a: 'a'}});
  983. })
  984. })
  985. describe('Access own properties [optional]', function () {
  986. it('should get a not own property', function () {
  987. var Obj = function () {
  988. }
  989. Obj.prototype.notOwn = {a: 'a'}
  990. var obj = new Obj()
  991. expect(objectPath.withInheritedProps.get(obj, 'notOwn.a')).to.be.equal('a')
  992. })
  993. it('should set a deep not own property on the prototype (if exists)', function () {
  994. var proto = {
  995. notOwn: {}
  996. }
  997. var obj = Object.create(proto)
  998. objectPath.withInheritedProps.set(obj, 'notOwn.test', 'a')
  999. expect(obj.notOwn.test).to.be.equal('a')
  1000. expect(proto.notOwn).to.be.deep.equal({test: 'a'})
  1001. })
  1002. it('has should return true on a not own property', function () {
  1003. var proto = {
  1004. notOwn: {a: 'a'}
  1005. }
  1006. var obj = Object.create(proto)
  1007. expect(objectPath.withInheritedProps.has(obj, 'notOwn')).to.be.true
  1008. expect(objectPath.withInheritedProps.has(obj, 'notOwn.a')).to.be.true
  1009. })
  1010. it('empty should empty a not own property', function () {
  1011. var proto = {
  1012. notOwn: {a: 'a'}
  1013. }
  1014. var obj = Object.create(proto)
  1015. objectPath.withInheritedProps.empty(obj, 'notOwn')
  1016. expect(proto.notOwn).to.be.deep.equal({})
  1017. expect(obj.notOwn).to.be.deep.equal({})
  1018. })
  1019. it('del should delete a not own property', function () {
  1020. var proto = {
  1021. notOwn: {a: 'a'}
  1022. }
  1023. var obj = Object.create(proto)
  1024. objectPath.withInheritedProps.del(obj, 'notOwn.a')
  1025. expect(proto.notOwn).to.be.deep.equal({})
  1026. //expect(obj.notOwn).to.be.deep.equal({});
  1027. objectPath.withInheritedProps.del(obj, 'notOwn')
  1028. //expect(proto).to.be.deep.equal({notOwn: {}});
  1029. //expect(obj).to.be.deep.equal({notOwn: {}});
  1030. })
  1031. })