require 'spec_helper'
require 'fakefs/spec_helpers'

module LicenseFinder
  describe NPM do
    let(:root) { "/fake-node-project" }
    let(:npm) { NPM.new project_path: Pathname.new(root) }

    it_behaves_like "a PackageManager"

    let(:package_json) do
      {
        dependencies: {
          "dependency.js" => "1.3.3.7",
          "dependency2.js" => "4.2"
        },
        devDependencies: {
          "dependency3.js" => "4.2"
        }
      }.to_json
    end

    let(:dependency_json) do
      <<-JSON
          {
            "dependencies": {
              "dependency.js": {
                "name": "dependency.js",
                "version": "1.3.3.7",
                "description": "description",
                "readme": "readme",
                "path": "/path/to/thing",
                "dependencies": {
                  "dependency1-1.js": {
                    "name": "dependency1-1.js"
                  }
                }
              },
              "dependency2.js": {
                "name": "dependency2.js",
                "version": "4.2",
                "description": "description2",
                "readme": "readme2",
                "path": "/path/to/thing2",
                "dependencies": {
                  "dependency2-1.js": {
                    "name": "dependency2-1.js",
                    "dependencies": {
                      "dependency1-1.js": {
                        "name": "dependency1-1.js"
                      }
                    }
                  }
                }
              },
              "dependency3.js": {
                "name": "dependency3.js",
                "version": "4.2",
                "description": "description3",
                "readme": "readme3",
                "path": "/path/to/thing3",
                "dependencies": {
                  "dependency1-1.js": {
                    "name": "dependency1-1.js"
                  },
                 "dependency3-1.js": {
                    "name": "dependency3-1.js"
                  }
                }
              }
            },
            "notADependency": {
              "dependency6.js": {
                "name": "dep6js",
                "version": "4.2",
                "description": "description6",
                "readme": "readme6",
                "path": "/path/to/thing6"
              }
            }
          }
      JSON
    end

    describe '.current_packages' do
      include FakeFS::SpecHelpers
      before do
        NPM.instance_variable_set(:@modules, nil)
        FileUtils.mkdir_p(root)
        File.write(File.join(root, "package.json"), package_json)
        allow(npm).to receive(:capture).with(/npm/).and_return([dependency_json, true])
      end

      it 'fetches data from npm' do
        current_packages = npm.current_packages

        expect(current_packages.map(&:name)).to eq(["dependency.js", "dependency1-1.js", "dependency2.js", "dependency2-1.js", "dependency3.js",  "dependency3-1.js"])
      end

      it "finds the groups for dependencies" do
        current_packages = npm.current_packages
        expect(current_packages.find { |p| p.name == "dependency.js" }.groups).to eq(["dependencies"])
        expect(current_packages.find { |p| p.name == "dependency1-1.js" }.groups).to eq(["dependencies", "devDependencies"])
        expect(current_packages.find { |p| p.name == "dependency2.js" }.groups).to eq(["dependencies"])
        expect(current_packages.find { |p| p.name == "dependency2-1.js" }.groups).to eq(["dependencies"])
        expect(current_packages.find { |p| p.name == "dependency3.js" }.groups).to eq(["devDependencies"])
        expect(current_packages.find { |p| p.name == "dependency3-1.js" }.groups).to eq(["devDependencies"])
      end

      it "does not support name version string" do
        json = <<-JSON
          {
            "devDependencies": {
              "foo": "4.2"
            }
          }
        JSON

        allow(Dir).to receive(:chdir).with(Pathname('/fake-node-project')) { |&block| block.call }
        allow(npm).to receive(:capture).with('npm list --json --long').and_return([json, true])

        current_packages = npm.current_packages
        expect(current_packages.map(&:name)).to eq([])
      end

      it "fails when command fails" do
        allow(npm).to receive(:capture).with(/npm/).and_return('Some error', false).once
        expect { npm.current_packages }.to raise_error(RuntimeError)
      end

      it "does not fail when command fails but produces output" do
        allow(npm).to receive(:capture).with(/npm/).and_return('{"foo":"bar"}', false).once
        silence_stderr { npm.current_packages }
      end

      context "npm recursive dependency edge case - GH#211" do
        let(:package_json) do
          FakeFS.without do
            File.read fixture_path "npm-recursive-dependencies/package.json"
          end
        end
        let(:dependency_json) do
          FakeFS.without do
            File.read fixture_path "npm-recursive-dependencies/npm-list.json"
          end
        end

        describe ".current_packages" do
          it "correctly navigates the dependencies tree and pulls out valid information" do
            expect(npm.current_packages.find { |p| p.name == "pui-react-alerts" }.version).to eq("3.0.0-alpha.2")
            expect(npm.current_packages.find { |p| p.name == "pui-react-media" }.version).to eq("3.0.0-alpha.2")
          end
        end
      end
    end
  end
end
