# frozen_string_literal: true

describe Nanoc::CLI::Commands::ShowData, :stdio do
  describe '#print_item_dependencies' do
    subject { runner.send(:print_item_dependencies, items, dependency_store) }

    let(:runner) do
      described_class.new(options, arguments, command)
    end

    let(:options) { {} }
    let(:arguments) { [] }
    let(:command) { double(:command) }

    let(:items) do
      Nanoc::Core::ItemCollection.new(
        config,
        [
          item_about,
          item_dog,
          item_other,
        ],
      )
    end

    let(:item_about) { Nanoc::Core::Item.new('About Me', {}, '/about.md') }
    let(:item_dog)   { Nanoc::Core::Item.new('About My Dog', {}, '/dog.md') }
    let(:item_other) { Nanoc::Core::Item.new('Raw Data', {}, '/other.dat') }

    let(:config) { Nanoc::Core::Configuration.new(dir: Dir.getwd).with_defaults }

    let(:dependency_store) do
      Nanoc::Core::DependencyStore.new(items, layouts, config)
    end

    let(:layouts) do
      Nanoc::Core::LayoutCollection.new(config)
    end

    it 'prints a legend' do
      expect { subject }.to output(
        /Item dependencies =+\n\nLegend:/,
      ).to_stdout
    end

    context 'no dependencies' do
      it 'outputs no dependencies for /about.md' do
        expect { subject }.to output(
          %r{^item /about.md depends on:\n  \(nothing\)$}m,
        ).to_stdout
      end

      it 'outputs no dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \(nothing\)$}m,
        ).to_stdout
      end

      it 'outputs no dependencies for /other.dat' do
        expect { subject }.to output(
          %r{^item /other.dat depends on:\n  \(nothing\)$}m,
        ).to_stdout
      end
    end

    context 'dependency (with raw_content prop) from about to dog' do
      before do
        dependency_store.record_dependency(item_about, item_dog, raw_content: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[    item \] \(r___\) /about.md$}m,
        ).to_stdout
      end
    end

    context 'dependency (with attributes prop) from about to dog' do
      before do
        dependency_store.record_dependency(item_about, item_dog, attributes: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[    item \] \(_a__\) /about.md$}m,
        ).to_stdout
      end
    end

    context 'dependency (with attributes prop) from config to dog' do
      before do
        dependency_store.record_dependency(config, item_dog, attributes: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[  config \] \(_a__\)$}m,
        ).to_stdout
      end
    end

    context 'dependency (with compiled_content prop) from about to dog' do
      before do
        dependency_store.record_dependency(item_about, item_dog, compiled_content: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[    item \] \(__c_\) /about.md$}m,
        ).to_stdout
      end
    end

    context 'dependency (with path prop) from about to dog' do
      before do
        dependency_store.record_dependency(item_about, item_dog, path: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[    item \] \(___p\) /about.md$}m,
        ).to_stdout
      end
    end

    context 'dependency (with multiple props) from about to dog' do
      before do
        dependency_store.record_dependency(item_about, item_dog, attributes: true, raw_content: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[    item \] \(ra__\) /about.md$}m,
        ).to_stdout
      end
    end

    context 'dependency onto all items' do
      before do
        dependency_store.record_dependency(items, item_dog, raw_content: true)
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[   items \] \(r___\) matching any identifier$}m,
        ).to_stdout
      end
    end

    context 'dependency onto one specific item' do
      before do
        dependency_store.record_dependency(items, item_dog, raw_content: ['/about.*'])
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[   items \] \(r___\) matching identifier /about\.\*$}m,
        ).to_stdout
      end
    end

    context 'dependency onto multiple specific items' do
      before do
        dependency_store.record_dependency(items, item_dog, raw_content: ['/about.*'])
        dependency_store.record_dependency(items, item_dog, raw_content: ['/giraffe.*'])
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{
            ^item\ /dog.md\ depends\ on:\n\ \ \[\ \ \ items\ \]\ \(r___\)
            \ matching\ identifier\ /about\.\*\n\s+matching\ identifier\ /giraffe\.\*$
          }xm,
        ).to_stdout
      end
    end

    context 'dependency onto one specific layout' do
      before do
        dependency_store.record_dependency(layouts, item_dog, raw_content: ['/about.*'])
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{^item /dog.md depends on:\n  \[ layouts \] \(r___\) matching identifier /about\.\*$}m,
        ).to_stdout
      end
    end

    context 'dependency onto multiple specific layouts' do
      before do
        dependency_store.record_dependency(layouts, item_dog, raw_content: ['/about.*'])
        dependency_store.record_dependency(layouts, item_dog, raw_content: ['/giraffe.*'])
      end

      it 'outputs dependencies for /dog.md' do
        expect { subject }.to output(
          %r{
            ^item\ /dog.md\ depends\ on:\n\ \ \[\ layouts\ \]\ \(r___\)
            \ matching\ identifier\ /about\.\*\n\s+matching\ identifier\ /giraffe\.\*$
          }xm,
        ).to_stdout
      end
    end
  end

  describe '#print_item_rep_outdatedness' do
    subject { runner.send(:print_item_rep_outdatedness, items, outdatedness_checker, reps) }

    let(:runner) do
      described_class.new(options, arguments, command)
    end

    let(:options) { {} }
    let(:arguments) { [] }
    let(:command) { double(:command) }

    let(:config) { Nanoc::Core::Configuration.new(dir: Dir.getwd) }

    let(:items) do
      Nanoc::Core::ItemCollection.new(
        config,
        [
          item_about,
          item_dog,
        ],
      )
    end

    let(:item_about) { Nanoc::Core::Item.new('About Me', {}, '/about.md') }
    let(:item_dog)   { Nanoc::Core::Item.new('About My Dog', {}, '/dog.md') }

    let(:item_rep_about) { Nanoc::Core::ItemRep.new(item_about, :default) }
    let(:item_rep_dog)   { Nanoc::Core::ItemRep.new(item_dog, :default) }

    let(:site) { double(:site) }
    let(:outdatedness_checker) { double(:outdatedness_checker) }

    let(:reps) do
      {
        item_about => [item_rep_about],
        item_dog => [item_rep_dog],
      }
    end

    context 'not outdated' do
      before do
        allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(item_rep_about).and_return([])
        allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(item_rep_dog).and_return([])
      end

      example do
        expect { subject }.to output(
          %r{^item /about.md, rep default:\n  is not outdated$},
        ).to_stdout
      end

      example do
        expect { subject }.to output(
          %r{^item /dog.md, rep default:\n  is not outdated$},
        ).to_stdout
      end
    end

    context 'outdated' do
      before do
        reasons_about =
          [
            Nanoc::Core::OutdatednessReasons::ContentModified,
            Nanoc::Core::OutdatednessReasons::AttributesModified.new([:title]),
          ]

        reasons_dog =
          [Nanoc::Core::OutdatednessReasons::DependenciesOutdated]

        allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
          .with(item_rep_about).and_return(reasons_about)

        allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
          .with(item_rep_dog).and_return(reasons_dog)
      end

      example do
        expect { subject }.to output(
          %r{
            ^item\ /about.md,\ rep\ default:\n\ \ is\ outdated:\n\ \ \ \ -
            \ The\ content\ of\ this\ item\ has\ been\ modified\ since\ the
            \ last\ time\ the\ site\ was\ compiled.\n\ \ \ \ -\ The\ attributes
            \ of\ this\ item\ have\ been\ modified\ since\ the\ last\ time\ the
            \ site\ was\ compiled.$
          }x,
        ).to_stdout
      end

      example do
        expect { subject }.to output(
          %r{
            ^item\ /dog.md,\ rep\ default:\n\ \ is\ outdated:\n\ \ \ \ -\ This
            \ item\ uses\ content\ or\ attributes\ that\ have\ changed\ since
            \ the\ last\ time\ the\ site\ was\ compiled.$
          }x,
        ).to_stdout
      end
    end
  end

  describe '#print_layouts' do
    subject { runner.send(:print_layouts, layouts, outdatedness_checker) }

    let(:runner) do
      described_class.new(options, arguments, command)
    end

    let(:options) { {} }
    let(:arguments) { [] }
    let(:command) { double(:command) }

    let(:config) { Nanoc::Core::Configuration.new(dir: Dir.getwd) }

    let(:layouts) do
      Nanoc::Core::LayoutCollection.new(config, [layout])
    end

    let(:layout) { Nanoc::Core::Layout.new('stuff', {}, '/default.erb') }

    let(:site) { double(:site) }
    let(:outdatedness_checker) { double(:outdatedness_checker) }

    context 'not outdated' do
      before do
        allow(outdatedness_checker).to receive(:outdatedness_reasons_for).with(layout).and_return([])
      end

      example do
        expect { subject }.to output(
          %r{^layout /default.erb:\n  is not outdated$},
        ).to_stdout
      end
    end

    context 'outdated' do
      before do
        reasons =
          [
            Nanoc::Core::OutdatednessReasons::ContentModified,
            Nanoc::Core::OutdatednessReasons::AttributesModified.new([:title]),
          ]

        allow(outdatedness_checker).to receive(:outdatedness_reasons_for)
          .with(layout).and_return(reasons)
      end

      example do
        expect { subject }.to output(
          %r{
            ^layout\ /default.erb:\n\ \ is\ outdated:\n\ \ \ \ -\ The\ content
            \ of\ this\ item\ has\ been\ modified\ since\ the\ last\ time\ the
            \ site\ was\ compiled.\n\ \ \ \ -\ The\ attributes\ of\ this\ item
            \ have\ been\ modified\ since\ the\ last\ time\ the\ site\ was
            \ compiled.$
          }x,
        ).to_stdout
      end
    end
  end
end
