test.mock.spec.dtd.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /* global require, chai, describe, before, it */
  2. // 数据模板定义(Data Temaplte Definition,DTD)
  3. /*
  4. ## BDD
  5. 1. 结构
  6. describe suite
  7. [ describe ]
  8. before after beforeEach afterEach
  9. it test
  10. done
  11. 搜索 this.async = fn && fn.length
  12. 2. 常用 expect
  13. expect().to
  14. .equal .deep.equal .not.equal
  15. .match
  16. .have.length .with.length
  17. .have.property .have.deep.property
  18. .to.be.a .to.be.an
  19. .that
  20. .least .most .within
  21. 3. 速度
  22. 搜索 test.speed
  23. slow > 75
  24. 75 / 2 < medium < 75
  25. fast < 75 / 2
  26. */
  27. var expect = chai.expect
  28. var Mock, $, _
  29. describe('DTD', function() {
  30. before(function(done) {
  31. require(['mock', 'underscore', 'jquery'], function() {
  32. Mock = arguments[0]
  33. _ = arguments[1]
  34. $ = arguments[2]
  35. expect(Mock).to.not.equal(undefined)
  36. expect(_).to.not.equal(undefined)
  37. expect($).to.not.equal(undefined)
  38. done()
  39. })
  40. })
  41. describe('Literal', function() {
  42. it('', function() {
  43. var data = Mock.mock(this.test.title)
  44. expect(data).to.equal(this.test.title)
  45. })
  46. it('foo', function() {
  47. var data = Mock.mock(this.test.title)
  48. expect(data).to.equal(this.test.title)
  49. })
  50. it(1, function() {
  51. var data = Mock.mock(this.test.title)
  52. expect(data).to.equal(this.test.title)
  53. })
  54. it(true, function() {
  55. var data = Mock.mock(this.test.title)
  56. expect(data).to.equal(this.test.title)
  57. })
  58. it(false, function() {
  59. var data = Mock.mock(this.test.title)
  60. expect(data).to.equal(this.test.title)
  61. })
  62. it({}, function() {
  63. var data = Mock.mock(this.test.title)
  64. expect(data).to.deep.equal(this.test.title)
  65. })
  66. it([], function() {
  67. var data = Mock.mock(this.test.title)
  68. expect(data).to.deep.equal(this.test.title)
  69. })
  70. it(function() {}, function() {
  71. var data = Mock.mock(this.test.title)
  72. expect(data).to.equal(undefined)
  73. })
  74. })
  75. describe('String', function() {
  76. // `'name|min-max': 'value'`
  77. it('name|min-max', function() {
  78. var data = Mock.mock({
  79. 'name|1-10': '★号'
  80. })
  81. expect(data.name).to.have.length.within(2, 20)
  82. })
  83. // `'name|count': 'value'`
  84. it('name|count', function() {
  85. var data = Mock.mock({
  86. 'name|10': '★号'
  87. })
  88. expect(data.name).to.be.a('string')
  89. .that.have.length(20)
  90. })
  91. })
  92. describe('Number', function() {
  93. // `'name|+step': value`
  94. it('name|+step', function() {
  95. var data = Mock.mock({
  96. 'list|10': [{
  97. 'name|+1': 100
  98. }]
  99. })
  100. expect(data.list).to.be.an('array').with.length(10)
  101. _.each(data.list, function(item, index) {
  102. expect(item).to.have.property('name')
  103. .that.be.a('number')
  104. if (index === 0) expect(item.name).to.equal(100)
  105. else expect(item.name).to.equal(
  106. data.list[index - 1].name + 1
  107. )
  108. })
  109. })
  110. // `'name|min-max': value`
  111. it('name|min-max', function() {
  112. var data = Mock.mock({
  113. 'name|1-100': 100
  114. })
  115. expect(data).to.have.property('name')
  116. .that.be.a('number').within(1, 100)
  117. })
  118. it('name|max-min', function() {
  119. var data = Mock.mock({
  120. 'name|100-1': 100
  121. })
  122. expect(data).to.have.property('name')
  123. .that.be.a('number').within(1, 100)
  124. })
  125. it('name|-min--max', function() {
  126. var data = Mock.mock({
  127. 'name|-100--1': 100
  128. })
  129. expect(data).to.have.property('name')
  130. .that.be.a('number').within(-100, -1)
  131. })
  132. it('name|-max--min', function() {
  133. var data = Mock.mock({
  134. 'name|-1--100': 100
  135. })
  136. expect(data).to.have.property('name')
  137. .that.be.a('number').within(-100, -1)
  138. })
  139. it('name|min-min', function() {
  140. var data = Mock.mock({
  141. 'name|10-10': 100
  142. })
  143. expect(data).to.have.property('name')
  144. .that.be.a('number').equal(10)
  145. })
  146. it('name|count', function() {
  147. var data = Mock.mock({
  148. 'name|10': 100
  149. })
  150. expect(data).to.have.property('name')
  151. .that.be.a('number').equal(10)
  152. })
  153. // `'name|min-max.dmin-dmax': value`
  154. // 1 整数部分 2 小数部分
  155. var RE_FLOAT = /([\+\-]?\d+)\.?(\d+)?/
  156. function validNumber(number, min, max, dmin, dmax) {
  157. expect(number).to.be.a('number')
  158. RE_FLOAT.lastIndex = 0
  159. var parts = RE_FLOAT.exec('' + number)
  160. expect(+parts[1]).to.be.a('number').within(min, max)
  161. expect(parts[2]).to.have.length.within(dmin, dmax)
  162. }
  163. it('name|min-max.dmin-dmax', function() {
  164. var data = Mock.mock({
  165. 'name|1-10.1-10': 123.456
  166. })
  167. validNumber(data.name, 1, 10, 1, 10)
  168. })
  169. it('name|min-max.dcount', function() {
  170. var data = Mock.mock({
  171. 'name|1-10.10': 123.456
  172. })
  173. validNumber(data.name, 1, 10, 10, 10)
  174. })
  175. it('name|count.dmin-dmax', function() {
  176. var data = Mock.mock({
  177. 'name|10.1-10': 123.456
  178. })
  179. validNumber(data.name, 10, 10, 1, 10)
  180. })
  181. it('name|count.dcount', function() {
  182. var data = Mock.mock({
  183. 'name|10.10': 123.456
  184. })
  185. validNumber(data.name, 10, 10, 10, 10)
  186. })
  187. it('name|.dmin-dmax', function() {
  188. var data = Mock.mock({
  189. 'name|.1-10': 123.456
  190. })
  191. validNumber(data.name, 123, 123, 1, 10)
  192. })
  193. it('name|.dcount', function() {
  194. var data = Mock.mock({
  195. 'name|.10': 123.456
  196. })
  197. validNumber(data.name, 123, 123, 10, 10)
  198. })
  199. })
  200. describe('Boolean', function() {
  201. // `'name|1': value`
  202. it('name|1', function() {
  203. var data = Mock.mock({
  204. 'name|1': true
  205. })
  206. expect(data).to.have.property('name')
  207. .that.be.a('boolean')
  208. })
  209. // `'name|min-max': value`
  210. it('name|min-max', function() {
  211. var data = Mock.mock({
  212. 'name|8-2': true
  213. })
  214. expect(data).to.have.property('name')
  215. .that.be.a('boolean')
  216. })
  217. })
  218. describe('Object', function() {
  219. var methods = {
  220. GET: '@URL',
  221. POST: '@URL',
  222. HEAD: '@URL',
  223. PUT: '@URL',
  224. DELETE: '@URL'
  225. }
  226. var methodCount, tpl, data
  227. // `'name|min-max': {}`
  228. it('name|min-max', function() {
  229. methodCount = _.keys(methods).length // 5
  230. for (var min = 0, max; min <= methodCount + 1; min++) {
  231. tpl = {}
  232. max = Mock.Random.integer(0, methodCount)
  233. // methods|0-? |1-? |2-? |3-? |4-? |5-? |6-?
  234. tpl['methods|' + min + '-' + max] = methods
  235. data = Mock.mock(tpl)
  236. expect(_.keys(data.methods)).to.have.length
  237. .that.within(Math.min(min, max), Math.max(min, max))
  238. }
  239. })
  240. // `'name|count': {}`
  241. it('name|count', function() {
  242. methodCount = _.keys(methods).length // 5
  243. for (var count = 0; count <= methodCount + 1; count++) {
  244. tpl = {}
  245. tpl['methods|' + count] = methods
  246. data = Mock.mock(tpl)
  247. expect(_.keys(data.methods)).to.have.length(
  248. Math.min(count, methodCount)
  249. )
  250. }
  251. })
  252. })
  253. describe('Array', function() {
  254. // `'name': [{}, {} ...]`
  255. it('name', function() {
  256. var value = [{
  257. foo: 'foo'
  258. }, {
  259. bar: 'bar'
  260. }, {
  261. foobar: 'foobar'
  262. }]
  263. var data = Mock.mock({
  264. name: value
  265. })
  266. expect(data).to.have.property('name')
  267. .that.be.an('array').with.length(3)
  268. .that.not.equal(value)
  269. expect(data).to.have.property('name')
  270. for (var i = 0; i < data.name.length; i++) {
  271. expect(data.name[i]).to.not.equal(value[i])
  272. expect(data.name[i]).to.deep.equal(value[i])
  273. }
  274. })
  275. // `'name|1': [{}, {} ...]`
  276. it('name|1: [1, 2, 4, 8]', function() {
  277. // number array
  278. var value = [1, 2, 4, 8]
  279. var data = Mock.mock({
  280. 'name|1': value
  281. })
  282. expect(data).to.have.property('name')
  283. .that.be.a('number')
  284. expect(value).to.include(data.name)
  285. })
  286. it('name|1: ["GET", "POST", "HEAD", "DELETE"]', function() {
  287. // string array
  288. var value = ['GET', 'POST', 'HEAD', 'DELETE']
  289. var data = Mock.mock({
  290. 'name|1': value
  291. })
  292. expect(data).to.have.property('name')
  293. .that.be.a('string')
  294. expect(value).to.include(data.name)
  295. })
  296. it('name|1 [{}]', function() {
  297. // object array
  298. var value = [{}]
  299. var data = Mock.mock({
  300. 'name|1': value
  301. })
  302. expect(data).to.have.property('name')
  303. .that.be.a('object')
  304. .that.deep.equal({})
  305. expect(data.name).to.not.equal(value[0])
  306. })
  307. it('name|1 [{}, {}, {}]', function() {
  308. // object array
  309. var data = Mock.mock({
  310. 'name|1': [{}, {}, {}]
  311. })
  312. expect(data).to.have.property('name')
  313. .that.be.a('object')
  314. .that.deep.equal({})
  315. })
  316. it('name|1 [{}, {}, {}]', function() {
  317. // object array
  318. var value = [{
  319. method: 'GET'
  320. }, {
  321. method: 'POST'
  322. }, {
  323. method: 'HEAD'
  324. }, {
  325. method: 'DELETE'
  326. }]
  327. var data = Mock.mock({
  328. 'name|1': value
  329. })
  330. expect(data).to.have.property('name')
  331. .that.be.a('object')
  332. .that.have.property('method')
  333. .that.be.a('string')
  334. expect(_.pluck(value, 'method')).include(data.name.method)
  335. })
  336. // `'name|+1': [{}, {} ...]`
  337. it('name|+1: ["a", "b", "c"]', function() {
  338. var data = Mock.mock({
  339. 'list|5': [{
  340. 'name|+1': ['a', 'b', 'c']
  341. }]
  342. })
  343. expect(data).to.have.property('list')
  344. .that.be.an('array').with.length(5)
  345. expect(data.list[0].name).to.equal('a')
  346. expect(data.list[1].name).to.equal('b')
  347. expect(data.list[2].name).to.equal('c')
  348. expect(data.list[3].name).to.equal('a')
  349. expect(data.list[4].name).to.equal('b')
  350. })
  351. it('name|+1: ["@integer", "@email", "@boolean"]', function() {
  352. var data = Mock.mock({
  353. 'list|5-10': [{
  354. 'name|+1': ['@integer', '@email', '@boolean']
  355. }]
  356. })
  357. expect(data).to.have.property('list')
  358. .that.be.an('array').have.length.within(5, 10)
  359. expect(data.list[0].name).to.be.a('number')
  360. expect(data.list[1].name).to.be.a('string')
  361. expect(data.list[2].name).to.be.a('boolean')
  362. expect(data.list[3].name).to.be.a('number')
  363. expect(data.list[4].name).to.be.a('string')
  364. })
  365. // `'name|min-max': [{}, {} ...]`
  366. it('name|min-min', function() {
  367. var data = Mock.mock({
  368. 'name|1-1': [{}]
  369. })
  370. expect(data.name).to.be.an('array').with.length(1)
  371. _.each(data.name, function(item /*, index*/ ) {
  372. expect(item).to.deep.equal({})
  373. })
  374. })
  375. it('name|min-max [{}]', function() {
  376. var data = Mock.mock({
  377. 'name|1-10': [{}]
  378. })
  379. expect(data.name).to.be.an('array').with.length.within(1, 10)
  380. _.each(data.name, function(item /*, index*/ ) {
  381. expect(item).to.deep.equal({})
  382. })
  383. })
  384. it('name|max-min [{}]', function() {
  385. var data = Mock.mock({
  386. 'name|10-1': [{}]
  387. })
  388. expect(data.name).to.be.an('array').with.length.within(1, 10)
  389. _.each(data.name, function(item /*, index*/ ) {
  390. expect(item).to.deep.equal({})
  391. })
  392. })
  393. it('name|min-max [{}, {}]', function() {
  394. var data = Mock.mock({
  395. 'name|1-10': [{}, {}]
  396. })
  397. expect(data.name).to.be.an('array').with.length.within(2, 20)
  398. _.each(data.name, function(item /*, index*/ ) {
  399. expect(item).to.deep.equal({})
  400. })
  401. })
  402. it('name|max-min [{}, {}]', function() {
  403. var data = Mock.mock({
  404. 'name|10-1': [{}, {}]
  405. })
  406. expect(data.name).to.be.an('array').with.length.within(2, 20)
  407. _.each(data.name, function(item /*, index*/ ) {
  408. expect(item).to.deep.equal({})
  409. })
  410. })
  411. // `'name|count': [{}, {} ...]`
  412. it('name|count [{}]', function() {
  413. var data = Mock.mock({
  414. 'name|10': [{}]
  415. })
  416. expect(data.name).to.be.an('array').with.length(10)
  417. _.each(data.name, function(item /*, index*/ ) {
  418. expect(item).to.deep.equal({})
  419. })
  420. })
  421. it('name|count [{}, {}]', function() {
  422. var data = Mock.mock({
  423. 'name|10': [{}, {}]
  424. })
  425. expect(data.name).to.be.an('array').with.length(20)
  426. _.each(data.name, function(item /*, index*/ ) {
  427. expect(item).to.deep.equal({})
  428. })
  429. })
  430. })
  431. describe('Function', function() {
  432. // `'name': function(){}`
  433. it('name: function', function() {
  434. var data = Mock.mock({
  435. prop: 'hello',
  436. name: function( /*root, path*/ ) {
  437. return this.prop
  438. }
  439. })
  440. expect(data).to.have.property('name')
  441. .that.be.a('string').equal('hello')
  442. })
  443. // 无序的 function
  444. it('name: function', function() {
  445. var data = Mock.mock({
  446. name2: function() {
  447. return this.prop * 2
  448. },
  449. prop: 1,
  450. name4: function() {
  451. return this.prop * 4
  452. }
  453. })
  454. expect(data.name2).to.equal(2)
  455. expect(data.name4).to.equal(4)
  456. })
  457. // #25 改变了非函数属性的顺序,查找起来不方便
  458. it('name: function', function() {
  459. var data = Mock.mock({
  460. name: function() {},
  461. first: '',
  462. second: '',
  463. third: ''
  464. })
  465. var keys = _.keys(data)
  466. expect(keys[0]).equal('first')
  467. expect(keys[1]).equal('second')
  468. expect(keys[2]).equal('third')
  469. expect(keys[3]).equal('name')
  470. })
  471. })
  472. /*
  473. 按照 http://www.regexr.com/ 的 Reference 设计测试用例。
  474. https://github.com/nuysoft/Mock/blob/7c1e3a686bcc515855f1f583d70ae0ee89acc65e/test/regexp.js#L120
  475. */
  476. describe('RegExp', function() {
  477. function validRegExp(regexp) {
  478. if (arguments.length > 1) {
  479. for (var i = 0; i < arguments.length; i++) {
  480. validRegExp(arguments[i])
  481. }
  482. }
  483. it(regexp, function() {
  484. var data = Mock.mock(regexp)
  485. this.test.title += ' => ' + data
  486. expect(regexp.test(data)).to.be.true
  487. })
  488. }
  489. describe('Character Classes', function() {
  490. validRegExp(/./)
  491. validRegExp(
  492. /[a-z]/,
  493. /[A-Z]/,
  494. /[0-9]/
  495. )
  496. validRegExp(
  497. /\w/,
  498. /\W/,
  499. /\s/,
  500. /\S/,
  501. /\d/,
  502. /\D/
  503. )
  504. validRegExp(
  505. /[.]/,
  506. /[\w]/,
  507. /[\W]/,
  508. /[\s]/,
  509. /[\S]/,
  510. /[\d]/,
  511. /[\D]/
  512. )
  513. validRegExp(
  514. /[^.]/,
  515. /[^\w]/,
  516. /[^\W]/,
  517. /[^\s]/,
  518. /[^\S]/,
  519. /[^\d]/,
  520. /[^\D]/
  521. )
  522. })
  523. describe('Quantifiers', function() {
  524. validRegExp(
  525. /\d?/,
  526. /\d+/,
  527. /\d*/
  528. )
  529. // {n}, {n,}, {n,m}, {0,1} ?, {1,0} +, {0,} *
  530. validRegExp(
  531. /\d{5}/,
  532. /\d{5,}/,
  533. /\d{5,10}/,
  534. /\d{0,1}/,
  535. /\d{0,}/
  536. )
  537. validRegExp(/[\u4E00-\u9FA5]+/) // 汉字
  538. })
  539. describe('Anchors', function() {
  540. validRegExp(/^/)
  541. validRegExp(/$/)
  542. validRegExp(/^foo/)
  543. validRegExp(/foo$/)
  544. validRegExp(/\bfoo/)
  545. validRegExp(/\Bfoo/)
  546. })
  547. describe('Escaped Characters', function() {
  548. validRegExp(/\000/)
  549. validRegExp(/\xFF/)
  550. validRegExp(/\uFFFF/)
  551. validRegExp(/\cI/)
  552. })
  553. describe('Groups & Lookaround', function() {
  554. validRegExp(/(ABC)/)
  555. validRegExp(/(ABC)\1/)
  556. validRegExp(/(?:ABC)/)
  557. validRegExp(/(?=ABC)/)
  558. validRegExp(/(?!ABC)/)
  559. // validRegExp(/(?<=ABC)/)
  560. // validRegExp(/(?<!ABC)/)
  561. validRegExp(/(\d{5,10})|([a-zA-Z]{5,10})/)
  562. validRegExp(/(?:\d{5,10})|(?:[a-zA-Z]{5,10})/)
  563. validRegExp(/(.)(\w)(\W)(\s)(\S)(\d)(\D),\1\2\3\4\5\6\7,\1\2\3\4\5\6\7/)
  564. })
  565. describe('Quantifiers & Alternation', function() {
  566. validRegExp(/.+/)
  567. validRegExp(/.*/)
  568. validRegExp(/.{1,3}/)
  569. validRegExp(/.?/)
  570. validRegExp(/a|bc/)
  571. validRegExp(/\d{5,10}|[a-zA-Z]{5,10}/)
  572. })
  573. describe('Flags', function() {
  574. // ignoreCase
  575. // multiline
  576. // global
  577. })
  578. })
  579. describe('Complex', function() {
  580. var tpl = {
  581. 'title': 'Syntax Demo',
  582. 'string1|1-10': '★',
  583. 'string2|3': 'value',
  584. 'number1|+1': 100,
  585. 'number2|1-100': 100,
  586. 'number3|1-100.1-10': 1,
  587. 'number4|123.1-10': 1,
  588. 'number5|123.3': 1,
  589. 'number6|123.10': 1.123,
  590. 'boolean1|1': true,
  591. 'boolean2|1-2': true,
  592. 'object1|2-4': {
  593. '110000': '北京市',
  594. '120000': '天津市',
  595. '130000': '河北省',
  596. '140000': '山西省'
  597. },
  598. 'object2|2': {
  599. '310000': '上海市',
  600. '320000': '江苏省',
  601. '330000': '浙江省',
  602. '340000': '安徽省'
  603. },
  604. 'array1|1': ['AMD', 'CMD', 'KMD', 'UMD'],
  605. 'array2|1-10': ['Mock.js'],
  606. 'array3|3': ['Mock.js'],
  607. 'array4|1-10': [{
  608. 'name|+1': ['Hello', 'Mock.js', '!']
  609. }],
  610. 'function': function() {
  611. return this.title
  612. },
  613. 'regexp1': /[a-z][A-Z][0-9]/,
  614. 'regexp2': /\w\W\s\S\d\D/,
  615. 'regexp3': /\d{5,10}/,
  616. 'nested': {
  617. a: {
  618. b: {
  619. c: 'Mock.js'
  620. }
  621. }
  622. },
  623. 'absolutePath': '@/title @/nested/a/b/c',
  624. 'relativePath': {
  625. a: {
  626. b: {
  627. c: '@../../../nested/a/b/c'
  628. }
  629. }
  630. },
  631. }
  632. it('', function() {
  633. var data = Mock.mock(tpl)
  634. this.test.title += JSON.stringify(data /*, null, 4*/ )
  635. expect(data).to.be.a('object')
  636. })
  637. })
  638. })