package common

import (
	"os"
	"os/exec"
	"path"
	"strings"
	"testing"
)

func TestGitMsgParsing(t *testing.T) {
	t.Run("tree message with size 56", func(t *testing.T) {
		const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"

		data := make(chan byte, 500)
		for _, b := range []byte(hdr) {
			data <- b
		}
		gitHdr, err := parseGitMsg(data)

		if err != nil {
			t.Error(err)
		}

		if gitHdr.hash != "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98" {
			t.Errorf("Invalid hash %s", gitHdr.hash)
		}

		if gitHdr.size != 56 {
			t.Errorf("Invalid msg size: %d", gitHdr.size)
		}

		if gitHdr.itemType != "tree" {
			t.Errorf("Invalid msg type: %s", gitHdr.itemType)
		}
	})
	t.Run("commit message with size 256", func(t *testing.T) {
		const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 256\x00"

		data := make(chan byte, 500)
		for _, b := range []byte(hdr) {
			data <- b
		}
		gitHdr, err := parseGitMsg(data)

		if err != nil {
			t.Error(err)
		}

		if gitHdr.hash != "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99" {
			t.Errorf("Invalid hash %s", gitHdr.hash)
		}

		if gitHdr.size != 256 {
			t.Errorf("Invalid msg size: %d", gitHdr.size)
		}

		if gitHdr.itemType != "commit" {
			t.Errorf("Invalid msg type: %s", gitHdr.itemType)
		}
	})
	t.Run("invalid tree message with size 56", func(t *testing.T) {
		const hdr = "f408r8ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"

		data := make(chan byte, 500)
		for _, b := range []byte(hdr) {
			data <- b
		}
		gitHdr, err := parseGitMsg(data)

		if err.Error() != "Invalid character during object hash parse 'r' at 4" {
			t.Error(err)
		}

		if gitHdr.hash != "" {
			t.Errorf("Invalid hash %s", gitHdr.hash)
		}

		if gitHdr.size != 0 {
			t.Errorf("Invalid msg size: %d", gitHdr.size)
		}

		if gitHdr.itemType != "" {
			t.Errorf("Invalid msg type: %s", gitHdr.itemType)
		}
	})
}

func TestGitCommitParsing(t *testing.T) {
	t.Run("parse valid commit message", func(t *testing.T) {
		const commitData = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 253\000" +
			`tree e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53
parent 429cc2fe02170ca5668f0461928c7e7430c7a17cd64ac298286d7162572a7703
author Adam Majer <amajer@suse.com> 1720709149 +0200
committer Adam Majer <amajer@suse.com> 1720709149 +0200

.` + "\000"
		ch := make(chan byte, 5000)
		for _, b := range []byte(commitData) {
			ch <- b
		}
		commit, err := parseGitCommit(ch)

		if err != nil {
			t.Error(err)
		}

		if commit.Tree != "e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53" {
			t.Errorf("Invalid commit object: %#v", commit)
		}

		if commit.Msg != "." {
			t.Errorf("Invalid commit msg: '%s'", commit.Msg)
		}
	})

	t.Run("parse multiline headers", func(t *testing.T) {
		const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1491\x00" +
			`tree 1f9c8fe8099615d6d3921528402ac53f09213b02
parent e08a654fae0ecc91678819e0b62a2e014bad3339
author Yagiz Nizipli <yagiz@nizipli.com> 1720967314 -0400
committer GitHub <noreply@github.com> 1720967314 +0200
gpgsig -----BEGIN PGP SIGNATURE-----
 
 wsFcBAABCAAQBQJmk+CSCRC1aQ7uu5UhlAAAQIYQAEQXCl3bUUuegiz5/oitIIF7
 6xhndcjQIuqY4dONIeOARrGwbKh8OtMHpfJhMRUmvWvXrsTA6P1PWl0YcyyIMzHZ
 a4sBsWyxA0uSztVywpvksvk6EdMoEXeXrHS3cBxePsH8bI+Pwnsv27PsevEwpyIT
 reB4zZsoGySFVqf2lnXxG5hSRMYw++BDXSDMZk2BP9BvueRXasJ0lT1c7HlbHepF
 TWzwyHZ91OhXjrdPY7qLQEEV/frwuM+UrxOPb2e83ZTg81vXFuugURfhHNx4Iu+F
 LCMvOeaF2vO5yJtMe8+tY1l0Wb8S1aWcGCECN2XCXmmnWxt+yYh2gjqxq3y0DMcz
 zvg6arQIepDFLkQPZMDlUCIjIJQn4FbAaQAvoyMF8Pi5YmxhRqgo3iOB5SBE8eES
 63ifZ311izuSdD+o3ObFpzLoTgq62kglwfegZN/X8CzTSIqrT1norYJEbSwkWID1
 WeRHUHfC7f6N3XK8zeb83zmhBU58ghW9sp5/LcefGMRJmVhBWhjBCpeMUaFHdKhl
 /dfgPl5gJrrJ+wM3O6iaay0R1Iv4Upe/yXrbQnIgGj/qqgMLEPBY8lzNYimVTLxd
 2ObrcXnERo3wwxeUgWaAARbEGQjC51DK/2SXxVGUh+IokicsBNRKU7lVWwwFFely
 ntjtge6Gs9pA5rSIilPH
 =V1bK
 -----END PGP SIGNATURE-----
 

meta: change email address of anonrig

PR-URL: https://github.com/nodejs/node/pull/53829
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"

		ch := make(chan byte, 5000)
		for _, b := range []byte(commitData) {
			ch <- b
		}
		commit, err := parseGitCommit(ch)

		if err != nil {
			t.Error(err)
		}

		if commit.Tree != "1f9c8fe8099615d6d3921528402ac53f09213b02" {
			t.Errorf("Invalid commit object: %#v", commit)
		}

		if commit.Msg[len(commit.Msg)-55:] != "Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>" {
			t.Errorf("Invalid commit msg: '%s'", commit.Msg[len(commit.Msg)-55:])
		}
	})

	t.Run("parse tree object", func(t *testing.T) {
		const treeData = "\x31\x61\x30\x35\x64\x62\x37\x33\x36\x39\x33\x37\x34\x33\x30\x65\x31\x38\x64\x66\x34\x33\x61\x32\x37\x61\x39\x38\x30\x30\x31\x30\x31\x32\x65\x31\x65\x64\x32\x30\x34\x38\x32\x39\x38\x36\x37\x31\x32\x38\x66\x32\x63\x65\x38\x34\x30\x36\x62\x35\x63\x66\x63\x39\x20\x74\x72\x65\x65\x20\x32\x30\x35\x00\x34\x30\x30\x30\x30\x20\x62\x6f\x74\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\x93\x17\xaa\x47\xf6\xea\x37\xe8\xbc\xe2\x80\x77\x57\x90\xf4\xa8\x01\xd7\xe3\x70\x2f\x84\xfb\xe1\xb0\x0e\x4a\x2c\x1c\x75\x2c\x2b\x34\x30\x30\x30\x30\x20\x6f\x62\x73\x2d\x73\x74\x61\x67\x69\x6e\x67\x2d\x62\x6f\x74\x00\x79\x77\x8b\x28\x7d\x37\x10\x59\xb9\x71\x28\x36\xed\x20\x31\x5f\xfb\xe1\xed\xb5\xba\x4f\x5e\xbb\x65\x65\x68\x23\x77\x32\x58\xfe\x34\x30\x30\x30\x30\x20\x70\x72\x2d\x72\x65\x76\x69\x65\x77\x00\x36\x0d\x45\xcb\x76\xb8\x93\xb3\x21\xba\xfa\xd5\x00\x9d\xfc\x59\xab\x88\xc1\x3c\x81\xcb\x48\x5a\xe0\x29\x29\x0f\xe3\x6b\x3c\x5e\x34\x30\x30\x30\x30\x20\x70\x72\x6a\x67\x69\x74\x2d\x75\x70\x64\x61\x74\x65\x72\x00\xb4\x0b\x1c\xf5\xfb\xec\x9a\xb2\x9f\x48\x3e\x21\x18\x0d\x51\xb7\x98\x6e\x21\x99\x74\x84\x67\x71\x41\x24\x42\xfc\xc9\x04\x12\x99\x00"

		ch := make(chan byte, 1000)
		for _, b := range []byte(treeData) {
			ch <- b
		}

		tree, err := parseGitTree(ch)

		if err != nil {
			t.Error(err)
		}

		found := false
		t.Log(tree.items)
		for _, item := range tree.items {
			if item.name == "bots-common" && item.hash == "9317aa47f6ea37e8bce280775790f4a801d7e3702f84fbe1b00e4a2c1c752c2b" && item.isTree() {
				found = true
				t.Log("found")
				break
			}
		}
		if !found {
			t.Error("expected sub-tree not found")
		}
	})

	t.Run("parse tree object with submodules", func(t *testing.T) {
		const treeData = "\x34\x38\x34\x66\x31\x62\x65\x65\x63\x39\x35\x63\x61\x36\x62\x38\x36\x30\x64\x30\x64\x37\x63\x35\x65\x34\x38\x37\x31\x36\x36\x62\x30\x38\x65\x31\x61\x34\x35\x36\x37\x36\x62\x31\x37\x64\x39\x65\x65\x66\x32\x39\x39\x39\x65\x39\x64\x37\x34\x63\x62\x63\x64\x36\x20\x74\x72\x65\x65\x20\x33\x34\x39\x00\x31\x30\x30\x36\x34\x34\x20\x2e\x67\x69\x74\x6d\x6f\x64\x75\x6c\x65\x73\x00\xc8\x1e\x14\x29\xc5\xd4\x07\xfc\x32\xf1\xd7\xe2\x64\xee\x88\xfc\xce\xfc\x44\xf7\xae\x2e\xc4\x6e\x2c\x15\x27\x26\x65\xd4\xb8\x78\x31\x30\x30\x36\x34\x34\x20\x52\x45\x41\x44\x4d\x45\x2e\x6d\x64\x00\x90\x22\x84\x13\xbf\xd3\x5c\xfb\x1e\x27\x6b\xd6\x17\x3e\x89\xed\x0f\xc6\x31\x85\x24\x58\x6d\x9d\xf0\x6a\x1e\x17\x57\x19\x8d\xc2\x31\x36\x30\x30\x30\x30\x20\x6d\x69\x6e\x67\x77\x33\x32\x2d\x67\x63\x63\x00\xdc\x55\xb8\x28\x32\x8c\x8e\x49\x4f\x67\x87\x4a\x7d\x8c\x03\xdd\x1c\x6b\x4e\x02\xd1\x6b\x86\xe0\x8e\x47\xd7\x0e\xcd\x79\x96\x80\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\xd6\xa7\x4c\x08\x40\x6c\xe4\x0c\xc8\xf7\xbf\xf2\xd5\xcf\x30\x90\x87\xa8\x72\x83\x61\xcc\x75\x35\x4b\x08\x62\xba\x50\x81\x93\xb8\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x32\x31\x00\x24\xee\x6b\xee\x74\x59\xa3\x86\xda\xda\xbf\x8a\x9f\x6a\xe4\xfa\x15\xc3\xf8\x10\xbf\xa0\x1c\xee\x52\x38\x13\x8a\xa2\x14\xd1\x80\x31\x36\x30\x30\x30\x30\x20\x6e\x6f\x64\x65\x6a\x73\x32\x32\x00\x87\x3a\x32\x3b\x26\x2e\xbb\x3b\xd7\x7b\x25\x92\xb2\xe1\x1b\xdd\x08\xdb\xc7\x21\xcb\xf4\xac\x9f\x97\x63\x7e\x58\xe1\xff\xfc\xe7\x31\x36\x30\x30\x30\x30\x20\x70\x79\x74\x68\x6f\x6e\x33\x31\x31\x00\x35\xc7\x02\xe8\x50\x1e\xed\xeb\x5c\xe4\x3d\x6f\x34\x60\xd1\x1c\x79\x1c\xfe\xfa\xa7\x72\x48\xf0\x8c\xad\x55\xd0\x0c\x37\xe7\x3a\x00"

		ch := make(chan byte, 1000)
		for _, b := range []byte(treeData) {
			ch <- b
		}

		tree, err := parseGitTree(ch)

		if err != nil {
			t.Error(err)
		}

		found := false
		for _, item := range tree.items {
			t.Log(item)
			if item.name == "nodejs22" && item.hash == "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7" && item.isSubmodule() {
				found = true
				break
			}
		}
		if !found {
			t.Error("expected submodule not found")
		}
	})
}

func TestCommitTreeParsingOfHead(t *testing.T) {
	gitDir := t.TempDir()
	testDir, _ := os.Getwd()
	var commitId string

	cmd := exec.Command("/usr/bin/bash", path.Join(testDir, "tsetup.sh"))
	cmd.Dir = gitDir
	cmd.Stdout = writeFunc(func(data []byte) (int, error) {
		commitId = commitId + strings.TrimSpace(string(data))
		return len(data), nil
	})
	if err := cmd.Run(); err != nil {
		t.Fatal(err.Error())
	}

	t.Run("reads HEAD and parses the tree", func(t *testing.T) {
		const nodejs21 = "c678c57007d496a98bec668ae38f2c26a695f94af78012f15d044ccf066ccb41"
			stdLogger, errLogger:=  CreateStdoutLogger(os.Stdout, os.Stdout)
		h := RequestHandler{
			GitPath: gitDir,
			StdLogger: stdLogger,
			ErrLogger: errLogger,
		}
		id, ok := h.GitSubmoduleCommitId("", "nodejs21", commitId)
		if !ok {
			t.Error("failed parse")
		}
		if id != nodejs21 {
			t.Errorf("hash doesn't match: %s vs. expected %s", id, nodejs21)
		}
	})

	t.Run("reads README.md", func (t *testing.T) {
			stdLogger, errLogger:=  CreateStdoutLogger(os.Stdout, os.Stdout)
		h := RequestHandler{
			GitPath: gitDir,
			StdLogger: stdLogger,
			ErrLogger: errLogger,
		}
		data := h.GitCatFile("", commitId, "README.md")
		if h.HasError() {
			t.Errorf("failed parse: %v", h.Error)
		}
		if string(data) != "foo\n" || len(data) != 4 {
			t.Errorf("Wrong data of len: %d", len(data))
		}
	})

	t.Run("try to parse unknown item", func(t *testing.T) {
	})
}

