has_groups_examples.rb 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. # Requires: let(:group_access_instance) { ... }
  2. # Requires: let(:new_group_access_instance) { ... }
  3. RSpec.shared_examples 'HasGroups' do
  4. context 'group' do
  5. let(:group_access_instance_inactive) do
  6. group_access_instance.update!(active: false)
  7. group_access_instance
  8. end
  9. let(:group_full) { create(:group) }
  10. let(:group_read) { create(:group) }
  11. let(:group_inactive) { create(:group, active: false) }
  12. context '.group_through_identifier' do
  13. it 'responds to group_through_identifier' do
  14. expect(described_class).to respond_to(:group_through_identifier)
  15. end
  16. it 'returns a Symbol as identifier' do
  17. expect(described_class.group_through_identifier).to be_a(Symbol)
  18. end
  19. it 'instance responds to group_through_identifier method' do
  20. expect(group_access_instance).to respond_to(described_class.group_through_identifier)
  21. end
  22. end
  23. context '.group_through' do
  24. it 'responds to group_through' do
  25. expect(described_class).to respond_to(:group_through)
  26. end
  27. it 'returns the Reflection instance of the has_many :through relation' do
  28. expect(described_class.group_through).to be_a(ActiveRecord::Reflection::HasManyReflection)
  29. end
  30. end
  31. context '#groups' do
  32. it 'responds to groups' do
  33. expect(group_access_instance).to respond_to(:groups)
  34. end
  35. context '#groups.access' do
  36. it 'responds to groups.access' do
  37. expect(group_access_instance.groups).to respond_to(:access)
  38. end
  39. context 'result' do
  40. before(:each) do
  41. group_access_instance.group_names_access_map = {
  42. group_full.name => 'full',
  43. group_read.name => 'read',
  44. group_inactive.name => 'change',
  45. }
  46. end
  47. it 'returns all related Groups' do
  48. expect(group_access_instance.groups.access.size).to eq(3)
  49. end
  50. it 'adds join table attribute(s like) access' do
  51. expect(group_access_instance.groups.access.first).to respond_to(:access)
  52. end
  53. it 'filters for given access parameter' do
  54. expect(group_access_instance.groups.access('read')).to include(group_read)
  55. end
  56. it 'filters for given access list parameter' do
  57. expect(group_access_instance.groups.access('read', 'change')).to include(group_read, group_inactive)
  58. end
  59. it 'always includes full access groups' do
  60. expect(group_access_instance.groups.access('read')).to include(group_full)
  61. end
  62. end
  63. end
  64. end
  65. context '#group_access?' do
  66. it 'responds to group_access?' do
  67. expect(group_access_instance).to respond_to(:group_access?)
  68. end
  69. before(:each) do
  70. group_access_instance.group_names_access_map = {
  71. group_read.name => 'read',
  72. }
  73. end
  74. context 'Group ID parameter' do
  75. include_examples '#group_access? call' do
  76. let(:group_parameter) { group_read.id }
  77. end
  78. end
  79. context 'Group parameter' do
  80. include_examples '#group_access? call' do
  81. let(:group_parameter) { group_read }
  82. end
  83. end
  84. it 'prevents inactive Group' do
  85. group_access_instance.group_names_access_map = {
  86. group_inactive.name => 'read',
  87. }
  88. expect(group_access_instance.group_access?(group_inactive.id, 'read')).to be false
  89. end
  90. it 'prevents inactive instances' do
  91. group_access_instance_inactive.group_names_access_map = {
  92. group_read.name => 'read',
  93. }
  94. expect(group_access_instance_inactive.group_access?(group_read.id, 'read')).to be false
  95. end
  96. end
  97. context '#group_ids_access' do
  98. it 'responds to group_ids_access' do
  99. expect(group_access_instance).to respond_to(:group_ids_access)
  100. end
  101. before(:each) do
  102. group_access_instance.group_names_access_map = {
  103. group_read.name => 'read',
  104. }
  105. end
  106. it 'lists only active Group IDs' do
  107. group_access_instance.group_names_access_map = {
  108. group_read.name => 'read',
  109. group_inactive.name => 'read',
  110. }
  111. result = group_access_instance.group_ids_access('read')
  112. expect(result).not_to include(group_inactive.id)
  113. end
  114. it "doesn't list for inactive instances" do
  115. group_access_instance_inactive.group_names_access_map = {
  116. group_read.name => 'read',
  117. }
  118. expect(group_access_instance_inactive.group_ids_access('read')).to be_empty
  119. end
  120. context 'single access' do
  121. it 'lists access Group IDs' do
  122. result = group_access_instance.group_ids_access('read')
  123. expect(result).to include(group_read.id)
  124. end
  125. it "doesn't list for no access" do
  126. result = group_access_instance.group_ids_access('change')
  127. expect(result).not_to include(group_read.id)
  128. end
  129. end
  130. context 'access list' do
  131. it 'lists access Group IDs' do
  132. result = group_access_instance.group_ids_access(%w[read change])
  133. expect(result).to include(group_read.id)
  134. end
  135. it "doesn't list for no access" do
  136. result = group_access_instance.group_ids_access(%w[change create])
  137. expect(result).not_to include(group_read.id)
  138. end
  139. end
  140. end
  141. context '#groups_access' do
  142. it 'responds to groups_access' do
  143. expect(group_access_instance).to respond_to(:groups_access)
  144. end
  145. it 'wraps #group_ids_access' do
  146. expect(group_access_instance).to receive(:group_ids_access)
  147. group_access_instance.groups_access('read')
  148. end
  149. it 'returns Groups' do
  150. group_access_instance.group_names_access_map = {
  151. group_read.name => 'read',
  152. }
  153. result = group_access_instance.groups_access('read')
  154. expect(result).to include(group_read)
  155. end
  156. end
  157. context '#group_names_access_map=' do
  158. it 'responds to group_names_access_map=' do
  159. expect(group_access_instance).to respond_to(:group_names_access_map=)
  160. end
  161. context 'existing instance' do
  162. it 'stores Hash with String values' do
  163. expect do
  164. group_access_instance.group_names_access_map = {
  165. group_full.name => 'full',
  166. group_read.name => 'read',
  167. }
  168. end.to change {
  169. described_class.group_through.klass.count
  170. }.by(2)
  171. end
  172. it 'stores Hash with Array<String> values' do
  173. expect do
  174. group_access_instance.group_names_access_map = {
  175. group_full.name => 'full',
  176. group_read.name => %w[read change],
  177. }
  178. end.to change {
  179. described_class.group_through.klass.count
  180. }.by(3)
  181. end
  182. it 'allows empty Hash value' do
  183. group_access_instance.group_names_access_map = {
  184. group_full.name => 'full',
  185. group_read.name => %w[read change],
  186. }
  187. expect do
  188. group_access_instance.group_names_access_map = {}
  189. end.to change {
  190. described_class.group_through.klass.count
  191. }.by(-3)
  192. end
  193. it 'prevents having full and other privilege at the same time' do
  194. invalid_combination = %w[full read change]
  195. exception = ActiveRecord::RecordInvalid
  196. expect do
  197. group_access_instance.group_names_access_map = {
  198. group_full.name => invalid_combination,
  199. }
  200. end.to raise_error(exception)
  201. expect do
  202. group_access_instance.group_names_access_map = {
  203. group_full.name => invalid_combination.reverse,
  204. }
  205. end.to raise_error(exception)
  206. end
  207. end
  208. context 'new instance' do
  209. it "doesn't store directly" do
  210. expect do
  211. new_group_access_instance.group_names_access_map = {
  212. group_full.name => 'full',
  213. group_read.name => 'read',
  214. }
  215. end.not_to change {
  216. described_class.group_through.klass.count
  217. }
  218. end
  219. it 'stores after save' do
  220. expect do
  221. new_group_access_instance.group_names_access_map = {
  222. group_full.name => 'full',
  223. group_read.name => 'read',
  224. }
  225. new_group_access_instance.save
  226. end.to change {
  227. described_class.group_through.klass.count
  228. }.by(2)
  229. end
  230. it 'allows empty Hash value' do
  231. expect do
  232. new_group_access_instance.group_names_access_map = {}
  233. new_group_access_instance.save
  234. end.not_to change {
  235. described_class.group_through.klass.count
  236. }
  237. end
  238. end
  239. end
  240. context '#group_names_access_map' do
  241. it 'responds to group_names_access_map' do
  242. expect(group_access_instance).to respond_to(:group_names_access_map)
  243. end
  244. it 'returns instance Group name => access relations as Hash' do
  245. expected = {
  246. group_full.name => ['full'],
  247. group_read.name => ['read'],
  248. }
  249. group_access_instance.group_names_access_map = expected
  250. expect(group_access_instance.group_names_access_map).to eq(expected)
  251. end
  252. it "doesn't map for inactive instances" do
  253. group_access_instance_inactive.group_names_access_map = {
  254. group_full.name => ['full'],
  255. group_read.name => ['read'],
  256. }
  257. expect(group_access_instance_inactive.group_names_access_map).to be_empty
  258. end
  259. it 'returns empty map if none is stored' do
  260. group_access_instance.group_names_access_map = {
  261. group_full.name => 'full',
  262. group_read.name => 'read',
  263. }
  264. group_access_instance.group_names_access_map = {}
  265. expect(group_access_instance.group_names_access_map).to be_blank
  266. end
  267. end
  268. context '#group_ids_access_map=' do
  269. it 'responds to group_ids_access_map=' do
  270. expect(group_access_instance).to respond_to(:group_ids_access_map=)
  271. end
  272. context 'existing instance' do
  273. it 'stores Hash with String values' do
  274. expect do
  275. group_access_instance.group_ids_access_map = {
  276. group_full.id => 'full',
  277. group_read.id => 'read',
  278. }
  279. end.to change {
  280. described_class.group_through.klass.count
  281. }.by(2)
  282. end
  283. it 'stores Hash with Array<String> values' do
  284. expect do
  285. group_access_instance.group_ids_access_map = {
  286. group_full.id => 'full',
  287. group_read.id => %w[read change],
  288. }
  289. end.to change {
  290. described_class.group_through.klass.count
  291. }.by(3)
  292. end
  293. it 'allows empty Hash value' do
  294. group_access_instance.group_ids_access_map = {
  295. group_full.id => 'full',
  296. group_read.id => %w[read change],
  297. }
  298. expect do
  299. group_access_instance.group_ids_access_map = {}
  300. end.to change {
  301. described_class.group_through.klass.count
  302. }.by(-3)
  303. end
  304. end
  305. context 'new instance' do
  306. it "doesn't store directly" do
  307. expect do
  308. new_group_access_instance.group_ids_access_map = {
  309. group_full.id => 'full',
  310. group_read.id => 'read',
  311. }
  312. end.not_to change {
  313. described_class.group_through.klass.count
  314. }
  315. end
  316. it 'stores after save' do
  317. expect do
  318. new_group_access_instance.group_ids_access_map = {
  319. group_full.id => 'full',
  320. group_read.id => 'read',
  321. }
  322. new_group_access_instance.save
  323. end.to change {
  324. described_class.group_through.klass.count
  325. }.by(2)
  326. end
  327. it 'allows empty Hash value' do
  328. expect do
  329. new_group_access_instance.group_ids_access_map = {}
  330. new_group_access_instance.save
  331. end.not_to change {
  332. described_class.group_through.klass.count
  333. }
  334. end
  335. end
  336. end
  337. context '#group_ids_access_map' do
  338. it 'responds to group_ids_access_map' do
  339. expect(group_access_instance).to respond_to(:group_ids_access_map)
  340. end
  341. it 'returns instance Group ID => access relations as Hash' do
  342. expected = {
  343. group_full.id => ['full'],
  344. group_read.id => ['read'],
  345. }
  346. group_access_instance.group_ids_access_map = expected
  347. expect(group_access_instance.group_ids_access_map).to eq(expected)
  348. end
  349. it "doesn't map for inactive instances" do
  350. group_access_instance_inactive.group_ids_access_map = {
  351. group_full.id => ['full'],
  352. group_read.id => ['read'],
  353. }
  354. expect(group_access_instance_inactive.group_ids_access_map).to be_empty
  355. end
  356. it 'returns empty map if none is stored' do
  357. group_access_instance.group_ids_access_map = {
  358. group_full.id => 'full',
  359. group_read.id => 'read',
  360. }
  361. group_access_instance.group_ids_access_map = {}
  362. expect(group_access_instance.group_ids_access_map).to be_blank
  363. end
  364. end
  365. context '#associations_from_param' do
  366. it 'handles group_ids parameter as group_ids_access_map' do
  367. expected = {
  368. group_full.id => ['full'],
  369. group_read.id => ['read'],
  370. }
  371. group_access_instance.associations_from_param(group_ids: expected)
  372. expect(group_access_instance.group_ids_access_map).to eq(expected)
  373. end
  374. it 'handles groups parameter as group_names_access_map' do
  375. expected = {
  376. group_full.name => ['full'],
  377. group_read.name => ['read'],
  378. }
  379. group_access_instance.associations_from_param(groups: expected)
  380. expect(group_access_instance.group_names_access_map).to eq(expected)
  381. end
  382. end
  383. context '#attributes_with_association_ids' do
  384. it 'includes group_ids as group_ids_access_map' do
  385. expected = {
  386. group_full.id => ['full'],
  387. group_read.id => ['read'],
  388. }
  389. group_access_instance.group_ids_access_map = expected
  390. result = group_access_instance.attributes_with_association_ids
  391. expect(result['group_ids']).to eq(expected)
  392. end
  393. end
  394. context '#attributes_with_association_names' do
  395. it 'includes group_ids as group_ids_access_map' do
  396. expected = {
  397. group_full.id => ['full'],
  398. group_read.id => ['read'],
  399. }
  400. group_access_instance.group_ids_access_map = expected
  401. result = group_access_instance.attributes_with_association_names
  402. expect(result['group_ids']).to eq(expected)
  403. end
  404. it 'includes groups as group_names_access_map' do
  405. expected = {
  406. group_full.name => ['full'],
  407. group_read.name => ['read'],
  408. }
  409. group_access_instance.group_names_access_map = expected
  410. result = group_access_instance.attributes_with_association_names
  411. expect(result['groups']).to eq(expected)
  412. end
  413. end
  414. context '.group_access' do
  415. it 'responds to group_access' do
  416. expect(described_class).to respond_to(:group_access)
  417. end
  418. before(:each) do
  419. group_access_instance.group_names_access_map = {
  420. group_read.name => 'read',
  421. }
  422. end
  423. it 'lists only active instances' do
  424. group_access_instance_inactive.group_names_access_map = {
  425. group_read.name => 'read',
  426. }
  427. result = described_class.group_access(group_read.id, 'read')
  428. expect(result).not_to include(group_access_instance_inactive)
  429. end
  430. context 'Group ID parameter' do
  431. include_examples '.group_access call' do
  432. let(:group_parameter) { group_read.id }
  433. end
  434. end
  435. context 'Group parameter' do
  436. include_examples '.group_access call' do
  437. let(:group_parameter) { group_read }
  438. end
  439. end
  440. end
  441. context '.group_access_ids' do
  442. it 'responds to group_access_ids' do
  443. expect(described_class).to respond_to(:group_access_ids)
  444. end
  445. it 'wraps .group_access' do
  446. expect(described_class).to receive(:group_access).and_call_original
  447. described_class.group_access_ids(group_read, 'read')
  448. end
  449. it 'returns class instances' do
  450. group_access_instance.group_names_access_map = {
  451. group_read.name => 'read',
  452. }
  453. result = described_class.group_access_ids(group_read, 'read')
  454. expect(result).to include(group_access_instance.id)
  455. end
  456. end
  457. it 'destroys relations before instance gets destroyed' do
  458. group_access_instance.group_names_access_map = {
  459. group_full.name => 'full',
  460. group_read.name => 'read',
  461. group_inactive.name => 'change',
  462. }
  463. expect do
  464. group_access_instance.destroy
  465. end.to change {
  466. described_class.group_through.klass.count
  467. }.by(-3)
  468. end
  469. end
  470. end
  471. RSpec.shared_examples '#group_access? call' do
  472. context 'single access' do
  473. it 'checks positive' do
  474. expect(group_access_instance.group_access?(group_parameter, 'read')).to be true
  475. end
  476. it 'checks negative' do
  477. expect(group_access_instance.group_access?(group_parameter, 'change')).to be false
  478. end
  479. end
  480. context 'access list' do
  481. it 'checks positive' do
  482. expect(group_access_instance.group_access?(group_parameter, %w[read change])).to be true
  483. end
  484. it 'checks negative' do
  485. expect(group_access_instance.group_access?(group_parameter, %w[change create])).to be false
  486. end
  487. end
  488. end
  489. RSpec.shared_examples '.group_access call' do
  490. context 'single access' do
  491. it 'lists access IDs' do
  492. expect(described_class.group_access(group_parameter, 'read')).to include(group_access_instance)
  493. end
  494. it 'excludes non access IDs' do
  495. expect(described_class.group_access(group_parameter, 'change')).not_to include(group_access_instance)
  496. end
  497. end
  498. context 'access list' do
  499. it 'lists access IDs' do
  500. expect(described_class.group_access(group_parameter, %w[read change])).to include(group_access_instance)
  501. end
  502. it 'excludes non access IDs' do
  503. expect(described_class.group_access(group_parameter, %w[change create])).not_to include(group_access_instance)
  504. end
  505. end
  506. end