index.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. 'use strict'
  2. const { test } = require('tap')
  3. const rfdc = require('..')
  4. const clone = rfdc()
  5. const cloneProto = rfdc({proto: true})
  6. const cloneCircles = rfdc({circles: true})
  7. const cloneCirclesProto = rfdc({circles: true, proto: true})
  8. types(clone, 'default')
  9. types(cloneProto, 'proto option')
  10. types(cloneCircles, 'circles option')
  11. types(cloneCirclesProto, 'circles and proto option')
  12. test('default – does not copy proto properties', async ({is}) => {
  13. is(clone(Object.create({a: 1})).a, undefined, 'value not copied')
  14. })
  15. test('proto option – copies enumerable proto properties', async ({is}) => {
  16. is(cloneProto(Object.create({a: 1})).a, 1, 'value copied')
  17. })
  18. test('circles option - circular object', async ({same, is, isNot}) => {
  19. const o = {nest: {a: 1, b: 2}}
  20. o.circular = o
  21. same(cloneCircles(o), o, 'same values')
  22. isNot(cloneCircles(o), o, 'different objects')
  23. isNot(cloneCircles(o).nest, o.nest, 'different nested objects')
  24. const c = cloneCircles(o)
  25. is(c.circular, c, 'circular references point to copied parent')
  26. isNot(c.circular, o, 'circular references do not point to original parent')
  27. })
  28. test('circles option – deep circular object', async ({same, is, isNot}) => {
  29. const o = {nest: {a: 1, b: 2}}
  30. o.nest.circular = o
  31. same(cloneCircles(o), o, 'same values')
  32. isNot(cloneCircles(o), o, 'different objects')
  33. isNot(cloneCircles(o).nest, o.nest, 'different nested objects')
  34. const c = cloneCircles(o)
  35. is(c.nest.circular, c, 'circular references point to copied parent')
  36. isNot(c.nest.circular, o, 'circular references do not point to original parent')
  37. })
  38. test('circles option alone – does not copy proto properties', async ({is}) => {
  39. is(cloneCircles(Object.create({a: 1})).a, undefined, 'value not copied')
  40. })
  41. test('circles and proto option – copies enumerable proto properties', async ({is}) => {
  42. is(cloneCirclesProto(Object.create({a: 1})).a, 1, 'value copied')
  43. })
  44. test('circles and proto option - circular object', async ({same, is, isNot}) => {
  45. const o = {nest: {a: 1, b: 2}}
  46. o.circular = o
  47. same(cloneCirclesProto(o), o, 'same values')
  48. isNot(cloneCirclesProto(o), o, 'different objects')
  49. isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
  50. const c = cloneCirclesProto(o)
  51. is(c.circular, c, 'circular references point to copied parent')
  52. isNot(c.circular, o, 'circular references do not point to original parent')
  53. })
  54. test('circles and proto option – deep circular object', async ({same, is, isNot}) => {
  55. const o = {nest: {a: 1, b: 2}}
  56. o.nest.circular = o
  57. same(cloneCirclesProto(o), o, 'same values')
  58. isNot(cloneCirclesProto(o), o, 'different objects')
  59. isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
  60. const c = cloneCirclesProto(o)
  61. is(c.nest.circular, c, 'circular references point to copied parent')
  62. isNot(c.nest.circular, o, 'circular references do not point to original parent')
  63. })
  64. test('circles and proto option – deep circular array', async ({same, is, isNot}) => {
  65. const o = { nest: [1, 2] }
  66. o.nest.push(o)
  67. same(cloneCirclesProto(o), o, 'same values')
  68. isNot(cloneCirclesProto(o), o, 'different objects')
  69. isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
  70. const c = cloneCirclesProto(o)
  71. is(c.nest[2], c, 'circular references point to copied parent')
  72. isNot(c.nest[2], o, 'circular references do not point to original parent')
  73. })
  74. function types (clone, label) {
  75. test(label + ' – number', async ({is}) => {
  76. is(clone(42), 42, 'same value')
  77. })
  78. test(label + ' – string', async ({is}) => {
  79. is(clone('str'), 'str', 'same value')
  80. })
  81. test(label + ' – boolean', async ({is}) => {
  82. is(clone(true), true, 'same value')
  83. })
  84. test(label + ' – function', async ({is}) => {
  85. const fn = () => {}
  86. is(clone(fn), fn, 'same function')
  87. })
  88. test(label + ' – async function', async ({is}) => {
  89. const fn = async () => {}
  90. is(clone(fn), fn, 'same function')
  91. })
  92. test(label + ' – generator function', async ({is}) => {
  93. const fn = function * () {}
  94. is(clone(fn), fn, 'same function')
  95. })
  96. test(label + ' – date', async ({is, isNot}) => {
  97. const date = new Date()
  98. is(+clone(date), +date, 'same value')
  99. isNot(clone(date), date, 'different object')
  100. })
  101. test(label + ' – null', async ({is}) => {
  102. is(clone(null), null, 'same value')
  103. })
  104. test(label + ' – shallow object', async ({same, isNot}) => {
  105. const o = {a: 1, b: 2}
  106. same(clone(o), o, 'same values')
  107. isNot(clone(o), o, 'different object')
  108. })
  109. test(label + ' – shallow array', async ({same, isNot}) => {
  110. const o = [1, 2]
  111. same(clone(o), o, 'same values')
  112. isNot(clone(o), o, 'different arrays')
  113. })
  114. test(label + ' – deep object', async ({same, isNot}) => {
  115. const o = {nest: {a: 1, b: 2}}
  116. same(clone(o), o, 'same values')
  117. isNot(clone(o), o, 'different objects')
  118. isNot(clone(o).nest, o.nest, 'different nested objects')
  119. })
  120. test(label + ' – deep array', async ({same, isNot}) => {
  121. const o = [ {a: 1, b: 2}, [3] ]
  122. same(clone(o), o, 'same values')
  123. isNot(clone(o), o, 'different arrays')
  124. isNot(clone(o)[0], o[0], 'different array elements')
  125. isNot(clone(o)[1], o[1], 'different array elements')
  126. })
  127. test(label + ' – nested number', async ({is}) => {
  128. is(clone({a: 1}).a, 1, 'same value')
  129. })
  130. test(label + ' – nested string', async ({is}) => {
  131. is(clone({s: 'str'}).s, 'str', 'same value')
  132. })
  133. test(label + ' – nested boolean', async ({is}) => {
  134. is(clone({b: true}).b, true, 'same value')
  135. })
  136. test(label + ' – nested function', async ({is}) => {
  137. const fn = () => {}
  138. is(clone({fn}).fn, fn, 'same function')
  139. })
  140. test(label + ' – nested async function', async ({is}) => {
  141. const fn = async () => {}
  142. is(clone({fn}).fn, fn, 'same function')
  143. })
  144. test(label + ' – nested generator function', async ({is}) => {
  145. const fn = function * () {}
  146. is(clone({fn}).fn, fn, 'same function')
  147. })
  148. test(label + ' – nested date', async ({is, isNot}) => {
  149. const date = new Date()
  150. is(+clone({d: date}).d, +date, 'same value')
  151. isNot(clone({d: date}).d, date, 'different object')
  152. })
  153. test(label + ' – nested date in array', async ({is, isNot}) => {
  154. const date = new Date()
  155. is(+clone({d: [date]}).d[0], +date, 'same value')
  156. isNot(clone({d: [date]}).d[0], date, 'different object')
  157. is(+cloneCircles({d: [date]}).d[0], +date, 'same value')
  158. isNot(cloneCircles({d: [date]}).d, date, 'different object')
  159. })
  160. test(label + ' – nested null', async ({is}) => {
  161. is(clone({n: null}).n, null, 'same value')
  162. })
  163. test(label + ' – arguments', async ({isNot, same}) => {
  164. function fn (...args) {
  165. same(clone(arguments), args, 'same values')
  166. isNot(clone(arguments), arguments, 'different object')
  167. }
  168. fn(1, 2, 3)
  169. })
  170. }