text:
require 'rails_helper'

RSpec.describe Signature, type: :model do
  it "has a valid factory" do
    expect(FactoryBot.build(:signature)).to be_valid
  end

  around do |example|
    perform_enqueued_jobs do
      example.call
    end
  end

  before do
    FactoryBot.create(:constituency, :london_and_westminster)
    FactoryBot.create(:location, code: "GB", name: "United Kingdom")
  end

  context "defaults" do
    it "has pending as default state" do
      s = Signature.new
      expect(s.state).to eq("pending")
    end

    it "generates perishable token" do
      s = FactoryBot.create(:signature, :perishable_token => nil)
      expect(s.perishable_token).not_to be_nil
    end

    it "sets notify_by_email to falsey" do
      s = Signature.new
      expect(s.notify_by_email).to be_falsey
    end

    it "generates unsubscription token" do
      s = FactoryBot.create(:signature, :unsubscribe_token => nil)
      expect(s.unsubscribe_token).not_to be_nil
    end

    it "generates signed token" do
      s = FactoryBot.create(:signature, :signed_token => nil)
      expect(s.signed_token).not_to be_nil
    end
  end

  RSpec::Matchers.define :have_valid do |field|
    match do |actual|
      actual.valid?
      expect(actual.errors[field]).to be_empty
    end
  end

  context "custom attribute setters" do
    describe "#postcode=" do
      let(:signature) { FactoryBot.build(:signature) }

      it "removes all whitespace" do
        signature.postcode = " N1  1TY  "
        expect(signature.postcode).to eq "N11TY"
      end
      it "upcases the postcode" do
        signature.postcode = "n11ty "
        expect(signature.postcode).to eq "N11TY"
      end
      it "removes whitespaces and upcase the postcode" do
        signature.postcode = "   N1  1ty "
        expect(signature.postcode).to eq "N11TY"
      end
    end
    describe "#email=" do
      let(:signature) { FactoryBot.build(:signature) }

      it "downcases the email" do
        signature.email = "JOE@PUBLIC.COM"
        expect(signature.email).to eq "joe@public.com"
      end
    end
  end

  describe "associations" do
    it { is_expected.to belong_to(:petition) }
    it { is_expected.to belong_to(:invalidation) }
  end

  describe "callbacks" do
    context "when the signature is destroyed" do
      let(:attributes) { FactoryBot.attributes_for(:petition) }
      let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
      let(:petition) do
        Petition.create(attributes) do |petition|
          petition.creator = creator

          5.times do
            petition.signatures << FactoryBot.create(:pending_signature)
          end
        end
      end

      before do
        petition.signatures.each { |s| s.validate! }
        petition.publish
      end

      context "and the signature is the creator" do
        it "cancels the destroy" do
          expect(creator.destroy).to eq(false)
        end
      end

      context "and the signature is not the creator" do
        let(:country_journal) { CountryPetitionJournal.for(petition, "GB") }
        let(:constituency_journal) { ConstituencyPetitionJournal.for(petition, "3415") }

        let(:signature) {
          FactoryBot.create(
            :pending_signature,
            petition: petition,
            constituency_id: "3415",
            location_code: "GB"
          )
        }

        before do
          signature.validate!
          petition.reload
        end

        it "decrements the petition signature count" do
          expect(petition.signature_count).to eq(7)
          expect{ signature.destroy }.to change{ petition.reload.signature_count }.by(-1)
        end

        it "decrements the country journal signature count" do
          expect(petition.signature_count).to eq(7)
          expect{ signature.destroy }.to change{ country_journal.reload.signature_count }.by(-1)
        end

        it "decrements the constituency journal signature count" do
          expect(petition.signature_count).to eq(7)
          expect{ signature.destroy }.to change{ constituency_journal.reload.signature_count }.by(-1)
        end
      end

      context "and the signature is invalidated" do
        let(:country_journal) { CountryPetitionJournal.for(petition, "GB") }
        let(:constituency_journal) { ConstituencyPetitionJournal.for(petition, "3415") }

        let(:signature) {
          FactoryBot.create(
            :pending_signature,
            petition: petition,
            constituency_id: "3415",
            location_code: "GB"
          )
        }

        before do
          signature.validate!
          signature.invalidate!
          petition.reload
        end

        it "doesn't decrement the petition signature count" do
          expect(petition.signature_count).to eq(6)
          expect{ signature.destroy }.not_to change{ petition.reload.signature_count }
        end

        it "doesn't decrement the country journal signature count" do
          expect(petition.signature_count).to eq(6)
          expect{ signature.destroy }.not_to change{ country_journal.reload.signature_count }
        end

        it "doesn't decrement the constituency journal signature count" do
          expect(petition.signature_count).to eq(6)
          expect{ signature.destroy }.not_to change{ constituency_journal.reload.signature_count }
        end
      end
    end

    context "when the signature is created" do
      let!(:petition) { FactoryBot.create(:open_petition) }
      let!(:signature) { petition.signatures.build(attributes) }
      let(:email) { "foo@example.com" }
      let(:location_code) { "GB" }
      let(:postcode) { "SW1A 1AA" }

      let(:attributes) do
        {
          name: "Suzy Signer",
          email: email,
          postcode: postcode,
          location_code: location_code,
          uk_citizenship: "1"
        }
      end

      context "and the signature is a duplicate" do
        before do
          petition.signatures.create!(attributes)
        end

        it "raises an ActiveRecord::RecordNotUnique exception" do
          expect { signature.save }.to raise_exception(ActiveRecord::RecordNotUnique)
        end
      end

      context "and the email is blank" do
        let(:email) { "" }

        it "doesn't set the uuid column" do
          expect {
            signature.save
          }.not_to change {
            signature.uuid
          }
        end
      end

      context "and the email is set" do
        let(:email) { "alice@example.com" }

        it "sets the uuid column" do
          expect {
            signature.save
          }.to change {
            signature.uuid
          }.from(nil).to("6613a3fd-c2c4-5bc2-a6de-3dc0b2527dd6")
        end
      end
    end
  end

  context "validations" do
    it { is_expected.to validate_presence_of(:name).with_message(/must be completed/) }
    it { is_expected.to validate_presence_of(:email).with_message(/must be completed/) }
    it { is_expected.to validate_presence_of(:location_code).with_message(/must be completed/) }
    it { is_expected.to validate_length_of(:name).is_at_most(255) }
    it { is_expected.to validate_length_of(:constituency_id).is_at_most(255) }

    it "validates format of email" do
      s = FactoryBot.build(:signature, :email => 'joe@example.com')
      expect(s).to have_valid(:email)
    end

    it "does not allow invalid email" do
      s = FactoryBot.build(:signature, :email => 'not an email')
      expect(s).not_to have_valid(:email)
    end

    it "does not allow emails using plus addresses" do
      signature = FactoryBot.build(:signature, email: 'foobar+petitions@example.com')
      expect(signature).not_to have_valid(:email)
      expect(signature.errors.full_messages).to include("You can't use 'plus addressing' in your email address")
    end

    it "does not allow blank or unknown state" do
      s = FactoryBot.build(:signature, :state => '')
      expect(s).not_to have_valid(:state)
      s.state = 'unknown'
      expect(s).not_to have_valid(:state)
    end

    it "allows known states" do
      s = FactoryBot.build(:signature)
      %w(pending validated ).each do |state|
        s.state = state
        expect(s).to have_valid(:state)
      end
    end

    describe "postcode" do
      it "requires a postcode for a UK address" do
        expect(FactoryBot.build(:signature, :postcode => 'SW1A 1AA')).to be_valid
        expect(FactoryBot.build(:signature, :postcode => '')).not_to be_valid
      end

      it "does not require a postcode for non-UK addresses" do
        expect(FactoryBot.build(:signature, :location_code => "GB", :postcode => '')).not_to be_valid
        expect(FactoryBot.build(:signature, :location_code => "US", :postcode => '')).to be_valid
      end

      it "checks the format of postcode" do
        s = FactoryBot.build(:signature, :postcode => 'SW1A1AA')
        expect(s).to have_valid(:postcode)
      end

      it "recognises special postcodes" do
        expect(FactoryBot.build(:signature, :postcode => 'BFPO 1234')).to have_valid(:postcode)
        expect(FactoryBot.build(:signature, :postcode => 'XM4 5HQ')).to have_valid(:postcode)
        expect(FactoryBot.build(:signature, :postcode => 'GIR 0AA')).to have_valid(:postcode)
      end

      it "does not allow prefix of postcode only" do
        s = FactoryBot.build(:signature, :postcode => 'N1')
        expect(s).not_to have_valid(:postcode)
      end

      it "does not allow unrecognised postcodes" do
        s = FactoryBot.build(:signature, :postcode => '90210')
        expect(s).not_to have_valid(:postcode)
      end

      it "does not allow postcodes longer than 255 characters for non-UK addresses" do
        s = FactoryBot.build(:signature, :location_code => "US", :postcode => "1" * 256)
        expect(s).not_to have_valid(:postcode)
      end
    end

    describe "uk_citizenship" do
      it "requires acceptance of uk_citizenship for a new record" do
        expect(FactoryBot.build(:signature, :uk_citizenship => '1')).to be_valid
        expect(FactoryBot.build(:signature, :uk_citizenship => '0')).not_to be_valid
        expect(FactoryBot.build(:signature, :uk_citizenship => nil)).not_to be_valid
      end

      it "does not require acceptance of uk_citizenship for old records" do
        sig = FactoryBot.create(:signature)
        sig.reload
        sig.uk_citizenship = '0'
        expect(sig).to be_valid
      end
    end
  end

  describe "scopes" do
    let(:week_ago) { 1.week.ago }
    let(:two_days_ago) { 2.days.ago }
    let!(:petition) { FactoryBot.create(:petition) }
    let!(:signature1) { FactoryBot.create(:signature, :email => "person1@example.com", :petition => petition, :state => Signature::VALIDATED_STATE, :notify_by_email => true) }
    let!(:signature2) { FactoryBot.create(:signature, :email => "person2@example.com", :petition => petition, :state => Signature::PENDING_STATE, :notify_by_email => true) }
    let!(:signature3) { FactoryBot.create(:signature, :email => "person3@example.com", :petition => petition, :state => Signature::VALIDATED_STATE, :notify_by_email => false) }
    let!(:signature4) { FactoryBot.create(:signature, :email => "person4@example.com", :petition => petition, :state => Signature::INVALIDATED_STATE, :notify_by_email => false) }
    let!(:signature5) { FactoryBot.create(:signature, :email => "person4@example.com", :petition => petition, :state => Signature::FRAUDULENT_STATE, :notify_by_email => false) }

    describe "validated" do
      it "returns only validated signatures" do
        signatures = Signature.validated
        expect(signatures.size).to eq(3)
        expect(signatures).to include(signature1, signature3, petition.creator)
      end
    end

    describe "subscribed" do
      it "returns only signatures with notify_by_email: true" do
        signatures = Signature.subscribed
        expect(signatures.size).to eq(3)
        expect(signatures).to include(signature1, signature2, petition.creator)
      end
    end

    describe "pending" do
      it "returns only pending signatures" do
        signatures = Signature.pending
        expect(signatures.size).to eq(1)
        expect(signatures).to include(signature2)
      end
    end

    describe "invalidated" do
      it "returns only invalidated signatures" do
        signatures = Signature.invalidated
        expect(signatures.size).to eq(1)
        expect(signatures).to include(signature4)
      end
    end

    describe "fraudulent" do
      it "returns only fraudulent signatures" do
        signatures = Signature.fraudulent
        expect(signatures.size).to eq(1)
        expect(signatures).to include(signature5)
      end
    end

    describe "for_invalidating" do
      let(:petition) { FactoryBot.create(:open_petition) }

      subject do
        described_class.for_invalidating.to_a
      end

      it "returns pending signatures" do
        signature = FactoryBot.create(:pending_signature, petition: petition)
        expect(subject).to include(signature)
      end

      it "returns validated signatures" do
        signature = FactoryBot.create(:validated_signature, petition: petition)
        expect(subject).to include(signature)
      end

      it "doesn't return fraudulent signatures" do
        signature = FactoryBot.create(:fraudulent_signature, petition: petition)
        expect(subject).not_to include(signature)
      end

      it "doesn't return invalidated signatures" do
        signature = FactoryBot.create(:invalidated_signature, petition: petition)
        expect(subject).not_to include(signature)
      end
    end

    describe "for_email" do
      let!(:other_petition) { FactoryBot.create(:petition) }
      let!(:other_signature) do
        FactoryBot.create(
          :signature,
          :email => "person3@example.com",
          :petition => other_petition,
          :state => Signature::PENDING_STATE
        )
      end

      it "returns an empty set if the email is not found" do
        expect(Signature.for_email("notfound@example.com")).to eq([])
      end

      it "returns only signatures for the given email address" do
        expect(Signature.for_email("person3@example.com")).to match_array(
          [signature3, other_signature]
        )
      end

      it "searches case-insensitively" do
        expect(Signature.for_email("Person3@example.com")).to match_array(
          [signature3, other_signature]
        )
      end
    end

    describe "checking whether the signature is the creator" do
      let!(:petition) { FactoryBot.create(:petition) }
      it "is the creator if the signature is listed as the creator signature" do
        expect(petition.creator).to be_creator
      end

      it "is not the creator if the signature is not listed as the creator" do
        signature = FactoryBot.create(:signature, :petition => petition)
        expect(signature).not_to be_creator
      end
    end
  end

  describe "read-only attributes" do
    [
      [:sponsor, true, false],
      [:creator, true, false]
    ].each do |attribute, value, new_value|

      describe "##{attribute}" do
        let(:signature) { FactoryBot.create(:signature, attribute => value) }
        let(:exception) { ActiveRecord::ActiveRecordError }
        let(:message) { "#{attribute} is marked as readonly" }

        it "can't be updated via update_column" do
          expect {
            signature.update_column(attribute, new_value)
          }.to raise_error(exception, message)
        end

        it "can't be updated via update" do
          expect {
            signature.update(attribute => value)
          }.not_to change {
            signature.reload.send(attribute)
          }
        end

        it "can't be updated via save" do
          expect {
            signature.send(:"#{attribute}=", new_value)
            signature.save
          }.not_to change {
            signature.reload.send(attribute)
          }
        end
      end

    end
  end

  describe ".search" do
    let(:scope) { double(:scope) }

    context "when searching with an ip address" do
      it "calls the for_ip scope and paginates the result" do
        expect(Signature).to receive(:for_ip).with("127.0.0.1").and_return(scope)
        expect(scope).to receive(:paginate).with(page: 1, per_page: 50)
        described_class.search("127.0.0.1")
      end

      context "and passing the page parameter" do
        it "calls the for_ip scope and paginates the result" do
          expect(Signature).to receive(:for_ip).with("127.0.0.1").and_return(scope)
          expect(scope).to receive(:paginate).with(page: 2, per_page: 50)
          described_class.search("127.0.0.1", page: "2")
        end
      end
    end

    context "when searching with an email address" do
      it "calls the for_email scope and paginates the result" do
        expect(Signature).to receive(:for_email).with("alice@example.com").and_return(scope)
        expect(scope).to receive(:paginate).with(page: 1, per_page: 50)
        described_class.search("alice@example.com")
      end

      context "and passing the page parameter" do
        it "calls the for_email scope and paginates the result" do
          expect(Signature).to receive(:for_email).with("alice@example.com").and_return(scope)
          expect(scope).to receive(:paginate).with(page: 2, per_page: 50)
          described_class.search("alice@example.com", page: "2")
        end
      end
    end

    context "when searching with a name" do
      it "calls the for_name scope and paginates the result" do
        expect(Signature).to receive(:for_name).with("Alice").and_return(scope)
        expect(scope).to receive(:paginate).with(page: 1, per_page: 50)
        described_class.search("Alice")
      end

      context "and passing the page parameter" do
        it "calls the for_name scope and paginates the result" do
          expect(Signature).to receive(:for_name).with("Alice").and_return(scope)
          expect(scope).to receive(:paginate).with(page: 2, per_page: 50)
          described_class.search("Alice", page: "2")
        end
      end
    end
  end

  describe ".validate!" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish
    end

    context "when passed a signature id that doesn't exist" do
      let(:signature_ids) { [petition.signatures.maximum(:id) + 1] }

      it "raises an ActiveRecord::RecordNotFound error" do
        expect {
          described_class.invalidate!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotFound)
      end
    end

    context "with a pending signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition) }

      before do
        allow(described_class).to receive(:find).and_call_original
        allow(described_class).to receive(:find).with([signature.id]).and_return([signature])
        expect(signature).to receive(:validate!).and_call_original
      end

      it "transitions the signature to the validated state" do
        expect {
          described_class.validate!([signature.id])
        }.to change {
          signature.reload.validated?
        }.from(false).to(true)
      end
    end
  end

  describe ".invalidate!" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish
    end

    context "when passed a signature id that doesn't exist" do
      let(:signature_ids) { [petition.signatures.maximum(:id) + 1] }

      it "raises an ActiveRecord::RecordNotFound error" do
        expect {
          described_class.invalidate!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotFound)
      end
    end

    context "with a validated signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition) }

      before do
        signature.validate!

        allow(described_class).to receive(:find).and_call_original
        allow(described_class).to receive(:find).with([signature.id]).and_return([signature])
        expect(signature).to receive(:invalidate!).and_call_original
      end

      it "transitions the signature to the invalidated state" do
        expect {
          described_class.invalidate!([signature.id])
        }.to change {
          signature.reload.invalidated?
        }.from(false).to(true)
      end
    end
  end

  describe ".subscribe!" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature, notify_by_email: false)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish
    end

    context "when passed a signature id that doesn't exist" do
      let(:signature_ids) { [petition.signatures.maximum(:id) + 1] }

      it "raises an ActiveRecord::RecordNotFound error" do
        expect {
          described_class.subscribe!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotFound)
      end
    end

    context "when trying to subscribe the creator" do
      it "doesn't raise an error" do
        expect {
          described_class.subscribe!([creator.id])
        }.not_to raise_error
      end
    end

    context "with a pending signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition) }

      it "doesn't raise an error" do
        expect {
          described_class.subscribe!([signature.id])
        }.not_to raise_error
      end
    end

    context "with a pending signature that isn't subscribed" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition, notify_by_email: false) }

      it "subscribes the signature" do
        expect {
          described_class.subscribe!([signature.id])
        }.to change {
          signature.reload.unsubscribed?
        }.from(true).to(false)
      end
    end

    context "with a validated signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition, notify_by_email: false) }

      before do
        signature.validate!

        allow(described_class).to receive(:find).and_call_original
        allow(described_class).to receive(:find).with([signature.id]).and_return([signature])
        expect(signature).to receive(:update!).with(notify_by_email: true).and_call_original
      end

      it "subscribes the signature" do
        expect {
          described_class.subscribe!([signature.id])
        }.to change {
          signature.reload.unsubscribed?
        }.from(true).to(false)
      end
    end
  end

  describe ".unsubscribe!" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish
    end

    context "when passed a signature id that doesn't exist" do
      let(:signature_ids) { [petition.signatures.maximum(:id) + 1] }

      it "raises an ActiveRecord::RecordNotFound error" do
        expect {
          described_class.unsubscribe!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotFound)
      end
    end

    context "when trying to unsubscribe the creator" do
      it "raises an error" do
        expect {
          described_class.unsubscribe!([creator.id])
        }.to raise_error(RuntimeError, "Can't unsubscribe the creator signature")
      end
    end

    context "with a pending signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition) }

      it "raises an error" do
        expect {
          described_class.unsubscribe!([signature.id])
        }.to raise_error(RuntimeError, "Can't unsubscribe a pending signature")
      end
    end

    context "with a validated signature" do
      let(:signature) { FactoryBot.create(:pending_signature, petition: petition) }

      before do
        signature.validate!

        allow(described_class).to receive(:find).and_call_original
        allow(described_class).to receive(:find).with([signature.id]).and_return([signature])
        expect(signature).to receive(:update!).with(notify_by_email: false).and_call_original
      end

      it "unsubscribes the signature" do
        expect {
          described_class.unsubscribe!([signature.id])
        }.to change {
          signature.reload.unsubscribed?
        }.from(false).to(true)
      end
    end
  end

  describe ".destroy!" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish
    end

    context "when passed a signature id that doesn't exist" do
      let(:signature_ids) { [petition.signatures.maximum(:id) + 1] }

      it "raises an ActiveRecord::RecordNotFound error" do
        expect {
          described_class.destroy!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotFound)
      end
    end

    context "when trying to delete the creator" do
      let(:signature_ids) { [creator.id] }

      it "raises an ActiveRecord::RecordNotDestroyed error" do
        expect {
          described_class.destroy!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotDestroyed)
      end
    end

    context "when the signature is not the creator" do
      let(:country_journal) { CountryPetitionJournal.for(petition, "GB") }
      let(:constituency_journal) { ConstituencyPetitionJournal.for(petition, "3415") }

      let(:signature) {
        FactoryBot.create(
          :pending_signature,
          petition: petition,
          constituency_id: "3415",
          location_code: "GB"
        )
      }

      before do
        signature.validate!
        petition.reload
      end

      it "decrements the petition signature count" do
        expect {
          described_class.destroy!([signature.id])
        }.to change {
          petition.reload.signature_count
        }.from(7).to(6)
      end

      it "decrements the country journal signature count" do
        expect {
          described_class.destroy!([signature.id])
        }.to change {
          country_journal.reload.signature_count
        }.by(-1)
      end

      it "decrements the constituency journal signature count" do
        expect {
          described_class.destroy!([signature.id])
        }.to change {
          constituency_journal.reload.signature_count
        }.by(-1)
      end
    end

    context "when one signature fails" do
      let(:signatures) { [petition.signatures.last, creator] }
      let(:signature_ids) { signatures.map(&:id) }

      before do
        allow(described_class).to receive(:find).with(signature_ids).and_return(signatures)
      end

      it "raises an ActiveRecord::RecordNotDestroyed error" do
        expect {
          described_class.destroy!(signature_ids)
        }.to raise_error(ActiveRecord::RecordNotDestroyed)
      end

      it "doesn't destroy any signatures" do
        expect {
          begin
            described_class.destroy!(signature_ids)
          rescue ActiveRecord::RecordNotDestroyed => e
            0
          end
        }.not_to change {
          petition.reload.signatures.count
        }
      end
    end
  end

  describe ".missing_constituency_id" do
    let!(:signature_1) { FactoryBot.create(:validated_signature, validated_at: 2.weeks.ago) }
    let!(:signature_2) { FactoryBot.create(:validated_signature, constituency_id: "3415") }
    let!(:signature_3) { FactoryBot.create(:validated_signature, location_code: "US") }
    let!(:signature_4) { FactoryBot.create(:validated_signature) }

    subject { described_class.missing_constituency_id(since: 1.week.ago) }

    it "doesn't include signatures from before the cut-off date" do
      expect(subject).not_to include(signature_1)
    end

    it "doesn't include signatures that have a constituency_id" do
      expect(subject).not_to include(signature_2)
    end

    it "doesn't include signatures that are not in the UK" do
      expect(subject).not_to include(signature_3)
    end

    it "includes signatures that need their constituency_id set" do
      expect(subject).to include(signature_4)
    end

    context "when not supplying the cut-off date" do
      subject { described_class.missing_constituency_id }

      it "includes all signatures that need their constituency_id set" do
        expect(subject).to include(signature_1)
      end
    end
  end

  describe ".petition_ids_with_invalid_signature_counts" do
    subject do
      described_class.petition_ids_with_invalid_signature_counts
    end

    context "when there are no petitions with invalid signature counts" do
      let!(:petition) { FactoryBot.create(:open_petition) }

      it "returns an empty array" do
        expect(subject).to eq([])
      end
    end

    context "when there are petitions with invalid signature counts" do
      let!(:petition) { FactoryBot.create(:open_petition, signature_count: 100) }

      it "returns an array of ids" do
        expect(described_class.petition_ids_with_invalid_signature_counts).to eq([petition.id])
      end
    end
  end

  describe ".fraudulent_domains" do
    subject do
      described_class.fraudulent_domains
    end

    before do
      FactoryBot.create(:fraudulent_signature, email: "alice@foo.com")
      FactoryBot.create(:fraudulent_signature, email: "bob@bar.com")
      FactoryBot.create(:fraudulent_signature, email: "charlie@foo.com")
    end

    it "returns a hash of domains and counts in descending order" do
      expect(subject).to be_an_instance_of(Hash)
      expect(subject.to_a).to eq([["foo.com", 2], ["bar.com", 1]])
    end
  end

  describe ".trending_domains" do
    before do
      FactoryBot.create(:validated_signature, email: "alice@foo.com", validated_at: 30.minutes.ago)
      FactoryBot.create(:validated_signature, email: "bob@bar.com", validated_at: 30.minutes.ago)
      FactoryBot.create(:validated_signature, email: "charlie@foo.com", validated_at: 30.minutes.ago)
    end

    it "returns a hash of domains and counts in descending order" do
      domains = described_class.trending_domains

      expect(domains).to be_an_instance_of(Hash)
      expect(domains.to_a).to eq([["foo.com", 2], ["bar.com", 1]])
    end

    it "ignores pending signatures" do
      FactoryBot.create(:pending_signature, email: "derek@foo.com", created_at: 30.minutes.ago)
      domains = described_class.trending_domains

      expect(domains.to_a).to eq([["foo.com", 2], ["bar.com", 1]])
    end

    it "ignores invalidated signatures" do
      FactoryBot.create(:invalidated_signature, email: "derek@foo.com", validated_at: 30.minutes.ago, invalidated_at: 10.minutes.ago)
      domains = described_class.trending_domains

      expect(domains.to_a).to eq([["foo.com", 2], ["bar.com", 1]])
    end

    it "ignores fraudulent signatures" do
      FactoryBot.create(:fraudulent_signature, email: "derek@foo.com", created_at: 30.minutes.ago)
      domains = described_class.trending_domains

      expect(domains.to_a).to eq([["foo.com", 2], ["bar.com", 1]])
    end

    it "can override the timespan" do
      FactoryBot.create(:validated_signature, email: "derek@foo.com", validated_at: 5.minutes.ago)
      domains = described_class.trending_domains(since: 10.minutes.ago)

      expect(domains.to_a).to eq([["foo.com", 1]])
    end

    it "can override the number returned" do
      domains = described_class.trending_domains(limit: 1)

      expect(domains.to_a).to eq([["foo.com", 2]])
    end
  end

  describe ".trending_ips" do
    before do
      FactoryBot.create(:validated_signature, ip_address: "10.0.1.1", validated_at: 30.minutes.ago)
      FactoryBot.create(:validated_signature, ip_address: "192.168.1.1", validated_at: 30.minutes.ago)
      FactoryBot.create(:validated_signature, ip_address: "10.0.1.1", validated_at: 30.minutes.ago)
    end

    it "returns a hash of domains and counts in descending order" do
      domains = described_class.trending_ips

      expect(domains).to be_an_instance_of(Hash)
      expect(domains.to_a).to eq([["10.0.1.1", 2], ["192.168.1.1", 1]])
    end

    it "ignores pending signatures" do
      FactoryBot.create(:pending_signature, ip_address: "10.0.1.1", created_at: 30.minutes.ago)
      domains = described_class.trending_ips

      expect(domains.to_a).to eq([["10.0.1.1", 2], ["192.168.1.1", 1]])
    end

    it "ignores invalidated signatures" do
      FactoryBot.create(:invalidated_signature, ip_address: "10.0.1.1", validated_at: 30.minutes.ago, invalidated_at: 10.minutes.ago)
      domains = described_class.trending_ips

      expect(domains.to_a).to eq([["10.0.1.1", 2], ["192.168.1.1", 1]])
    end

    it "ignores fraudulent signatures" do
      FactoryBot.create(:fraudulent_signature, ip_address: "10.0.1.1", created_at: 30.minutes.ago)
      domains = described_class.trending_ips

      expect(domains.to_a).to eq([["10.0.1.1", 2], ["192.168.1.1", 1]])
    end

    it "can override the timespan" do
      FactoryBot.create(:validated_signature, ip_address: "10.0.1.1", validated_at: 5.minutes.ago)
      domains = described_class.trending_ips(since: 10.minutes.ago)

      expect(domains.to_a).to eq([["10.0.1.1", 1]])
    end

    it "can override the number returned" do
      domains = described_class.trending_ips(limit: 1)

      expect(domains.to_a).to eq([["10.0.1.1", 2]])
    end
  end

  describe ".duplicate_emails" do
    let!(:petition) { FactoryBot.create(:open_petition) }

    context "when there are no duplicate emails" do
      it "returns zero" do
        expect(petition.signatures.duplicate_emails).to eq(0)
      end
    end

    context "when there are duplicate emails" do
      before do
        FactoryBot.create(:validated_signature, petition: petition, name: "Alice", email: "aliceandbob@example.com")
        FactoryBot.create(:validated_signature, petition: petition, name: "Bob", email: "aliceandbob@example.com")
      end

      it "returns the number of duplicate emails" do
        expect(petition.signatures.duplicate_emails).to eq(1)
      end
    end
  end

  describe "#number" do
    let(:attributes) { FactoryBot.attributes_for(:petition) }
    let(:creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:petition) do
      Petition.create(attributes) do |petition|
        petition.creator = creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    let(:other_attributes) { FactoryBot.attributes_for(:petition) }
    let(:other_creator) { FactoryBot.create(:pending_signature, creator: true) }
    let(:other_petition) do
      Petition.create(other_attributes) do |petition|
        petition.creator = other_creator

        5.times do
          petition.signatures << FactoryBot.create(:pending_signature)
        end
      end
    end

    before do
      petition.signatures.each { |s| s.validate! }
      petition.publish

      other_petition.signatures.each { |s| s.validate! }
      other_petition.publish
    end

    it "returns the signature number" do
      signature = FactoryBot.create(:pending_signature, petition: petition)
      signature.validate!

      expect(signature.petition.reload.signature_count).to eq(7)
      expect(signature.number).to eq(7)
    end

    it "is scoped to the petition" do
      other_signature = FactoryBot.create(:pending_signature, petition: other_petition)
      other_signature.validate!

      signature = FactoryBot.create(:pending_signature, petition: petition)
      signature.validate!

      expect(other_signature.petition.reload.signature_count).to eq(7)
      expect(other_signature.number).to eq(7)

      expect(signature.petition.reload.signature_count).to eq(7)
      expect(signature.number).to eq(7)
    end

    it "remains the same after another signature is added" do
      signature = FactoryBot.create(:pending_signature, petition: petition)
      later_signature = FactoryBot.create(:pending_signature, petition: petition)
      signature.validate!

      expect { later_signature.validate! }.not_to change{ signature.number }
    end

    it "remains the same even if an earlier signature is validated" do
      earlier_signature = FactoryBot.create(:pending_signature, petition: petition)
      signature = FactoryBot.create(:pending_signature, petition: petition)
      signature.validate!

      expect { earlier_signature.validate! }.not_to change{ signature.number }
    end
  end

  describe "#pending?" do
    it "returns true if the signature has a pending state" do
      signature = FactoryBot.build(:pending_signature)
      expect(signature.pending?).to be_truthy
    end

    (Signature::STATES - [Signature::PENDING_STATE]).each do |state|
      it "returns false if the signature is #{state} state" do
        signature = FactoryBot.build(:"#{state}_signature")
        expect(signature.pending?).to be_falsey
      end
    end
  end

  describe "#fraudulent?" do
    it "returns true if the signature has a fraudulent state" do
      signature = FactoryBot.build(:fraudulent_signature)
      expect(signature.fraudulent?).to be_truthy
    end

    (Signature::STATES - [Signature::FRAUDULENT_STATE]).each do |state|
      it "returns false if the signature is #{state} state" do
        signature = FactoryBot.build(:"#{state}_signature")
        expect(signature.fraudulent?).to be_falsey
      end
    end
  end

  describe "#validated?" do
    it "returns true if the signature has a validated state" do
      signature = FactoryBot.build(:validated_signature)
      expect(signature.validated?).to be_truthy
    end

    (Signature::STATES - [Signature::VALIDATED_STATE]).each do |state|
      it "returns false if the signature is #{state} state" do
        signature = FactoryBot.build(:"#{state}_signature")
        expect(signature.validated?).to be_falsey
      end
    end
  end

  describe "#invalidated?" do
    it "returns true if the signature has an invalidated state" do
      signature = FactoryBot.build(:invalidated_signature)
      expect(signature.invalidated?).to be_truthy
    end

    (Signature::STATES - [Signature::INVALIDATED_STATE]).each do |state|
      it "returns false if the signature is #{state} state" do
        signature = FactoryBot.build(:"#{state}_signature")
        expect(signature.invalidated?).to be_falsey
      end
    end
  end

  describe '#creator?' do
    let(:petition) { FactoryBot.create(:petition) }
    let(:signature) { FactoryBot.create(:signature, petition: petition) }
    let(:creator) { petition.creator }

    it 'is true if the signature is the creator for the petition it belongs to' do
      expect(creator.creator?).to be_truthy
    end

    it 'is false if the signature is not the creator for the petition it belongs to' do
      expect(signature.creator?).to be_falsey
    end
  end

  describe '#sponsor?' do
    let(:petition) { FactoryBot.create(:petition) }
    let(:sponsor) { FactoryBot.create(:sponsor, petition: petition) }
    let(:signature) { FactoryBot.create(:signature, petition: petition) }

    it 'is true if the signature is a sponsor signature for the petition it belongs to' do
      expect(sponsor.sponsor?).to be_truthy
    end

    it 'is false if the signature is not a sponsor signature for the petition it belongs to' do
      expect(signature.sponsor?).to be_falsey
    end
  end

  describe '#validate!' do
    let(:signature) { FactoryBot.create(:pending_signature, attributes) }
    let(:location_code) { "GB" }
    let(:postcode) { "SW1A 1AA" }

    let (:attributes) do
      {
        petition: petition,
        name: "Suzy Signer",
        email: "suzy@example.com",
        postcode: postcode,
        location_code: location_code,
        uk_citizenship: "1",
        created_at: 2.days.ago,
        updated_at: 2.days.ago
      }
    end

    context "when the petition is open" do
      let(:petition) { FactoryBot.create(:open_petition, created_at: 2.days.ago, updated_at: 2.days.ago) }

      it "transitions the signature to the validated state" do
        signature.validate!
        expect(signature).to be_validated
      end

      it "timestamps the signature to say it was updated just now" do
        signature.validate!
        expect(signature.updated_at).to be_within(1.second).of(Time.current)
      end

      it "timestamps the signature to say it was validated just now" do
        signature.validate!
        expect(signature.validated_at).to be_within(1.second).of(Time.current)
      end

      it "increments the petition count" do
        expect{ signature.validate! }.to change{ petition.reload.signature_count }.by(1)
      end

      it "updates the petition to say it was updated just now" do
        signature.validate!
        expect(petition.reload.updated_at).to be_within(1.second).of(Time.current)
      end

      it "updates the petition to say it was last signed at just now" do
        signature.validate!
        expect(petition.reload.last_signed_at).to be_within(1.second).of(Time.current)
      end

      it "doesn't increment the petition count twice" do
        signature.validate!
        expect{ signature.validate! }.to change{ petition.reload.signature_count }.by(0)
      end

      it "generates a signed_token if it's missing" do
        signature.update_column(:signed_token, nil)

        expect {
          signature.validate!
        }.to change {
          signature.reload[:signed_token]
        }.from(nil).to(be_present)
      end

      it 'tells the relevant constituency petition journal to record a new signature' do
        expect(ConstituencyPetitionJournal).to receive(:record_new_signature_for).with(signature)
        signature.validate!
      end

      it 'does not talk to the constituency petition journal if the signature is not pending' do
        expect(ConstituencyPetitionJournal).not_to receive(:record_new_signature_for)
        signature.update_columns(state: Signature::VALIDATED_STATE)
        signature.validate!
      end

      it 'tells the relevant country petition journal to record a new signature' do
        expect(CountryPetitionJournal).to receive(:record_new_signature_for).with(signature)
        signature.validate!
      end

      it 'does not talk to the country petition journal if the signature is not pending' do
        expect(CountryPetitionJournal).not_to receive(:record_new_signature_for)
        signature.update_columns(state: Signature::VALIDATED_STATE)
        signature.validate!
      end

      it "retries if the schema has changed" do
        expect(signature).to receive(:lock!).once.and_raise(PG::InFailedSqlTransaction)
        expect(signature).to receive(:lock!).once.and_call_original
        expect(signature.class.connection).to receive(:clear_cache!).once

        signature.validate!
        expect(signature).to be_validated
      end

      it "raises PG::InFailedSqlTransaction if it fails twice" do
        expect(signature).to receive(:lock!).twice.and_raise(PG::InFailedSqlTransaction)
        expect{ signature.validate! }.to raise_error(PG::InFailedSqlTransaction)
      end

      context "and the signer is from the UK" do
        let(:location_code) { "GB" }

        context "and the postcode is valid" do
          let(:postcode) { "SW1A 1AA" }

          it "calls the Constituency API and sets the constituency_id" do
            expect(Constituency).to receive(:find_by_postcode).with("SW1A1AA").and_call_original

            signature.validate!

            expect(signature).to be_validated
            expect(signature.constituency_id).to eq("3415")
          end
        end

        context "and the postcode is invalid" do
          let(:postcode) { "SW14 9RQ" }

          it "calls the Constituency API but doesn't set constituency_id" do
            expect(Constituency).to receive(:find_by_postcode).with("SW149RQ").and_call_original

            signature.validate!

            expect(signature).to be_validated
            expect(signature.constituency_id).to be_nil
          end
        end
      end

      context "and the signer is not from the UK" do
        let(:location_code) { "US" }

        context "and the postcode is set" do
          let(:postcode) { "12345" }

          it "doesn't call the Constituency API and doesn't set constituency_id" do
            expect(Constituency).not_to receive(:find_by_postcode)

            signature.validate!

            expect(signature).to be_validated
            expect(signature.constituency_id).to be_nil
          end
        end

        context "and the postcode is blank" do
          let(:postcode) { "" }

          it "doesn't call the Constituency API and doesn't set constituency_id" do
            expect(Constituency).not_to receive(:find_by_postcode)

            signature.validate!

            expect(signature).to be_validated
            expect(signature.constituency_id).to be_nil
          end
        end
      end
    end
  end

  describe '#invalidate!' do
    let!(:petition) { FactoryBot.create(:open_petition, created_at: 2.days.ago, updated_at: 2.days.ago) }
    let!(:signature) { FactoryBot.create(:validated_signature, petition: petition, created_at: 2.days.ago, updated_at: 2.days.ago) }
    let(:now) { Time.current }

    it "transitions the signature to the validated state" do
      signature.invalidate!
      expect(signature).to be_invalidated
    end

    it "timestamps the signature to say it was updated just now" do
      signature.invalidate!
      expect(signature.updated_at).to be_within(1.second).of(Time.current)
    end

    it "sets notify_by_email to false" do
      expect {
        signature.invalidate!
      }.to change {
        signature.reload.notify_by_email?
      }.from(true).to(false)
    end

    it "timestamps the signature to say it was invalidated just now" do
      signature.invalidate!
      expect(signature.invalidated_at).to be_within(1.second).of(Time.current)
    end

    it "decrements the petition count" do
      expect{ signature.invalidate! }.to change{ petition.reload.signature_count }.by(-1)
    end

    it "updates the petition to say it was updated just now" do
      signature.invalidate!
      expect(petition.reload.updated_at).to be_within(1.second).of(Time.current)
    end

    it "doesn't decrement the petition count twice" do
      signature.invalidate!
      expect{ signature.invalidate! }.to change{ petition.reload.signature_count }.by(0)
    end

    it 'tells the relevant constituency petition journal to invalidate the signature' do
      expect(ConstituencyPetitionJournal).to receive(:invalidate_signature_for).with(signature, now)
      signature.invalidate!(now)
    end

    it 'does not talk to the constituency petition journal if the signature is not validated' do
      expect(ConstituencyPetitionJournal).not_to receive(:invalidate_signature_for)
      signature.update_columns(state: Signature::INVALIDATED_STATE)
      signature.invalidate!
    end

    it 'tells the relevant country petition journal to invalidate the signature' do
      expect(CountryPetitionJournal).to receive(:invalidate_signature_for).with(signature, now)
      signature.invalidate!(now)
    end

    it 'does not talk to the country petition journal if the signature is not validated' do
      expect(CountryPetitionJournal).not_to receive(:invalidate_signature_for)
      signature.update_columns(state: Signature::INVALIDATED_STATE)
      signature.invalidate!
    end

    it "retries if the schema has changed" do
      expect(signature).to receive(:lock!).once.and_raise(PG::InFailedSqlTransaction)
      expect(signature).to receive(:lock!).once.and_call_original
      expect(signature.class.connection).to receive(:clear_cache!).once

      signature.invalidate!
      expect(signature).to be_invalidated
    end

    it "raises PG::InFailedSqlTransaction if it fails twice" do
      expect(signature).to receive(:lock!).twice.and_raise(PG::InFailedSqlTransaction)
      expect{ signature.invalidate! }.to raise_error(PG::InFailedSqlTransaction)
    end
  end

  describe "#save" do
    let(:petition) { FactoryBot.create(:petition, creator_attributes: { name: "Alice", email: "aliceandbob@example.com" }) }

    before do
      FactoryBot.create(:validated_signature, name: "Bob", email: "aliceandbob@example.com", petition: petition)
    end

    context "when the new creator hasn't already signed" do
      it "saves the new name" do
        expect(petition.update(creator_attributes: { name: "Fred" })).to be_truthy
      end
    end

    context "when the new creator has already signed" do
      it "doesn't save the new name" do
        expect(petition.update(creator_attributes: { name: "Bob" })).to be_falsey
      end

      it "adds an error to the name attribute" do
        expect {
          petition.update(creator_attributes: { name: "Bob" })
        }.to change {
          petition.creator.errors[:name]
        }.from([]).to(["Bob has already signed this petition using aliceandbob@example.com"])
      end
    end
  end

  describe "#unsubscribe" do
    let(:signature) { FactoryBot.create(:validated_signature, notify_by_email: subscribed) }
    let(:unsubscribe_token) { signature.unsubscribe_token }

    before do
      signature.unsubscribe!(unsubscribe_token)
    end

    context "when subcribed" do
      let(:subscribed) { true }

      it "changes the subscription status" do
        expect(signature.notify_by_email).to be_falsey
      end

      it "doesn't add an error to the :base attribute" do
        expect(signature.errors[:base]).to be_empty
      end
    end

    context "when already unsubcribed" do
      let(:subscribed) { false }

      it "doesn't change the subscription status" do
        expect(signature.notify_by_email).to be_falsey
      end

      it "adds an error to the :base attribute" do
        expect(signature.errors[:base]).to include("Already Unsubscribed")
      end
    end

    context "when token is invalid" do
      let(:subscribed) { true }
      let(:unsubscribe_token) { "invalid token" }

      it "doesn't change the subscription status" do
        expect(signature.notify_by_email).to be_truthy
      end

      it "adds an error to the :base attribute" do
        expect(signature.errors[:base]).to include("Invalid Unsubscribe Token")
      end
    end
  end

  describe "#already_unsubscribed?" do
    let(:signature) { FactoryBot.create(:validated_signature) }

    context "when there is no error on the :base attribute" do
      it "returns false" do
        expect(signature.already_unsubscribed?).to be_falsey
      end
    end

    context "when there is an error on the :base attribute" do
      before do
        signature.errors.add(:base, "Already Unsubscribed")
      end

      it "returns true" do
        expect(signature.already_unsubscribed?).to be_truthy
      end
    end
  end

  describe "#invalid_unsubscribe_token?" do
    let(:signature) { FactoryBot.create(:validated_signature) }

    context "when there is no error on the :base attribute" do
      it "returns false" do
        expect(signature.invalid_unsubscribe_token?).to be_falsey
      end
    end

    context "when there is an error on the :base attribute" do
      before do
        signature.errors.add(:base, "Invalid Unsubscribe Token")
      end

      it "returns true" do
        expect(signature.invalid_unsubscribe_token?).to be_truthy
      end
    end
  end

  describe "#subscribed?" do
    context "when the signature is pending" do
      let(:signature) { FactoryBot.build(:pending_signature, notify_by_email: true) }

      it "returns false" do
        expect(signature.subscribed?).to eq(false)
      end
    end

    context "when the signature is validated" do
      context "and notify_by_email is true" do
        let(:signature) { FactoryBot.build(:validated_signature, notify_by_email: true) }

        it "returns true" do
          expect(signature.subscribed?).to eq(true)
        end
      end

      context "and notify_by_email is false" do
        let(:signature) { FactoryBot.build(:validated_signature, notify_by_email: false) }

        it "returns false" do
          expect(signature.subscribed?).to eq(false)
        end
      end
    end

    context "when the signature is fraudulent" do
      let(:signature) { FactoryBot.build(:fraudulent_signature, notify_by_email: true) }

      it "returns false" do
        expect(signature.subscribed?).to eq(false)
      end
    end

    context "when the signature is invalidated" do
      let(:signature) { FactoryBot.build(:invalidated_signature, notify_by_email: true) }

      it "returns false" do
        expect(signature.subscribed?).to eq(false)
      end
    end
  end

  describe "#constituency" do
    let(:signature) { FactoryBot.build(:signature, attributes) }
    let(:constituency) { signature.constituency }
    let(:location_code) { "GB" }

    let(:attributes) do
      { postcode: postcode, constituency_id: constituency_id }
    end

    context "when the constituency_id is not set" do
      let(:constituency_id) { nil }

      context "and the signature is not from the UK" do
        let(:postcode) { "12345" }

        it "returns nil" do
          expect(signature).to receive(:united_kingdom?).and_return(false)
          expect(Constituency).not_to receive(:find_by_postcode)
          expect(signature.constituency).to be_nil
        end
      end

      context "and the API returns a single result" do
        let(:postcode) { "N1 1TY" }

        before do
          stub_api_request_for("N11TY").to_return(api_response(:ok, "single"))
        end

        it "returns the correct constituency" do
          expect(Constituency).to receive(:find_by_postcode).with("N11TY").and_call_original
          expect(constituency.name).to eq("Islington South and Finsbury")
        end
      end

      context "and the API returns multiple result" do
        let(:postcode) { "N1" }

        before do
          stub_api_request_for("N1").to_return(api_response(:ok, "multiple"))
        end

        it "returns the correct constituency" do
          expect(Constituency).to receive(:find_by_postcode).with("N1").and_call_original
          expect(constituency.name).to eq("Hackney North and Stoke Newington")
        end
      end

      context "and the API returns no results" do
        let(:postcode) { "SW14 9RQ" }

        before do
          stub_api_request_for("SW149RQ").to_return(api_response(:ok, "no_results"))
        end

        it "returns nil" do
          expect(Constituency).to receive(:find_by_postcode).with("SW149RQ").and_call_original
          expect(constituency).to be_nil
        end
      end

      context "and the API raises an error" do
        let(:postcode) { "N1 1TY" }

        before do
          stub_api_request_for("N11TY").to_timeout
        end

        it "returns nil" do
          expect(Constituency).to receive(:find_by_postcode).with("N11TY").and_call_original
          expect(constituency).to be_nil
        end
      end
    end

    context "when the constituency_id is set" do
      let(:constituency_id) { "3415" }
      let(:postcode) { "SW1A 1AA" }

      it "searches the database for the constituency" do
        expect(Constituency).not_to receive(:find_by_postcode)
        expect(Constituency).to receive(:find_by_external_id).with("3415").and_call_original
        expect(constituency.name).to eq("Cities of London and Westminster")
      end
    end
  end

  describe "#signed_token" do
    let(:signature) { FactoryBot.create(:validated_signature) }

    context "when the underlying column is nil" do
      before do
        signature.update_column(:signed_token, nil)
      end

      it "generates and saves a new token" do
        expect {
          signature.signed_token
        }.to change {
          signature.reload[:signed_token]
        }.from(nil).to(be_present)
      end
    end

    context "when another process has updated the column" do
      let(:token) { Authlogic::Random.friendly_token }

      before do
        signature.update_column(:signed_token, nil)
      end

      it "returns the token from the database" do
        expect(signature).to receive(:signed_token?).and_return(true)
        expect(signature).to receive(:read_attribute).with(:signed_token).and_return(token)
        expect(signature.signed_token).to eq(token)
      end
    end
  end

  describe 'email sent timestamps' do
    describe '#get_email_sent_at_for' do
      let(:signature) { FactoryBot.create(:validated_signature) }
      let(:the_stored_time) { 6.days.ago }

      [
        %w[government_response government_response_email_at],
        %w[debate_scheduled debate_scheduled_email_at],
        %w[debate_outcome debate_outcome_email_at],
        %w[petition_email petition_email_at]
      ].each do |timestamp, column|

        context "when the timestamp '#{timestamp}' is not set" do
          it "returns nil" do
            expect(signature.get_email_sent_at_for(timestamp)).to be_nil
          end
        end

        context "when the timestamp '#{timestamp}' is set" do
          before do
            signature.update_column(column, the_stored_time)
          end

          it "returns the stored timestamp" do
            expect(signature.get_email_sent_at_for(timestamp)).to eq(the_stored_time)
          end
        end

      end
    end

    describe '#set_email_sent_at_for' do
      let(:signature) { FactoryBot.create(:validated_signature) }
      let(:the_stored_time) { 6.days.ago }

      [
        %w[government_response government_response_email_at],
        %w[debate_scheduled debate_scheduled_email_at],
        %w[debate_outcome debate_outcome_email_at],
        %w[petition_email petition_email_at]
      ].each do |timestamp, column|

        context "when a time is supplied for timestamp '#{timestamp}'" do
          it "sets the column to the supplied time" do
            expect {
              signature.set_email_sent_at_for(timestamp, to: the_stored_time)
            }.to change {
              signature.reload[column]
            }.from(nil).to(be_within(0.001.second).of(the_stored_time))
          end
        end

        context "when a time is not supplied for timestamp '#{timestamp}'" do
          it "sets the column to the current time" do
            expect {
              signature.set_email_sent_at_for(timestamp)
            }.to change {
              signature.reload[column]
            }.from(nil).to(be_within(1.second).of(Time.current))
          end
        end

      end
    end

    describe "#need_emailing_for" do
      let!(:a_signature) { FactoryBot.create(:validated_signature) }
      let!(:another_signature) { FactoryBot.create(:validated_signature) }
      let(:since_timestamp) { 5.days.ago }

      subject { Signature.need_emailing_for('government_response', since: since_timestamp) }

      it "does not return those that do not want to be emailed" do
        a_signature.update_attribute(:notify_by_email, false)
        expect(subject).not_to include a_signature
      end

      it "does not return unvalidated signatures" do
        another_signature.update_column(:state, Signature::PENDING_STATE)
        expect(subject).not_to include another_signature
      end

      it "does not return signatures that have a sent timestamp newer than the petitions requested receipt" do
        another_signature.set_email_sent_at_for('government_response', to: since_timestamp + 1.day)
        expect(subject).not_to include another_signature
      end

      it "does not return signatures that have a sent timestamp equal to the petitions requested receipt" do
        another_signature.set_email_sent_at_for('government_response', to: since_timestamp)
        expect(subject).not_to include another_signature
      end

      it "does return signatures that have a sent timestamp older than the petitions requested receipt" do
        another_signature.set_email_sent_at_for('government_response', to: since_timestamp - 1.day)
        expect(subject).to include another_signature
      end

      it "returns signatures that have null for the requested timestamp" do
        a_signature.update_column(:government_response_email_at, nil)
        expect(subject).to match_array [a_signature, another_signature]
      end
    end
  end

  describe "#email_count" do
    it "returns 0 for new signatures" do
      signature = FactoryBot.create(:pending_signature)
      expect(signature.email_count).to be(0)
    end
  end

  describe "#email_threshold_reached?" do
    let(:email_count_threshold) { 5 }

    it "returns false when the signature hasn't reached the threshold" do
      signature = FactoryBot.create(:validated_signature)
      expect(signature.email_threshold_reached?).to be false
    end

    it "returns true when the signature is at the email count threshold" do
      signature = FactoryBot.create(:validated_signature, email_count: email_count_threshold)
      expect(signature.email_threshold_reached?).to be true
    end
  end

  describe "#find_duplicate" do
    let(:petition) { FactoryBot.create(:open_petition) }
    let(:other_petition) { FactoryBot.create(:open_petition) }
    let(:signature) { petition.signatures.build(attributes) }
    let(:name) { "Suzy Signer" }
    let(:postcode) { "SW1A 1AA" }
    let(:email) { "foo@example.com" }

    let(:attributes) do
      {
        name: name,
        email: email,
        postcode: postcode,
        location_code: "GB",
        uk_citizenship: "1"
      }
    end

    context "when a signature doesn't already exist with the same email address" do
      it "returns nil" do
        expect(signature.find_duplicate).to be_nil
      end
    end

    context "when a signature already exists with the same email address" do
      before do
        petition.signatures.create!(
          name: "Suzy Signer",
          email: "foo@example.com",
          postcode: "SW1A 1AA",
          location_code: "GB",
          uk_citizenship: "1"
        )
      end

      context "and the name is the same" do
        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name is the same but different case" do
        let(:name) { "suzy signer" }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name is the same but with extra whitespace" do
        let(:name) { " Suzy  Signer " }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name is different" do
        let(:name) { "Sam Signer" }

        it "returns nil" do
          expect(signature.find_duplicate).to be_nil
        end
      end

      context "and the postcode is different" do
        let(:postcode) { "SW1A 1AB" }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name and postcode are different" do
        let(:name) { "Sam Signer" }
        let(:postcode) { "SW1A 1AB" }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name is the same, but is scoped to a different petition" do
        let(:signature) { other_petition.signatures.build(attributes) }

        it "returns nil" do
          expect(signature.find_duplicate).to be_nil
        end
      end

      context "but the email is a different case" do
        let(:email) { "FOO@example.com" }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end
    end

    context "when two signatures already exists with the same email address" do
      before do
        petition.signatures.create!(
          name: "Suzy Signer",
          email: "foo@example.com",
          postcode: "SW1A 1AA",
          location_code: "GB",
          uk_citizenship: "1"
        )

        petition.signatures.create!(
          name: "Sam Signer",
          email: "foo@example.com",
          postcode: "SW1A 1AA",
          location_code: "GB",
          uk_citizenship: "1"
        )
      end

      context "and the name is the same" do
        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end

      context "and the name is different" do
        let(:name) { "Sue Signer" }

        it "returns the signature" do
          expect(signature.find_duplicate).to be_present
        end
      end
    end
  end

  describe "#find_duplicate!" do
    let(:petition) { FactoryBot.create(:open_petition) }
    let(:signature) { petition.signatures.build(attributes) }

    let(:attributes) do
      {
        name: "Suzy Signer",
        email: "foo@example.com",
        postcode: "SW1A 1AA",
        location_code: "GB",
        uk_citizenship: "1"
      }
    end

    context "when a duplicate signature doesn't exist" do
      it "raises an ActiveRecord::RecordNotFound exception" do
        expect { signature.find_duplicate! }.to raise_exception(ActiveRecord::RecordNotFound)
      end
    end

    context "when a duplicate signature does exist" do
      before do
        petition.signatures.create!(attributes)
      end

      it "returns the signature" do
        expect(signature.find_duplicate!).to be_present
      end
    end
  end
end


text:
<?php

namespace Synapse\Db;

use Silex\Application;
use Silex\ServiceProviderInterface;
use Synapse\Db\Adapter\Adapter;
use Synapse\Db\Transaction;
use Synapse\Mapper\SqlFactory;
use Zend\Db\Sql\Sql;

/**
 * Provider for Zend database services
 */
class DbServiceProvider implements ServiceProviderInterface
{
    /**
     * Register the database adapter
     *
     * @param  Application $app Silex application
     */
    public function register(Application $app)
    {
        $app['db'] = $app->share(function ($app) {
            return new Adapter($app['config']->load('db'));
        });

        $app['db.transaction'] = $app->share(function ($app) {
            return new Transaction($app['db']);
        });

        $app->initializer(
            'Synapse\\Db\\TransactionAwareInterface',
            function ($object, $app) {
                $object->setTransaction($app['db.transaction']);
                return $object;
            }
        );

        $this->registerMapperInitializer($app);
    }

    /**
     * Perform extra chores on boot (none needed here)
     *
     * @param  Application $app
     */
    public function boot(Application $app)
    {
        // noop
    }

    /**
     * Register an initializer that injects a SQL Factory into all AbstractMappers
     *
     * @param  Application $app
     */
    protected function registerMapperInitializer(Application $app)
    {
        $initializer = function ($mapper, $app) {
            $mapper->setSqlFactory(new SqlFactory);
        };

        $app->initializer('Synapse\Mapper\AbstractMapper', $initializer);
    }
}

redpajama_set_name: RedPajamaGithub


text:
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MongoBackupDetails.cs" company="Naos Project">
//    Copyright (c) Naos Project 2019. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Naos.Database.Mongo.Domain
{
    using System;

    /// <summary>
    /// Captures the details of a backup operation.
    /// </summary>
    public class MongoBackupDetails
    {
        /// <summary>
        /// Gets or sets the name of the backup (not the name of the backup file,
        /// but rather the name of the backup set identifying the backup within the file).
        /// If not specified, it is blank.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets a description of the backup.
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the location at which to save the backup (i.e. file path or URL).
        /// For local/network storage, must be a file and NOT a directory (i.e. c:\MyBackups\TodayBackup.bak, not c:\MyBackups).
        /// </summary>
        public Uri BackupTo { get; set; }

        /// <summary>
        /// Gets or sets the name of the credential to use when backing up to a URL.
        /// </summary>
        public string Credential { get; set; }
    }
}


text: A weather android application


text:
'use strict';

var debug = require('debuglog')('connect:diskdb'),
    DiskDB = require('diskdb'),
    _ = require('lodash'),
    DiskDBStore;

module.exports = function (connect) {

    var Store = connect.Store;

    DiskDBStore = function DiskDBStore (options) {
        options = options || {};
        Store.call(this, options);
        this.db = options.db || DiskDB.connect(options.path, [options.name])[options.name];
        this.prefix = this.prefix || 'sess:';
    };

    /**
    * Inherit from `Store`.
    *
    */
    DiskDBStore.prototype.__proto__ = Store.prototype;

    /**
    * Attempt to fetch session by the given `sessionId`.
    *
    * @param {String} sessionId
    * @param {Function} callback
    * @api public
    */
    DiskDBStore.prototype.get = function (sessionId, callback) {
        sessionId = this.prefix + sessionId;
        debug('GET "%s"', sessionId);
        var data = this.db.findOne({
            sessionId:sessionId
        });
        debug('GOT %j', data);
        callback(null, data);
    };

    /**
    * Commit the given `session` object associated with the given `sessionId`.
    *
    * @param {String} sessionId
    * @param {Session} session
    * @param {Function} callback
    * @api public
    */
    DiskDBStore.prototype.set = function (sessionId, session, callback) {
        sessionId = this.prefix + sessionId;
        debug('SET "%s" : %j', sessionId, session);
        callback(null, this.db.update(
            {sessionId: sessionId},
            _.extend({sessionId: sessionId}, session),
            {upsert: true}
        ));
    };

    /**
    * Destroy the session associated with the given `sessionId`.
    *
    * @param {String} sessionId
    * @api public
    */
    DiskDBStore.prototype.destroy = function(sessionId, callback) {
        debug('DESTROY %s', sessionId);
        sessionId = this.prefix + sessionId;
        callback(null, this.db.remove({
            sessionId:sessionId
        }, false));
    };

    return DiskDBStore;
};


text:
namespace Microsoft.Azure.Management.Relay.Models
{
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;
    using System.Runtime;
    using System.Runtime.Serialization;

    /// <summary>
    /// Defines values for UnavailableReason.
    /// </summary>
    [JsonConverter(typeof(StringEnumConverter))]
    public enum UnavailableReason
    {
        [EnumMember(Value = "None")]
        None,
        [EnumMember(Value = "InvalidName")]
        InvalidName,
        [EnumMember(Value = "SubscriptionIsDisabled")]
        SubscriptionIsDisabled,
        [EnumMember(Value = "NameInUse")]
        NameInUse,
        [EnumMember(Value = "NameInLockdown")]
        NameInLockdown,
        [EnumMember(Value = "TooManyNamespaceInCurrentSubscription")]
        TooManyNamespaceInCurrentSubscription
    }
    internal static class UnavailableReasonEnumExtension
    {
        internal static string ToSerializedValue(this UnavailableReason? value)
        {
            return value == null ? null : ((UnavailableReason)value).ToSerializedValue();
        }

        internal static string ToSerializedValue(this UnavailableReason value)
        {
            switch( value )
            {
                case UnavailableReason.None:
                    return "None";
                case UnavailableReason.InvalidName:
                    return "InvalidName";
                case UnavailableReason.SubscriptionIsDisabled:
                    return "SubscriptionIsDisabled";
                case UnavailableReason.NameInUse:
                    return "NameInUse";
                case UnavailableReason.NameInLockdown:
                    return "NameInLockdown";
                case UnavailableReason.TooManyNamespaceInCurrentSubscription:
                    return "TooManyNamespaceInCurrentSubscription";
            }
            return null;
        }

        internal static UnavailableReason? ParseUnavailableReason(this string value)
        {
            switch( value )
            {
                case "None":
                    return UnavailableReason.None;
                case "InvalidName":
                    return UnavailableReason.InvalidName;
                case "SubscriptionIsDisabled":
                    return UnavailableReason.SubscriptionIsDisabled;
                case "NameInUse":
                    return UnavailableReason.NameInUse;
                case "NameInLockdown":
                    return UnavailableReason.NameInLockdown;
                case "TooManyNamespaceInCurrentSubscription":
                    return UnavailableReason.TooManyNamespaceInCurrentSubscription;
            }
            return null;
        }
    }
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SM2Core.Items {
	public interface Tool: Item {
	}
}


text:
namespace App.Metrics.Counter
{
    /// <summary>
    ///     Combines the value for a counter with the defined unit for the value.
    /// </summary>
    public sealed class CounterValueSource : MetricValueSourceBase<CounterValue>
    {
        /// <summary>
        ///     Initializes a new instance of the <see cref="CounterValueSource" /> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="value">The value.</param>
        /// <param name="unit">The unit.</param>
        /// <param name="tags">The tags.</param>
        /// <param name="resetOnReporting">if set to <c>true</c> [reset on reporting]. Defaults to <c>false</c>.</param>
        /// <param name="reportItemPercentages">if set to <c>true</c> [report item percentages]. Defaults to <c>true</c></param>
        /// <param name="reportSetItems">if set to <c>true</c> [report set items]. Defaults to <c>true</c></param>
        public CounterValueSource(
            string name,
            IMetricValueProvider<CounterValue> value,
            Unit unit,
            MetricTags tags,
            bool resetOnReporting = false,
            bool reportItemPercentages = true,
            bool reportSetItems = true)
            : base(name, value, unit, tags, resetOnReporting)
        {
            ReportItemPercentages = reportItemPercentages;
            ReportSetItems = reportSetItems;
        }

        public bool ReportItemPercentages { get; }

        public bool ReportSetItems { get; }
    }
}


text:
package org.nschmidt.ldparteditor.composite;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.wb.swt.SWTResourceManager;

/**
 * This is the separator for any toolbar group.
 */
public class ToolSeparator extends Composite {

    ToolSeparator(Composite parent, int style, boolean isHorizontal) {
        super(parent, style);
        this.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
        if (isHorizontal) {
            this.setLayoutData(new RowData(1, 25));
        } else {
            this.setLayoutData(new RowData(25, 1));
        }
    }
}


text:
import com.code_intelligence.jazzer.api.FuzzedDataProvider;

import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.commons.configuration2.YAMLConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;

public class YAMLConfigurationReadFuzzer {
    public static void fuzzerTestOneInput(byte[] data) {
        // Create needed objects
        YAMLConfiguration yamlConfig = new YAMLConfiguration();
        InputStream inputStream = new ByteArrayInputStream(data);

        try {
            yamlConfig.read(inputStream);
        } catch (ConfigurationException ignored) {
            // expected Exceptions get ignored
        }
    }
}


text:
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {type PathCommands} from './common.js';

import {buildPath, drawPathWithLineStyle, emptyBounds, type LineStyle} from './highlight_common.js';

interface QueryingDescendantData {
  descendantBorder: PathCommands;
}
export interface ContainerQueryHighlight {
  containerBorder: PathCommands;
  queryingDescendants?: QueryingDescendantData[];
  containerQueryContainerHighlightConfig: {
    containerBorder?: LineStyle,
    descendantBorder?: LineStyle,
  };
}

export function drawContainerQueryHighlight(
    highlight: ContainerQueryHighlight, context: CanvasRenderingContext2D, emulationScaleFactor: number) {
  const config = highlight.containerQueryContainerHighlightConfig;
  const bounds = emptyBounds();
  const borderPath = buildPath(highlight.containerBorder, bounds, emulationScaleFactor);
  drawPathWithLineStyle(context, borderPath, config.containerBorder, 2 /* thicker container outline */);

  if (!highlight.queryingDescendants) {
    return;
  }

  for (const descendant of highlight.queryingDescendants) {
    const descendantBounds = emptyBounds();
    const descendantBorderPath = buildPath(descendant.descendantBorder, descendantBounds, emulationScaleFactor);
    drawPathWithLineStyle(context, descendantBorderPath, config.descendantBorder);
  }
}


text:
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif

#ifndef __G_APPLICATION_H__
#define __G_APPLICATION_H__

#include <glib-object.h>
#include <gio/giotypes.h>

G_BEGIN_DECLS

#define G_TYPE_APPLICATION              (g_application_get_type ())
#define G_APPLICATION(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_APPLICATION, GApplication))
#define G_APPLICATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_APPLICATION, GApplicationClass))
#define G_IS_APPLICATION(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_APPLICATION))
#define G_IS_APPLICATION_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_APPLICATION))
#define G_APPLICATION_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_APPLICATION, GApplicationClass))

typedef struct _GApplication            GApplication;
typedef struct _GApplicationPrivate     GApplicationPrivate;
typedef struct _GApplicationClass       GApplicationClass;

/**
 * GApplication:
 *
 * The <structname>GApplication</structname> structure contains private
 * data and should only be accessed using the provided API
 *
 * Since: 2.26
 */
struct _GApplication
{
  /*< private >*/
  GObject parent_instance;

  GApplicationPrivate *priv;
};

/**
 * GApplicationClass:
 * @action_with_data: class handler for the #GApplication::action-with-data signal
 * @quit_with_data: class handler for the #GApplication::quit-with-data signal
 * @prepare_activation: class handler for the #GApplication::prepare-activation signal
 * @run: virtual function, called by g_application_run()
 *
 * The <structname>GApplicationClass</structname> structure contains
 * private data only
 *
 * Since: 2.26
 */
struct _GApplicationClass
{
  /*< private >*/
  GObjectClass parent_class;

  /*< public >*/
  /* signals */
  void        (* action_with_data) (GApplication *application,
				    const gchar  *action_name,
				    GVariant     *platform_data);
  gboolean    (* quit_with_data)   (GApplication *application,
				    GVariant     *platform_data);
  void        (* prepare_activation)   (GApplication  *application,
                                        GVariant      *arguments,
                                        GVariant      *platform_data);

  /* vfuncs */
  void        (* run)    (GApplication *application);

  /*< private >*/
  /* Padding for future expansion */
  void (*_g_reserved1) (void);
  void (*_g_reserved2) (void);
  void (*_g_reserved3) (void);
  void (*_g_reserved4) (void);
  void (*_g_reserved5) (void);
  void (*_g_reserved6) (void);
};
GType                   g_application_get_type                  (void) G_GNUC_CONST;

GApplication *          g_application_new                       (const gchar      *appid,
								 int               argc,
								 char            **argv);

GApplication *          g_application_try_new                   (const gchar      *appid,
								 int               argc,
								 char            **argv,
								 GError          **error);

GApplication *          g_application_unregistered_try_new      (const gchar      *appid,
								 int               argc,
								 char            **argv,
								 GError          **error);

gboolean                g_application_register                  (GApplication      *application);

GApplication *          g_application_get_instance              (void);
G_CONST_RETURN gchar *  g_application_get_id                    (GApplication      *application);

void                    g_application_add_action                (GApplication      *application,
                                                                 const gchar       *name,
                                                                 const gchar       *description);
void                    g_application_remove_action             (GApplication      *application,
                                                                 const gchar       *name);
gchar **                g_application_list_actions              (GApplication      *application);
void                    g_application_set_action_enabled        (GApplication      *application,
                                                                 const gchar       *name,
                                                                 gboolean           enabled);
gboolean                g_application_get_action_enabled        (GApplication      *application,
                                                                 const gchar       *name);
G_CONST_RETURN gchar *  g_application_get_action_description    (GApplication      *application,
                                                                 const gchar       *name);
void                    g_application_invoke_action             (GApplication      *application,
                                                                 const gchar       *name,
                                                                 GVariant          *platform_data);

void                    g_application_run                       (GApplication      *application);
gboolean                g_application_quit_with_data            (GApplication      *application,
                                                                 GVariant          *platform_data);

gboolean                g_application_is_remote                 (GApplication      *application);

G_END_DECLS

#endif /* __G_APPLICATION_H__ */


text:
if command -v gpg-agent >/dev/null; then
  export GPG_TTY=$(tty)
  gpg-agent 2>&1 | grep -q "running and available" \
    || eval $(gpg-agent --daemon)
fi

# Helper for getting passphrase out of store
gpgphrase() {
  lpass show --field="Passphrase" "GPG"
}


text:
title: Problemas de instalação
---
# Problemas de instalação

Quando você executa o DrupalConsole do diretório raiz do Drupal 8, você pode obter mensagens de erro diferentes, tentaremos compilar os problemas relatados e como corrigi-los

---

Mensagem de erro:
```
[PDOException] SQLSTATE[HY000] [2002] No such file or directory
```
Você precisará editar a diretiva 'host' em seu arquivo 'settings.php'.

Navegue até `sites/default/settings.php`. No seu arquivo `settings.php` , mude a diretiva `host` para ler:
```
'host' => '127.0.0.1'
```
ou se o seu 'settings.php' já lê:
```
'host' => '127.0.0.1'
```
altere-o para ler:
```
'host' => 'localhost'.
```
Após realizar a alteração, certifique-se de salvar o arquivo e então executar o Drupal Console.

---

Mensagem de erro:
```
[PDOException]
SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/tmp/mysql.sock'
```
Criando um link simbólico apontando para `/tmp/mysql.sock`:
```
ln -s /path/to/your/mysql/data/mysql.sock /tmp/mysql.sock
```


text:
import Component from '@glimmer/component';
import {
  _destroyComponent,
  _insertComponent
} from '../../../utils/component/lifecycle';
import {
  deregisterElement,
  registerElement
} from '../../../utils/registration/element';
import { input, keyDown } from '../../../utils/select-box/input/keyboard';
import { action } from '@ember/object';
import buildId from '../../../utils/shared/id';

export default class SelectBoxInput extends Component {
  element = null;

  get id() {
    return buildId(this);
  }

  @action
  handleInsertElement(element) {
    registerElement(this, element);
    _insertComponent(this);
  }

  @action
  handleDestroyElement() {
    deregisterElement(this);
    _destroyComponent(this);
  }

  @action
  handleInput(e) {
    input(this, e);
  }

  @action
  handleKeyDown(e) {
    keyDown(this, e);
  }
}


text:
Shell Script for Auto MongoDB Backup to Amazon S3 Periodically

### How to use
You must initialize these variables in script (`mongo-bkg-s3.sh`):

`MONGODB_USER`       This is your Mongodb root user

`MONGODB_PASSWORD`   This is your Mongodb root user's password

`AWS_ACCESS_KEY`     This is the AWS Access Key where you want to store your backup

`AWS_SECRET_KEY`     This is the AWS Secret Key where you want to store your backup

`S3_REGION`          This is the Amazon S3 region where you want to store your backup

`S3_BUCKET`          This is the Amazon S3 bucket name where you want to store your backup

And run this command in terminal `bash /path-to/mongo-bkg-s3.sh`.

### How to run periodically

To edit cronjobs, run this command in terminal `sudo crontab -e` and choose option to your desire edittor.

Then add this line `0 1 * * * bash /path-to/mongo-bkg-s3.sh` in cronjobs to execute on everyday at 01:00 AM.

If you want to store the output in a log file, then use this one `0 1 * * * bash /path-to/mongo-bkg-s3.sh > /path-to/mongo-bkg-s3.log 2>&1`.

To view the list of cronjobs you can run: `sudo crontab -l`.


text:
package tmb.voltdb;

import org.voltdb.*;

// TODO(chasseur): This loads the entire bus state in one go, which could
// potentially overrun some VoltDB limits on result set size. Look into
// piecewise loading as an alternative.
public class LoadState extends VoltProcedure {
  public final SQLStmt getClientsSQL = new SQLStmt(
      "SELECT client_id FROM client WHERE disconnect_time IS NULL;");
  public final SQLStmt getSendableSQL = new SQLStmt(
      "SELECT client_id, type_id FROM sendable;");
  public final SQLStmt getReceivableSQL = new SQLStmt(
      "SELECT client_id, type_id FROM receivable;");
  public final SQLStmt getCancellableMessagesSQL = new SQLStmt(
      "SELECT message_id FROM cancellable_message;");
  public final SQLStmt getQueuedMessagesSQL = new SQLStmt(
      "SELECT * FROM queued_message;");

  public VoltTable[] run() throws VoltAbortException {
    voltQueueSQL(getClientsSQL);
    voltQueueSQL(getSendableSQL);
    voltQueueSQL(getReceivableSQL);
    voltQueueSQL(getCancellableMessagesSQL);
    voltQueueSQL(getQueuedMessagesSQL);

    return voltExecuteSQL();
  }
}


text:
import  * as MT from "./ModelTypes";

import { ErrorHandler } from "../helpers/ErrorHandler";
import { AttributeValidationError } from "../helpers/Errors";

export interface IAttributeDics {
    [key:string]: MT.MTBase<any>
}

export interface IAttributeItem {
    id: string, attribute: MT.MTBase<any>
}

export class ModelBase {

    protected static _proto;

    protected test: typeof ModelBase = ModelBase;
    protected test2 = 1;
    protected _attribute_errors: ErrorHandler<AttributeValidationError>;

    constructor( ) {
        this._attribute_errors = new ErrorHandler<AttributeValidationError>();
    }

    define( defs: Object ): boolean {
        var noError = true;
        this.static.getAttributeNames().forEach( ( name ) => {
            if( defs[ name ] != undefined ) {
                var attr: MT.MTBase<any> = this[name];
                try {
                    attr.value = defs[ name ];
                } catch( e ) {
                    noError = false;
                    this.errorHandler.add( e );
                }
            }
        });

        return noError;
    }

    static getAttributeNames():Array<string> {
        return this.getAttributes().map( ( item ) => {
            return item.id;
        } );
    }

    static getAttributes(sample?: ModelBase): Array<IAttributeItem> {

        var sample = sample||this.sample();

        return Object.keys( sample ).map( ( name ) => {
            return { id: name, attribute: sample[ name ] };
        } ).filter( ( item ) => {
            if( item.attribute instanceof MT.MTBase ) {
                return true;
            } else {
                return false;
            }
        } );
    }

    get errorHandler() { return this._attribute_errors; }

    protected get static(): typeof ModelBase {
        var self:any = this;
        var staticClass: typeof ModelBase  = self.__proto__.constructor;
        return staticClass;
    }

    protected static sample(): ModelBase {
        if ( this._proto ) {
            return this._proto;
        } else {
            return this._proto = (new this());
        }
    }
}


text:
from slicc.ast.DeclAST import DeclAST
from slicc.symbols import Var

class ObjDeclAST(DeclAST):
    def __init__(self, slicc, type_ast, ident, pairs, rvalue, pointer):
        super(ObjDeclAST, self).__init__(slicc, pairs)

        self.type_ast = type_ast
        self.ident = ident
        self.rvalue = rvalue
        self.pointer = pointer

    def __repr__(self):
        return "[ObjDecl: %r]" % self.ident

    def generate(self, parent = None):
        if "network" in self and not ("virtual_network" in self or
                                      "physical_network" in self) :
            self.error("Network queues require a 'virtual_network' attribute")

        type = self.type_ast.type

        # FIXME : should all use accessors here to avoid public member
        # variables
        if self.ident == "version":
            c_code = "m_version"
        elif self.ident == "machineID":
            c_code = "m_machineID"
        elif self.ident == "clusterID":
            c_code = "m_clusterID"
        else:
            c_code = "(*m_%s_ptr)" % (self.ident)

        # check type if this is a initialization
        init_code = ""
        if self.rvalue:
            rvalue_type,init_code = self.rvalue.inline(True)
            if type != rvalue_type:
                self.error("Initialization type mismatch '%s' and '%s'" % \
                           (type, rvalue_type))

        machine = self.symtab.state_machine

        v = Var(self.symtab, self.ident, self.location, type, c_code,
                self.pairs, machine)

        # Add data member to the parent type
        if parent:
            if not parent.addDataMember(self.ident, type, self.pairs, init_code):
                self.error("Duplicate data member: %s:%s" % (parent, self.ident))

        elif machine:
            machine.addObject(v)

        else:
            self.symtab.newSymbol(v)