@@ -2,6 +2,7 @@ package server
22
33import (
44 "archive/tar"
5+ "archive/zip"
56 "bytes"
67 "compress/gzip"
78 "database/sql"
@@ -590,3 +591,195 @@ func TestHandleComparePage(t *testing.T) {
590591 t .Errorf ("expected status 400 for invalid separator, got %d" , w .Code )
591592 }
592593}
594+
595+ func TestArchiveFilename (t * testing.T ) {
596+ tests := []struct {
597+ input string
598+ want string
599+ }{
600+ {"package.tar.gz" , "package.tar.gz" },
601+ {"d2e2f014ccd6ec9fae8dbe6336a4164346a2a856" , "d2e2f014ccd6ec9fae8dbe6336a4164346a2a856.zip" },
602+ {"file.zip" , "file.zip" },
603+ {"archive.tgz" , "archive.tgz" },
604+ {"noext" , "noext.zip" },
605+ }
606+
607+ for _ , tt := range tests {
608+ t .Run (tt .input , func (t * testing.T ) {
609+ got := archiveFilename (tt .input )
610+ if got != tt .want {
611+ t .Errorf ("archiveFilename(%q) = %q, want %q" , tt .input , got , tt .want )
612+ }
613+ })
614+ }
615+ }
616+
617+ func TestOpenArchiveStripsSingleRootDir (t * testing.T ) {
618+ data := createZipArchive (t , map [string ]string {
619+ "repo-abc123/README.md" : "hello" ,
620+ "repo-abc123/src/main.go" : "package main" ,
621+ "repo-abc123/go.mod" : "module test" ,
622+ })
623+ reader , err := openArchive ("test.zip" , bytes .NewReader (data ), "composer" )
624+ if err != nil {
625+ t .Fatalf ("openArchive failed: %v" , err )
626+ }
627+ defer func () { _ = reader .Close () }()
628+
629+ files , err := reader .List ()
630+ if err != nil {
631+ t .Fatalf ("List failed: %v" , err )
632+ }
633+ for _ , f := range files {
634+ if strings .HasPrefix (f .Path , "repo-abc123/" ) {
635+ t .Errorf ("file %q still has root prefix after stripping" , f .Path )
636+ }
637+ }
638+ }
639+
640+ func TestOpenArchiveMultipleRootDirs (t * testing.T ) {
641+ data := createZipArchive (t , map [string ]string {
642+ "src/main.go" : "package main" ,
643+ "docs/README.md" : "hello" ,
644+ })
645+ reader , err := openArchive ("test.zip" , bytes .NewReader (data ), "composer" )
646+ if err != nil {
647+ t .Fatalf ("openArchive failed: %v" , err )
648+ }
649+ defer func () { _ = reader .Close () }()
650+
651+ files , err := reader .List ()
652+ if err != nil {
653+ t .Fatalf ("List failed: %v" , err )
654+ }
655+ paths := make (map [string ]bool )
656+ for _ , f := range files {
657+ paths [f .Path ] = true
658+ }
659+ if ! paths ["src/main.go" ] {
660+ t .Error ("expected src/main.go to remain unchanged" )
661+ }
662+ if ! paths ["docs/README.md" ] {
663+ t .Error ("expected docs/README.md to remain unchanged" )
664+ }
665+ }
666+
667+ func TestOpenArchiveFlatNoSubdirs (t * testing.T ) {
668+ data := createZipArchive (t , map [string ]string {
669+ "README.md" : "hello" ,
670+ "main.go" : "package main" ,
671+ })
672+ reader , err := openArchive ("test.zip" , bytes .NewReader (data ), "composer" )
673+ if err != nil {
674+ t .Fatalf ("openArchive failed: %v" , err )
675+ }
676+ defer func () { _ = reader .Close () }()
677+
678+ files , err := reader .List ()
679+ if err != nil {
680+ t .Fatalf ("List failed: %v" , err )
681+ }
682+ paths := make (map [string ]bool )
683+ for _ , f := range files {
684+ paths [f .Path ] = true
685+ }
686+ if ! paths ["README.md" ] {
687+ t .Error ("expected README.md at root" )
688+ }
689+ }
690+
691+ func TestOpenArchiveNpmUsesPackagePrefix (t * testing.T ) {
692+ data := createTarGzArchive (t , map [string ]string {
693+ "package/README.md" : "hello" ,
694+ "package/index.js" : "module.exports = {}" ,
695+ })
696+ reader , err := openArchive ("pkg.tgz" , bytes .NewReader (data ), "npm" )
697+ if err != nil {
698+ t .Fatalf ("openArchive failed: %v" , err )
699+ }
700+ defer func () { _ = reader .Close () }()
701+
702+ files , err := reader .List ()
703+ if err != nil {
704+ t .Fatalf ("List failed: %v" , err )
705+ }
706+ for _ , f := range files {
707+ if strings .HasPrefix (f .Path , "package/" ) {
708+ t .Errorf ("file %q still has package/ prefix" , f .Path )
709+ }
710+ }
711+ }
712+
713+ func TestOpenArchiveExtensionlessFilename (t * testing.T ) {
714+ data := createZipArchive (t , map [string ]string {
715+ "repo-hash/README.md" : "hello" ,
716+ })
717+ reader , err := openArchive ("d2e2f014ccd6ec9fae8dbe6336a4164346a2a856" , bytes .NewReader (data ), "composer" )
718+ if err != nil {
719+ t .Fatalf ("openArchive failed: %v" , err )
720+ }
721+ defer func () { _ = reader .Close () }()
722+
723+ files , err := reader .List ()
724+ if err != nil {
725+ t .Fatalf ("List failed: %v" , err )
726+ }
727+ if len (files ) == 0 {
728+ t .Fatal ("expected files in archive" )
729+ }
730+ for _ , f := range files {
731+ if strings .HasPrefix (f .Path , "repo-hash/" ) {
732+ t .Errorf ("file %q still has root prefix" , f .Path )
733+ }
734+ }
735+ }
736+
737+ func createZipArchive (t * testing.T , files map [string ]string ) []byte {
738+ t .Helper ()
739+ buf := new (bytes.Buffer )
740+ w := zip .NewWriter (buf )
741+
742+ for name , content := range files {
743+ f , err := w .Create (name )
744+ if err != nil {
745+ t .Fatalf ("failed to create zip entry: %v" , err )
746+ }
747+ if _ , err := f .Write ([]byte (content )); err != nil {
748+ t .Fatalf ("failed to write zip content: %v" , err )
749+ }
750+ }
751+
752+ if err := w .Close (); err != nil {
753+ t .Fatalf ("failed to close zip writer: %v" , err )
754+ }
755+ return buf .Bytes ()
756+ }
757+
758+ func createTarGzArchive (t * testing.T , files map [string ]string ) []byte {
759+ t .Helper ()
760+ buf := new (bytes.Buffer )
761+ gw := gzip .NewWriter (buf )
762+ tw := tar .NewWriter (gw )
763+
764+ for name , content := range files {
765+ header := & tar.Header {
766+ Name : name ,
767+ Size : int64 (len (content )),
768+ Mode : 0644 ,
769+ }
770+ if err := tw .WriteHeader (header ); err != nil {
771+ t .Fatalf ("failed to write tar header: %v" , err )
772+ }
773+ if _ , err := tw .Write ([]byte (content )); err != nil {
774+ t .Fatalf ("failed to write tar content: %v" , err )
775+ }
776+ }
777+
778+ if err := tw .Close (); err != nil {
779+ t .Fatalf ("failed to close tar writer: %v" , err )
780+ }
781+ if err := gw .Close (); err != nil {
782+ t .Fatalf ("failed to close gzip writer: %v" , err )
783+ }
784+ return buf .Bytes ()
785+ }
0 commit comments