package packagemanager import ( "strings" "testing" "github.com/stretchr/testify/assert" ) func TestNpmParseCommand(t *testing.T) { cases := []struct { name string command string assert func(t *testing.T, parsedCommand *ParsedCommand, err error) }{ { name: "install a single package", command: "npm install @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) }, }, { name: "install a single package with specific version", command: "npm install @types/node@1.2.3", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Equal(t, "1.2.3", parsedCommand.InstallTargets[0].PackageVersion.Version) }, }, { name: "install a development package", command: "npm install --save-dev @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, { name: "install a development package with short flag", command: "npm i -D @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, { name: "no install target", command: "npm install", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) }, }, { name: "multiple package installations", command: "npm install @types/node @types/react", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Equal(t, "@types/react", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) }, }, { name: "not an installation command", command: "npm update @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.NotNil(t, parsedCommand) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) }, }, { name: "skip intermediate flags", command: "npm --x -y install @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, { name: "multiple development packages", command: "npm i -D @types/node -D @types/react", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Equal(t, "@types/react", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) }, }, { name: "second package has a version", command: "npm i express @types/node@1.2.3", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "express", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) assert.Equal(t, "1.2.3", parsedCommand.InstallTargets[1].PackageVersion.Version) }, }, { name: "manifest installation (bare install)", command: "npm install", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, true, parsedCommand.IsManifestInstall) }, }, { name: "manifest installation (short form)", command: "npm i", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, true, parsedCommand.IsManifestInstall) }, }, { name: "npm install with dev flag but no packages", command: "npm install --save-dev", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, false, parsedCommand.IsManifestInstall) // with no package name, npm won’t add or install anything new }, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { npm, err := NewNpmPackageManager(DefaultNpmPackageManagerConfig()) assert.NoError(t, err) parsedCommand, err := npm.ParseCommand(strings.Split(tc.command, " ")) tc.assert(t, parsedCommand, err) }) } } func TestYarnParseCommand(t *testing.T) { cases := []struct { name string command string assert func(t *testing.T, parsedCommand *ParsedCommand, err error) }{ { name: "install a single package", command: "yarn add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) }, }, { name: "manifest installation with install command", command: "yarn install", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, true, parsedCommand.IsManifestInstall) }, }, { name: "bare yarn command (manifest install)", command: "yarn", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, true, parsedCommand.IsManifestInstall) }, }, { name: "yarn install with package name (invalid syntax)", command: "yarn install express", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.NotNil(t, parsedCommand) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) assert.Equal(t, false, parsedCommand.IsManifestInstall) }, }, { name: "second package has a version", command: "yarn add express @types/node@1.2.3", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "express", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) assert.Equal(t, "1.2.3", parsedCommand.InstallTargets[1].PackageVersion.Version) }, }, { name: "skip intermediate flags", command: "yarn --x -y add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { yarn, err := NewNpmPackageManager(DefaultYarnPackageManagerConfig()) assert.NoError(t, err) parsedCommand, err := yarn.ParseCommand(strings.Split(tc.command, " ")) tc.assert(t, parsedCommand, err) }) } } func TestPnpmParseCommand(t *testing.T) { cases := []struct { name string command string assert func(t *testing.T, parsedCommand *ParsedCommand, err error) }{ { name: "install a single package", command: "pnpm add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) }, }, { name: "install a development package with short flag", command: "pnpm i -D @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, { name: "manifest installation", command: "pnpm install", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, true, parsedCommand.IsManifestInstall) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) }, }, { name: "multiple package installations", command: "pnpm add @types/node @types/react", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Equal(t, "@types/react", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) }, }, { name: "skip intermediate flags", command: "pnpm --x -y add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { pnpm, err := NewNpmPackageManager(DefaultPnpmPackageManagerConfig()) assert.NoError(t, err) parsedCommand, err := pnpm.ParseCommand(strings.Split(tc.command, " ")) tc.assert(t, parsedCommand, err) }) } } func TestBunParseCommand(t *testing.T) { cases := []struct { name string command string assert func(t *testing.T, parsedCommand *ParsedCommand, err error) }{ { name: "install a single package", command: "bun add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version) }, }, { name: "install a development package with short flag", command: "bun add -d @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, { name: "manifest installation", command: "bun install", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, true, parsedCommand.IsManifestInstall) assert.Equal(t, 0, len(parsedCommand.InstallTargets)) }, }, { name: "multiple package installations", command: "bun add @types/node @types/react", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 2, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) assert.Equal(t, "@types/react", parsedCommand.InstallTargets[1].PackageVersion.Package.Name) }, }, { name: "skip intermediate flags", command: "bun --x -y add @types/node", assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) { assert.NoError(t, err) assert.Equal(t, 1, len(parsedCommand.InstallTargets)) assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name) }, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { bun, err := NewNpmPackageManager(DefaultBunPackageManagerConfig()) assert.NoError(t, err) parsedCommand, err := bun.ParseCommand(strings.Split(tc.command, " ")) tc.assert(t, parsedCommand, err) }) } }