validate-projection-schema.spec.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import {expect} from 'chai';
  2. import {format} from '@e22m4u/js-format';
  3. import {validateProjectionSchema} from './validate-projection-schema.js';
  4. describe('validateProjectionSchema', function () {
  5. it('should require the "shallowMode" argument to be a Boolean', function () {
  6. const throwable = v => () => validateProjectionSchema({}, v);
  7. const error = s =>
  8. format('Argument "shallowMode" must be a Boolean, but %s was given.', s);
  9. expect(throwable('str')).to.throw(error('"str"'));
  10. expect(throwable('')).to.throw(error('""'));
  11. expect(throwable(10)).to.throw(error('10'));
  12. expect(throwable(0)).to.throw(error('0'));
  13. expect(throwable([])).to.throw(error('Array'));
  14. expect(throwable({})).to.throw(error('Object'));
  15. expect(throwable(null)).to.throw(error('null'));
  16. expect(throwable(() => undefined)).to.throw(error('Function'));
  17. throwable(true)();
  18. throwable(false)();
  19. throwable(undefined)();
  20. });
  21. it('should require the "validatedSchemas" argument to be a Set instance', function () {
  22. const throwable = v => () => validateProjectionSchema({}, false, v);
  23. const error = s =>
  24. format(
  25. 'Argument "validatedSchemas" must be ' +
  26. 'an instance of Set, but %s was given.',
  27. s,
  28. );
  29. expect(throwable('str')).to.throw(error('"str"'));
  30. expect(throwable('')).to.throw(error('""'));
  31. expect(throwable(10)).to.throw(error('10'));
  32. expect(throwable(0)).to.throw(error('0'));
  33. expect(throwable(true)).to.throw(error('true'));
  34. expect(throwable(false)).to.throw(error('false'));
  35. expect(throwable([])).to.throw(error('Array'));
  36. expect(throwable({})).to.throw(error('Object'));
  37. expect(throwable(null)).to.throw(error('null'));
  38. expect(throwable(() => undefined)).to.throw(error('Function'));
  39. throwable(new Set())();
  40. throwable(undefined)();
  41. });
  42. it('should skip validation if the given schema is already validated', function () {
  43. const validatedSchemas = new Set();
  44. const schema = {foo: 10};
  45. validatedSchemas.add(schema);
  46. validateProjectionSchema(schema, false, validatedSchemas);
  47. });
  48. it('should require the "schema" argument to be a valid value', function () {
  49. const throwable = v => () => validateProjectionSchema(v);
  50. const error = s =>
  51. format(
  52. 'Projection schema must be an Object, a Function ' +
  53. 'or a non-empty String, but %s was given.',
  54. s,
  55. );
  56. expect(throwable('')).to.throw(error('""'));
  57. expect(throwable(10)).to.throw(error('10'));
  58. expect(throwable(0)).to.throw(error('0'));
  59. expect(throwable(true)).to.throw(error('true'));
  60. expect(throwable(false)).to.throw(error('false'));
  61. expect(throwable([])).to.throw(error('Array'));
  62. expect(throwable(undefined)).to.throw(error('undefined'));
  63. expect(throwable(null)).to.throw(error('null'));
  64. throwable('str')();
  65. throwable({})();
  66. throwable(() => ({}))();
  67. });
  68. it('should require property options to be an object or a boolean', function () {
  69. const throwable = v => () => validateProjectionSchema({foo: v});
  70. const error = s =>
  71. format(
  72. 'Property options must be an Object or a Boolean, but %s was given.',
  73. s,
  74. );
  75. expect(throwable('str')).to.throw(error('"str"'));
  76. expect(throwable('')).to.throw(error('""'));
  77. expect(throwable(10)).to.throw(error('10'));
  78. expect(throwable(0)).to.throw(error('0'));
  79. expect(throwable([])).to.throw(error('Array'));
  80. expect(throwable(null)).to.throw(error('null'));
  81. expect(throwable(() => ({}))).to.throw(error('Function'));
  82. throwable({})();
  83. throwable(true)();
  84. throwable(false)();
  85. throwable(undefined)();
  86. });
  87. it('should require the "select" option to be a boolean', function () {
  88. const throwable = v => () => validateProjectionSchema({foo: {select: v}});
  89. const error = s =>
  90. format(
  91. 'Property option "select" must be a Boolean, but %s was given.',
  92. s,
  93. );
  94. expect(throwable('str')).to.throw(error('"str"'));
  95. expect(throwable('')).to.throw(error('""'));
  96. expect(throwable(10)).to.throw(error('10'));
  97. expect(throwable(0)).to.throw(error('0'));
  98. expect(throwable({})).to.throw(error('Object'));
  99. expect(throwable([])).to.throw(error('Array'));
  100. expect(throwable(null)).to.throw(error('null'));
  101. expect(throwable(() => ({}))).to.throw(error('Function'));
  102. throwable(true)();
  103. throwable(false)();
  104. throwable(undefined)();
  105. });
  106. it('should require the "scopes" option to be an object', function () {
  107. const throwable = v => () => validateProjectionSchema({foo: {scopes: v}});
  108. const error = s =>
  109. format(
  110. 'Property option "scopes" must be an Object, but %s was given.',
  111. s,
  112. );
  113. expect(throwable('str')).to.throw(error('"str"'));
  114. expect(throwable('')).to.throw(error('""'));
  115. expect(throwable(10)).to.throw(error('10'));
  116. expect(throwable(0)).to.throw(error('0'));
  117. expect(throwable(true)).to.throw(error('true'));
  118. expect(throwable(false)).to.throw(error('false'));
  119. expect(throwable([])).to.throw(error('Array'));
  120. expect(throwable(null)).to.throw(error('null'));
  121. expect(throwable(() => ({}))).to.throw(error('Function'));
  122. throwable({})();
  123. throwable(undefined)();
  124. });
  125. it('should require the scope options to be an object or a boolean', function () {
  126. const throwable = v => () =>
  127. validateProjectionSchema({foo: {scopes: {input: v}}});
  128. const error = s =>
  129. format(
  130. 'Scope options must be an Object or a Boolean, but %s was given.',
  131. s,
  132. );
  133. expect(throwable('str')).to.throw(error('"str"'));
  134. expect(throwable('')).to.throw(error('""'));
  135. expect(throwable(10)).to.throw(error('10'));
  136. expect(throwable(0)).to.throw(error('0'));
  137. expect(throwable([])).to.throw(error('Array'));
  138. expect(throwable(null)).to.throw(error('null'));
  139. expect(throwable(() => ({}))).to.throw(error('Function'));
  140. throwable({})();
  141. throwable(true)();
  142. throwable(false)();
  143. throwable(undefined)();
  144. });
  145. it('should require the "select" option of scope to be a boolean', function () {
  146. const throwable = v => () =>
  147. validateProjectionSchema({foo: {scopes: {input: {select: v}}}});
  148. const error = s =>
  149. format('Scope option "select" must be a Boolean, but %s was given.', s);
  150. expect(throwable('str')).to.throw(error('"str"'));
  151. expect(throwable('')).to.throw(error('""'));
  152. expect(throwable(10)).to.throw(error('10'));
  153. expect(throwable(0)).to.throw(error('0'));
  154. expect(throwable({})).to.throw(error('Object'));
  155. expect(throwable([])).to.throw(error('Array'));
  156. expect(throwable(null)).to.throw(error('null'));
  157. expect(throwable(() => ({}))).to.throw(error('Function'));
  158. throwable(true)();
  159. throwable(false)();
  160. throwable(undefined)();
  161. });
  162. it('should require the "schema" option to be a valid value', function () {
  163. const throwable = v => () => validateProjectionSchema({foo: {schema: v}});
  164. const error = s =>
  165. format(
  166. 'Property option "schema" must be an Object, a Function ' +
  167. 'or a non-empty String, but %s was given.',
  168. s,
  169. );
  170. expect(throwable('')).to.throw(error('""'));
  171. expect(throwable(10)).to.throw(error('10'));
  172. expect(throwable(0)).to.throw(error('0'));
  173. expect(throwable(true)).to.throw(error('true'));
  174. expect(throwable(false)).to.throw(error('false'));
  175. expect(throwable([])).to.throw(error('Array'));
  176. expect(throwable(null)).to.throw(error('null'));
  177. throwable('str')();
  178. throwable({})();
  179. throwable(() => ({}))();
  180. throwable(undefined)();
  181. });
  182. it('should validate the embedded schema', function () {
  183. const throwable = () =>
  184. validateProjectionSchema({foo: {schema: {bar: 10}}});
  185. expect(throwable).to.throw(
  186. 'Property options must be an Object or a Boolean, but 10 was given.',
  187. );
  188. });
  189. it('should validate the given schema in the shallow mode', function () {
  190. const throwable = () => validateProjectionSchema({foo: 10}, true);
  191. expect(throwable).to.throw(
  192. 'Property options must be an Object or a Boolean, but 10 was given.',
  193. );
  194. });
  195. it('should skip embedded schema validation in the shallow mode', function () {
  196. validateProjectionSchema({foo: {schema: {bar: 10}}}, true);
  197. });
  198. it('should allow circular schema validation', function () {
  199. const schemaA = {foo: {select: true}};
  200. const schemaB = {bar: {select: true}};
  201. schemaA.foo.schema = schemaB;
  202. schemaB.bar.schema = schemaA;
  203. validateProjectionSchema(schemaA);
  204. });
  205. it('should allow circular schema validation in the shallow mode', function () {
  206. const schemaA = {foo: {select: true}};
  207. const schemaB = {bar: {select: true}};
  208. schemaA.foo.schema = schemaB;
  209. schemaB.bar.schema = schemaA;
  210. validateProjectionSchema(schemaA, true);
  211. });
  212. });