doc_test.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. require 'test_helper'
  2. require 'docs'
  3. class DocsDocTest < MiniTest::Spec
  4. let :doc do
  5. Class.new Docs::Doc do
  6. self.name = 'name'
  7. self.type = 'type'
  8. end
  9. end
  10. let :page do
  11. { path: 'path', store_path: 'store_path', output: 'output', entries: [entry] }
  12. end
  13. let :entry do
  14. Docs::Entry.new 'name', 'path', 'type'
  15. end
  16. let :store do
  17. Docs::NullStore.new
  18. end
  19. describe ".inherited" do
  20. it "sets .type" do
  21. assert_equal doc.type, Class.new(doc).type
  22. end
  23. end
  24. describe ".name" do
  25. it "returns 'Doc' when the class is Docs::Doc" do
  26. assert_equal 'Doc', Docs::Doc.name
  27. end
  28. end
  29. describe ".name=" do
  30. it "stores .name" do
  31. doc.name = 'test'
  32. assert_equal 'test', doc.name
  33. end
  34. end
  35. describe ".slug" do
  36. it "returns 'doc' when the class is Docs::Doc" do
  37. assert_equal 'doc', Docs::Doc.slug
  38. end
  39. it "returns 'doc~4.2_lts' when the class is Docs::Doc and its #version is '42 LTS'" do
  40. stub(Docs::Doc).version { '4.2 LTS' }
  41. assert_equal 'doc~4.2_lts', Docs::Doc.slug
  42. end
  43. it "returns 'foo~42' when #slug has been set to 'foo' and #version to '42'" do
  44. doc.slug = 'foo'
  45. doc.version = '42'
  46. assert_equal 'foo~42', doc.slug
  47. end
  48. it "returns 'foobar' when #name has been set to 'FooBar'" do
  49. doc.name = 'FooBar'
  50. assert_equal 'foobar', doc.slug
  51. end
  52. it "raises error when #name has unsluggable characters" do
  53. assert_raises do
  54. doc.name = 'Foo-Bar'
  55. doc.slug
  56. end
  57. end
  58. end
  59. describe ".slug=" do
  60. it "stores .slug" do
  61. doc.slug = 'test'
  62. assert_equal 'test', doc.slug
  63. end
  64. end
  65. describe ".version=" do
  66. it "stores .version as a string" do
  67. doc.version = 4815162342
  68. assert_equal '4815162342', doc.version
  69. end
  70. end
  71. describe ".release=" do
  72. it "stores .release" do
  73. doc.release = '1'
  74. assert_equal '1', doc.release
  75. end
  76. end
  77. describe ".links=" do
  78. it "stores .links" do
  79. doc.links = { test: true }
  80. assert_equal({ test: true }, doc.links)
  81. end
  82. end
  83. describe ".abstract" do
  84. it "returns nil" do
  85. assert_nil doc.abstract
  86. end
  87. end
  88. describe ".abstract=" do
  89. it "stores .abstract" do
  90. doc.abstract = true
  91. assert doc.abstract
  92. end
  93. end
  94. describe ".path" do
  95. it "returns .slug" do
  96. doc.slug = 'slug'
  97. assert_equal 'slug', doc.path
  98. end
  99. end
  100. describe ".index_path" do
  101. it "returns .path + ::INDEX_FILENAME" do
  102. stub(doc).path { 'path' }
  103. assert_equal File.join('path', Docs::Doc::INDEX_FILENAME), doc.index_path
  104. end
  105. end
  106. describe ".db_path" do
  107. it "returns .path + ::DB_FILENAME" do
  108. stub(doc).path { 'path' }
  109. assert_equal File.join('path', Docs::Doc::DB_FILENAME), doc.db_path
  110. end
  111. end
  112. describe ".meta_path" do
  113. it "returns .path + ::META_FILENAME" do
  114. stub(doc).path { 'path' }
  115. assert_equal File.join('path', Docs::Doc::META_FILENAME), doc.meta_path
  116. end
  117. end
  118. describe ".new" do
  119. it "raises an error when .abstract is true" do
  120. doc.abstract = true
  121. assert_raises NotImplementedError do
  122. doc.new
  123. end
  124. end
  125. end
  126. describe ".as_json" do
  127. it "returns a hash" do
  128. assert_instance_of Hash, doc.as_json
  129. end
  130. it "includes the doc's name, slug, type, version, and release" do
  131. assert_equal %i(name slug type), doc.as_json.keys
  132. %w(name slug type version release links).each do |attribute|
  133. eval "stub(doc).#{attribute} { attribute }"
  134. assert_equal attribute, doc.as_json[attribute.to_sym]
  135. end
  136. end
  137. it "includes the doc's version when it's defined and nil" do
  138. refute doc.as_json.key?(:version)
  139. doc.version = nil
  140. assert doc.as_json.key?(:version)
  141. end
  142. end
  143. describe ".store_page" do
  144. it "builds a page" do
  145. any_instance_of(doc) do |instance|
  146. stub(instance).build_page('id') { @called = true; nil }
  147. end
  148. doc.store_page(store, 'id') {}
  149. assert @called
  150. end
  151. context "when the page builds successfully" do
  152. before do
  153. any_instance_of(doc) do |instance|
  154. stub(instance).build_page { page }
  155. end
  156. end
  157. context "and it has :entries" do
  158. it "returns true" do
  159. assert doc.store_page(store, 'id')
  160. end
  161. it "stores a file" do
  162. mock(store).write(page[:store_path], page[:output])
  163. doc.store_page(store, 'id')
  164. end
  165. it "opens the .path directory before storing the file" do
  166. stub(doc).path { 'path' }
  167. stub(store).write { assert false }
  168. mock(store).open('path') do |_, block|
  169. stub(store).write
  170. block.call
  171. end
  172. doc.store_page(store, 'id')
  173. end
  174. end
  175. context "and it doesn't have :entries" do
  176. before do
  177. page[:entries] = []
  178. end
  179. it "returns false" do
  180. refute doc.store_page(store, 'id')
  181. end
  182. it "doesn't store a file" do
  183. dont_allow(store).write
  184. doc.store_page(store, 'id')
  185. end
  186. end
  187. end
  188. context "when the page doesn't build successfully" do
  189. before do
  190. any_instance_of(doc) do |instance|
  191. stub(instance).build_page { nil }
  192. end
  193. end
  194. it "returns false" do
  195. refute doc.store_page(store, 'id')
  196. end
  197. it "doesn't store a file" do
  198. dont_allow(store).write
  199. doc.store_page(store, 'id')
  200. end
  201. end
  202. end
  203. describe ".store_pages" do
  204. it "build the pages" do
  205. any_instance_of(doc) do |instance|
  206. stub(instance).build_pages { @called = true }
  207. end
  208. doc.store_pages(store) {}
  209. assert @called
  210. end
  211. context "when pages are built successfully" do
  212. let :pages do
  213. [
  214. page.deep_dup.tap { |p| page[:entries].first.tap { |e| e.name = 'one' } },
  215. page.deep_dup.tap { |p| page[:entries].first.tap { |e| e.name = 'two' } }
  216. ]
  217. end
  218. before do
  219. any_instance_of(doc) do |instance|
  220. stub(instance).build_pages { |block| pages.each(&block) }
  221. end
  222. end
  223. context "and at least one page has :entries" do
  224. it "returns true" do
  225. assert doc.store_pages(store)
  226. end
  227. it "stores a file for each page that has :entries" do
  228. pages.first.merge!(entries: [], output: '')
  229. mock(store).write(page[:store_path], page[:output])
  230. mock(store).write('index.json', anything)
  231. mock(store).write('db.json', anything)
  232. mock(store).write('meta.json', anything)
  233. doc.store_pages(store)
  234. end
  235. it "stores an index that contains all the pages' entries" do
  236. stub(store).write(page[:store_path], page[:output])
  237. stub(store).write('db.json', anything)
  238. stub(store).write('meta.json', anything)
  239. mock(store).write('index.json', anything) do |path, json|
  240. json = JSON.parse(json)
  241. assert_equal pages.length, json['entries'].length
  242. assert_includes json['entries'], Docs::Entry.new('one', 'path', 'type').as_json.stringify_keys
  243. end
  244. doc.store_pages(store)
  245. end
  246. it "stores a db that contains all the pages, indexed by path" do
  247. stub(store).write(page[:store_path], page[:output])
  248. stub(store).write('index.json', anything)
  249. stub(store).write('meta.json', anything)
  250. mock(store).write('db.json', anything) do |path, json|
  251. json = JSON.parse(json)
  252. assert_equal page[:output], json[page[:path]]
  253. end
  254. doc.store_pages(store)
  255. end
  256. it "stores a meta file that contains the doc's metadata" do
  257. stub(store).write(page[:store_path], page[:output])
  258. stub(store).write('index.json', anything)
  259. stub(store).write('db.json', anything)
  260. mock(store).write('meta.json', anything) do |path, json|
  261. json = JSON.parse(json)
  262. assert_equal %w(name slug type mtime db_size).sort, json.keys.sort
  263. end
  264. doc.store_pages(store)
  265. end
  266. it "replaces the .path directory before storing the files" do
  267. stub(doc).path { 'path' }
  268. stub(store).write { assert false }
  269. mock(store).replace('path') do |_, block|
  270. stub(store).write
  271. block.call
  272. end
  273. doc.store_pages(store)
  274. end
  275. end
  276. context "and no pages have :entries" do
  277. before do
  278. pages.each { |page| page[:entries] = [] }
  279. end
  280. it "returns false" do
  281. refute doc.store_pages(store)
  282. end
  283. it "doesn't store files" do
  284. dont_allow(store).write
  285. doc.store_pages(store)
  286. end
  287. end
  288. end
  289. context "when no pages are built successfully" do
  290. before do
  291. any_instance_of(doc) do |instance|
  292. stub(instance).build_pages
  293. end
  294. end
  295. it "returns false" do
  296. refute doc.store_pages(store)
  297. end
  298. it "doesn't store files" do
  299. dont_allow(store).write
  300. doc.store_pages(store)
  301. end
  302. end
  303. end
  304. describe ".versions" do
  305. it "returns [self] if no versions have been created" do
  306. assert_equal [doc], doc.versions
  307. end
  308. end
  309. describe ".version" do
  310. context "with no args" do
  311. it "returns @version by default" do
  312. doc.version = 'v'
  313. assert_equal 'v', doc.version
  314. end
  315. end
  316. context "with args" do
  317. it "creates a version subclass" do
  318. version = doc.version('4') { self.release = '8'; self.links = ["https://#{self.version}"] }
  319. assert_equal [version], doc.versions
  320. assert_nil doc.version
  321. assert_nil doc.release
  322. refute doc.version?
  323. assert version.version?
  324. assert_equal '4', version.version
  325. assert_equal '8', version.release
  326. assert_equal 'name', version.name
  327. assert_equal 'type', version.type
  328. assert_equal ['https://4'], version.links
  329. end
  330. end
  331. it "compares versions" do
  332. instance = doc.versions.first.new
  333. assert_equal "Up-to-date", instance.outdated_state('0.0.2', '0.0.3')
  334. assert_equal "Outdated major version", instance.outdated_state('0.2', '0.3')
  335. assert_equal 'Up-to-date', instance.outdated_state('1', '1')
  336. assert_equal 'Up-to-date', instance.outdated_state('1.2', '1.2')
  337. assert_equal 'Up-to-date', instance.outdated_state('1.2.2', '1.2.2')
  338. assert_equal 'Up-to-date', instance.outdated_state('1.2.2', '1.2.3')
  339. assert_equal "Outdated major version", instance.outdated_state('1', '2')
  340. assert_equal "Up-to-date", instance.outdated_state('1.0.2', '1.0.3')
  341. assert_equal "Outdated major version", instance.outdated_state('1.2', '1.3')
  342. assert_equal "Outdated minor version", instance.outdated_state('2.2', '2.3')
  343. assert_equal "Outdated major version", instance.outdated_state('9', '10')
  344. assert_equal "Outdated major version", instance.outdated_state('99', '101')
  345. assert_equal 'Up-to-date', instance.outdated_state('2006-01-02', '2006-01-03')
  346. assert_equal "Outdated minor version", instance.outdated_state('2006-01-02', '2006-02-03')
  347. end
  348. end
  349. end