<commit_before># frozen_string_literal: true

require "cases/helper"
require "models/post"
require "models/topic"
require "models/comment"
require "models/reply"
require "models/author"
require "models/developer"
require "models/computer"

class NamedScopingTest < ActiveRecord::TestCase
  fixtures :posts, :authors, :topics, :comments, :author_addresses

  def test_implements_enumerable
    assert !Topic.all.empty?

    assert_equal Topic.all.to_a, Topic.base
    assert_equal Topic.all.to_a, Topic.base.to_a
    assert_equal Topic.first,    Topic.base.first
    assert_equal Topic.all.to_a, Topic.base.map { |i| i }
  end

  def test_found_items_are_cached
    all_posts = Topic.base

    assert_queries(1) do
      all_posts.collect { true }
      all_posts.collect { true }
    end
  end

  def test_reload_expires_cache_of_found_items
    all_posts = Topic.base
    all_posts.to_a

    new_post = Topic.create!
    assert_not_includes all_posts, new_post
    assert_includes all_posts.reload, new_post
  end

  def test_delegates_finds_and_calculations_to_the_base_class
    assert !Topic.all.empty?

    assert_equal Topic.all.to_a,                Topic.base.to_a
    assert_equal Topic.first,                   Topic.base.first
    assert_equal Topic.count,                   Topic.base.count
    assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
  end

  def test_calling_merge_at_first_in_scope
    Topic.class_eval do
      scope :calling_merge_at_first_in_scope, Proc.new { merge(Topic.replied) }
    end
    assert_equal Topic.calling_merge_at_first_in_scope.to_a, Topic.replied.to_a
  end

  def test_method_missing_priority_when_delegating
    klazz = Class.new(ActiveRecord::Base) do
      self.table_name = "topics"
      scope :since, Proc.new { where("written_on >= ?", Time.now - 1.day) }
      scope :to,    Proc.new { where("written_on <= ?", Time.now) }
    end
    assert_equal klazz.to.since.to_a, klazz.since.to.to_a
  end

  def test_scope_should_respond_to_own_methods_and_methods_of_the_proxy
    assert Topic.approved.respond_to?(:limit)
    assert Topic.approved.respond_to?(:count)
    assert Topic.approved.respond_to?(:length)
  end

  def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
    assert !Topic.all.merge!(where: { approved: true }).to_a.empty?

    assert_equal Topic.all.merge!(where: { approved: true }).to_a, Topic.approved
    assert_equal Topic.where(approved: true).count, Topic.approved.count
  end

  def test_scopes_with_string_name_can_be_composed
    # NOTE that scopes defined with a string as a name worked on their own
    # but when called on another scope the other scope was completely replaced
    assert_equal Topic.replied.approved, Topic.replied.approved_as_string
  end

  def test_scopes_are_composable
    assert_equal((approved = Topic.all.merge!(where: { approved: true }).to_a), Topic.approved)
    assert_equal((replied = Topic.all.merge!(where: "replies_count > 0").to_a), Topic.replied)
    assert !(approved == replied)
    assert !(approved & replied).empty?

    assert_equal approved & replied, Topic.approved.replied
  end

  def test_procedural_scopes
    topics_written_before_the_third = Topic.where("written_on < ?", topics(:third).written_on)
    topics_written_before_the_second = Topic.where("written_on < ?", topics(:second).written_on)
    assert_not_equal topics_written_before_the_second, topics_written_before_the_third

    assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on)
    assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
  end

  def test_procedural_scopes_returning_nil
    all_topics = Topic.all

    assert_equal all_topics, Topic.written_before(nil)
  end

  def test_scope_with_object
    objects = Topic.with_object
    assert_operator objects.length, :>, 0
    assert objects.all?(&:approved?), "all objects should be approved"
  end

  def test_has_many_associations_have_access_to_scopes
    assert_not_equal Post.containing_the_letter_a, authors(:david).posts
    assert !Post.containing_the_letter_a.empty?

    assert_equal authors(:david).posts & Post.containing_the_letter_a, authors(:david).posts.containing_the_letter_a
  end

  def test_scope_with_STI
    assert_equal 3, Post.containing_the_letter_a.count
    assert_equal 1, SpecialPost.containing_the_letter_a.count
  end

  def test_has_many_through_associations_have_access_to_scopes
    assert_not_equal Comment.containing_the_letter_e, authors(:david).comments
    assert !Comment.containing_the_letter_e.empty?

    assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e
  end

  def test_scopes_honor_current_scopes_from_when_defined
    assert !Post.ranked_by_comments.limit_by(5).empty?
    assert !authors(:david).posts.ranked_by_comments.limit_by(5).empty?
    assert_not_equal Post.ranked_by_comments.limit_by(5), authors(:david).posts.ranked_by_comments.limit_by(5)
    assert_not_equal Post.top(5), authors(:david).posts.top(5)
    # Oracle sometimes sorts differently if WHERE condition is changed
    assert_equal authors(:david).posts.ranked_by_comments.limit_by(5).to_a.sort_by(&:id), authors(:david).posts.top(5).to_a.sort_by(&:id)
    assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
  end

  def test_scopes_body_is_a_callable
    e = assert_raises ArgumentError do
      Class.new(Post).class_eval { scope :containing_the_letter_z, where("body LIKE '%z%'") }
    end
    assert_equal "The scope body needs to be callable.", e.message
  end

  def test_active_records_have_scope_named__all__
    assert !Topic.all.empty?<commit_msg>Fix random CI failure due to non-deterministic sorting order<commit_after># frozen_string_literal: true

require "cases/helper"
require "models/post"
require "models/topic"
require "models/comment"
require "models/reply"
require "models/author"
require "models/developer"
require "models/computer"

class NamedScopingTest < ActiveRecord::TestCase
  fixtures :posts, :authors, :topics, :comments, :author_addresses

  def test_implements_enumerable
    assert !Topic.all.empty?

    assert_equal Topic.all.to_a, Topic.base
    assert_equal Topic.all.to_a, Topic.base.to_a
    assert_equal Topic.first,    Topic.base.first
    assert_equal Topic.all.to_a, Topic.base.map { |i| i }
  end

  def test_found_items_are_cached
    all_posts = Topic.base

    assert_queries(1) do
      all_posts.collect { true }
      all_posts.collect { true }
    end
  end

  def test_reload_expires_cache_of_found_items
    all_posts = Topic.base
    all_posts.to_a

    new_post = Topic.create!
    assert_not_includes all_posts, new_post
    assert_includes all_posts.reload, new_post
  end

  def test_delegates_finds_and_calculations_to_the_base_class
    assert !Topic.all.empty?

    assert_equal Topic.all.to_a,                Topic.base.to_a
    assert_equal Topic.first,                   Topic.base.first
    assert_equal Topic.count,                   Topic.base.count
    assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
  end

  def test_calling_merge_at_first_in_scope
    Topic.class_eval do
      scope :calling_merge_at_first_in_scope, Proc.new { merge(Topic.replied) }
    end
    assert_equal Topic.calling_merge_at_first_in_scope.to_a, Topic.replied.to_a
  end

  def test_method_missing_priority_when_delegating
    klazz = Class.new(ActiveRecord::Base) do
      self.table_name = "topics"
      scope :since, Proc.new { where("written_on >= ?", Time.now - 1.day) }
      scope :to,    Proc.new { where("written_on <= ?", Time.now) }
    end
    assert_equal klazz.to.since.to_a, klazz.since.to.to_a
  end

  def test_scope_should_respond_to_own_methods_and_methods_of_the_proxy
    assert Topic.approved.respond_to?(:limit)
    assert Topic.approved.respond_to?(:count)
    assert Topic.approved.respond_to?(:length)
  end

  def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
    assert !Topic.all.merge!(where: { approved: true }).to_a.empty?

    assert_equal Topic.all.merge!(where: { approved: true }).to_a, Topic.approved
    assert_equal Topic.where(approved: true).count, Topic.approved.count
  end

  def test_scopes_with_string_name_can_be_composed
    # NOTE that scopes defined with a string as a name worked on their own
    # but when called on another scope the other scope was completely replaced
    assert_equal Topic.replied.approved, Topic.replied.approved_as_string
  end

  def test_scopes_are_composable
    assert_equal((approved = Topic.all.merge!(where: { approved: true }).to_a), Topic.approved)
    assert_equal((replied = Topic.all.merge!(where: "replies_count > 0").to_a), Topic.replied)
    assert !(approved == replied)
    assert !(approved & replied).empty?

    assert_equal approved & replied, Topic.approved.replied
  end

  def test_procedural_scopes
    topics_written_before_the_third = Topic.where("written_on < ?", topics(:third).written_on)
    topics_written_before_the_second = Topic.where("written_on < ?", topics(:second).written_on)
    assert_not_equal topics_written_before_the_second, topics_written_before_the_third

    assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on)
    assert_equal topics_written_before_the_second, Topic.written_before(topics(:second).written_on)
  end

  def test_procedural_scopes_returning_nil
    all_topics = Topic.all

    assert_equal all_topics, Topic.written_before(nil)
  end

  def test_scope_with_object
    objects = Topic.with_object
    assert_operator objects.length, :>, 0
    assert objects.all?(&:approved?), "all objects should be approved"
  end

  def test_has_many_associations_have_access_to_scopes
    assert_not_equal Post.containing_the_letter_a, authors(:david).posts
    assert !Post.containing_the_letter_a.empty?

    expected = authors(:david).posts & Post.containing_the_letter_a
    assert_equal expected.sort_by(&:id), authors(:david).posts.containing_the_letter_a.sort_by(&:id)
  end

  def test_scope_with_STI
    assert_equal 3, Post.containing_the_letter_a.count
    assert_equal 1, SpecialPost.containing_the_letter_a.count
  end

  def test_has_many_through_associations_have_access_to_scopes
    assert_not_equal Comment.containing_the_letter_e, authors(:david).comments
    assert !Comment.containing_the_letter_e.empty?

    expected = authors(:david).comments & Comment.containing_the_letter_e
    assert_equal expected.sort_by(&:id), authors(:david).comments.containing_the_letter_e.sort_by(&:id)
  end

  def test_scopes_honor_current_scopes_from_when_defined
    assert !Post.ranked_by_comments.limit_by(5).empty?
    assert !authors(:david).posts.ranked_by_comments.limit_by(5).empty?
    assert_not_equal Post.ranked_by_comments.limit_by(5), authors(:david).posts.ranked_by_comments.limit_by(5)
    assert_not_equal Post.top(5), authors(:david).posts.top(5)
    # Oracle sometimes sorts differently if WHERE condition is changed
    assert_equal authors(:david).posts.ranked_by_comments.limit_by(5).to_a.sort_by(&:id), authors(:david).posts.top(5).to_a.sort_by(&:id)
    assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
  end

  def test_scopes_body_is_a_callable
    e = assert_raises ArgumentError do
      Class.new(Post).class_eval { scope :containing_the_letter_z, where("body LIKE '%z%'") }
    end
    assert_equal "The scope body needs to be callable.", e.message
  end

  def test_active_records_have_scope_named__all__
    assert !Topic.all.empty?
{'fraction_non_alphanumeric': 0.0881015698721798, 'fraction_numerical': 0.0027451316805353005, 'mean_word_length': 4.604807692307692, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5320634', 'n_tokens_mistral': 4058, 'n_tokens_neox': 3922, 'n_words': 687}