require 'rails_helper' RSpec.describe PostImplication, type: :model do let!(:post_record) do Post.create!( title: 'post', url: 'https://example.com/post-implication-post' ) end let!(:parent_post) do Post.create!( title: 'parent post', url: 'https://example.com/post-implication-parent' ) end it 'is valid with post and parent_post' do implication = described_class.new( post: post_record, parent_post: ) expect(implication).to be_valid end it 'does not allow same post as parent_post' do implication = described_class.new( post: post_record, parent_post: post_record ) expect(implication).not_to be_valid expect(implication.errors[:parent_post_id]).to be_present end it 'does not allow duplicate pair' do described_class.create!( post: post_record, parent_post: ) duplicate = described_class.new( post: post_record, parent_post: ) expect(duplicate).not_to be_valid expect(duplicate.errors[:post_id]).to be_present end it 'rejects a parent that would create a two-post cycle' do described_class.create!(post: post_record, parent_post:) implication = described_class.new( post: parent_post, parent_post: post_record) expect(implication).not_to be_valid expect(implication.errors.of_kind?(:parent_post_id, :invalid)).to be true end it 'rejects a parent that would create a three-post cycle' do ancestor_post = create(:post) described_class.create!(post: post_record, parent_post:) described_class.create!(post: parent_post, parent_post: ancestor_post) implication = described_class.new( post: ancestor_post, parent_post: post_record) expect(implication).not_to be_valid expect(implication.errors.of_kind?(:parent_post_id, :invalid)).to be true end it 'allows a parent with an ancestor when no cycle would result' do ancestor_post = create(:post) described_class.create!(post: parent_post, parent_post: ancestor_post) implication = described_class.new(post: post_record, parent_post:) expect(implication).to be_valid end it 'terminates when existing ancestors already contain a cycle' do ancestor_post = create(:post) described_class.create!(post: parent_post, parent_post: ancestor_post) legacy_implication = described_class.new( post: ancestor_post, parent_post:) legacy_implication.save!(validate: false) implication = described_class.new(post: post_record, parent_post:) expect(implication).to be_valid end end