github.com/tc-hib/go-winres@v0.3.4-0.20240411120550-c4d55a3dfc2e/main_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/md5"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"testing"
    12  )
    13  
    14  const tmpDir = "_testdata/tmp"
    15  
    16  func Test_Extract(t *testing.T) {
    17  	a := os.Args
    18  	defer func() { os.Args = a }()
    19  
    20  	f := makeTmpDir(t)
    21  	defer f()
    22  
    23  	os.Args = []string{"./go-winres.exe", "extract", "--dir", "_testdata/tmp", "_testdata/rh.exe"}
    24  	main()
    25  	if loadJSON(t, "winres.json") != jsonRHM {
    26  		t.Error("json is different (json manifest)")
    27  	}
    28  	checkFile(t, "#1_0000.ico", []byte{0x00, 0x24, 0x99, 0x66, 0x72, 0xaf, 0x62, 0x12, 0x35, 0x22, 0x9b, 0x7b, 0x2, 0x2f, 0xe5, 0x94})
    29  	checkFile(t, "APP_040C.ico", []byte{0xdd, 0xaf, 0x55, 0xb5, 0xd7, 0x3c, 0x65, 0xc3, 0x59, 0xb7, 0x3a, 0x39, 0x48, 0x62, 0xb3, 0x10})
    30  	checkFile(t, "APP_0409.ico", []byte{0xee, 0x29, 0x1d, 0xaa, 0xc1, 0x3d, 0x24, 0xfc, 0xc5, 0xe, 0x64, 0x71, 0x44, 0xf0, 0x1e, 0x46})
    31  	checkFile(t, "CURSOR_0000.cur", []byte{0x9f, 0x41, 0xe3, 0x26, 0xcc, 0x10, 0xb1, 0xed, 0xd9, 0x96, 0x38, 0x59, 0xc6, 0x93, 0x37, 0x9e})
    32  	checkFile(t, "PNG_CUR-64X128_0000.png", []byte{0x40, 0x83, 0x52, 0xdb, 0x5, 0xe7, 0xc2, 0x32, 0x5b, 0xc1, 0x40, 0x15, 0x5b, 0x16, 0x9f, 0x4d})
    33  	checkFile(t, "ICON16_0000.bmp", []byte{0xd7, 0x0c, 0xa6, 0x11, 0x23, 0xf6, 0x81, 0xef, 0xaa, 0xd3, 0x01, 0x61, 0x5f, 0x3e, 0x68, 0x1a})
    34  }
    35  
    36  func Test_Init(t *testing.T) {
    37  	a := os.Args
    38  	defer func() { os.Args = a }()
    39  
    40  	f := makeTmpDir(t)
    41  	defer f()
    42  
    43  	func() {
    44  		f := moveToTmpDir(t)
    45  		defer f()
    46  
    47  		os.Args = []string{"./go-winres.exe", "init"}
    48  		main()
    49  
    50  		s, err := os.Stat("winres/winres.json")
    51  		if err != nil || s.Size() == 0 {
    52  			t.Fatal(err)
    53  		}
    54  		s, err = os.Stat("winres/icon.png")
    55  		if err != nil || s.Size() == 0 {
    56  			t.Fatal(err)
    57  		}
    58  		s, err = os.Stat("winres/icon16.png")
    59  		if err != nil || s.Size() == 0 {
    60  			t.Fatal(err)
    61  		}
    62  	}()
    63  }
    64  
    65  func Test_Extract_XMLManifest(t *testing.T) {
    66  	a := os.Args
    67  	defer func() { os.Args = a }()
    68  
    69  	f := makeTmpDir(t)
    70  	defer f()
    71  
    72  	os.Args = []string{"./go-winres.exe", "extract", "--dir", "_testdata/tmp", "--xml-manifest", "_testdata/rh.exe"}
    73  	main()
    74  	if loadJSON(t, "winres.json") != jsonRH {
    75  		t.Error("json is different (xml manifest)")
    76  	}
    77  	checkFile(t, "#1_0000.manifest", []byte{0x21, 0x19, 0x26, 0x2f, 0x8a, 0x5b, 0x5f, 0x64, 0x0e, 0x6e, 0xe7, 0x01, 0x20, 0xdb, 0xd2, 0x05})
    78  	checkFile(t, "#1_0000.ico", []byte{0x00, 0x24, 0x99, 0x66, 0x72, 0xaf, 0x62, 0x12, 0x35, 0x22, 0x9b, 0x7b, 0x2, 0x2f, 0xe5, 0x94})
    79  	checkFile(t, "APP_040C.ico", []byte{0xdd, 0xaf, 0x55, 0xb5, 0xd7, 0x3c, 0x65, 0xc3, 0x59, 0xb7, 0x3a, 0x39, 0x48, 0x62, 0xb3, 0x10})
    80  	checkFile(t, "APP_0409.ico", []byte{0xee, 0x29, 0x1d, 0xaa, 0xc1, 0x3d, 0x24, 0xfc, 0xc5, 0xe, 0x64, 0x71, 0x44, 0xf0, 0x1e, 0x46})
    81  	checkFile(t, "CURSOR_0000.cur", []byte{0x9f, 0x41, 0xe3, 0x26, 0xcc, 0x10, 0xb1, 0xed, 0xd9, 0x96, 0x38, 0x59, 0xc6, 0x93, 0x37, 0x9e})
    82  	checkFile(t, "PNG_CUR-64X128_0000.png", []byte{0x40, 0x83, 0x52, 0xdb, 0x5, 0xe7, 0xc2, 0x32, 0x5b, 0xc1, 0x40, 0x15, 0x5b, 0x16, 0x9f, 0x4d})
    83  	checkFile(t, "ICON16_0000.bmp", []byte{0xd7, 0x0c, 0xa6, 0x11, 0x23, 0xf6, 0x81, 0xef, 0xaa, 0xd3, 0x01, 0x61, 0x5f, 0x3e, 0x68, 0x1a})
    84  }
    85  
    86  func Test_Patch(t *testing.T) {
    87  	a := os.Args
    88  	defer func() { os.Args = a }()
    89  
    90  	f := makeTmpDir(t)
    91  	defer f()
    92  
    93  	copyFile(t, "_testdata/vs0.exe", "_testdata/tmp/temp.exe")
    94  	os.Args = []string{"./go-winres.exe", "patch", "--in", "_testdata/icons.json", "--product-version", "1.2.3.4", "_testdata/tmp/temp.exe"}
    95  	main()
    96  	checkFile(t, "temp.exe", []byte{0xae, 0x96, 0xc0, 0xfd, 0x7a, 0x9c, 0x95, 0xab, 0xd8, 0xe1, 0x8e, 0x55, 0x91, 0xd2, 0xbc, 0xa0})
    97  	checkFile(t, "temp.exe.bak", []byte{0x29, 0x13, 0xa7, 0xc5, 0x4a, 0xf9, 0x47, 0xef, 0xd6, 0x4f, 0x37, 0xc5, 0x62, 0xba, 0xd4, 0x39})
    98  }
    99  
   100  func Test_Patch_Add(t *testing.T) {
   101  	a := os.Args
   102  	defer func() { os.Args = a }()
   103  
   104  	f := makeTmpDir(t)
   105  	defer f()
   106  
   107  	copyFile(t, "_testdata/rh.exe", "_testdata/tmp/temp.exe")
   108  	os.Args = []string{"./go-winres.exe", "patch", "--in", "_testdata/icons.json", "--no-backup", "_testdata/tmp/temp.exe"}
   109  	main()
   110  	checkFile(t, "temp.exe", []byte{0xc4, 0x4a, 0x7f, 0x74, 0xe9, 0x0c, 0xfb, 0x37, 0x9a, 0x62, 0x82, 0x28, 0xbc, 0x68, 0x77, 0xc2})
   111  	if _, err := os.Stat("_testdata/tmp/temp.exe.bak"); err == nil {
   112  		t.Error("temp.exe.bak should not exist")
   113  	}
   114  }
   115  
   116  func Test_Patch_Replace(t *testing.T) {
   117  	a := os.Args
   118  	defer func() { os.Args = a }()
   119  
   120  	f := makeTmpDir(t)
   121  	defer f()
   122  
   123  	copyFile(t, "_testdata/rh.exe", "_testdata/tmp/temp.exe")
   124  
   125  	os.Args = []string{"./go-winres.exe", "patch", "--in", "_testdata/test.json", "--delete", "--file-version", "1.2", "_testdata/tmp/temp.exe"}
   126  	main()
   127  	checkFile(t, "temp.exe", []byte{0x67, 0x5b, 0xc5, 0x8a, 0xb3, 0x48, 0xfc, 0xf0, 0xaf, 0xea, 0xa5, 0xc0, 0x5f, 0xba, 0x8d, 0xc3})
   128  	checkFile(t, "temp.exe.bak", []byte{0x79, 0xbc, 0x0f, 0x27, 0x2b, 0x3f, 0x82, 0x69, 0xfa, 0xc1, 0x42, 0x1d, 0xc7, 0xdb, 0x68, 0x6c})
   129  }
   130  
   131  func Test_GitTag(t *testing.T) {
   132  	a := os.Args
   133  	defer func() { os.Args = a }()
   134  
   135  	f := makeTmpDir(t)
   136  	defer f()
   137  
   138  	copyFile(t, "_testdata/vs0.exe", "_testdata/tmp/temp1.exe")
   139  	copyFile(t, "_testdata/rh.exe", "_testdata/tmp/temp2.exe")
   140  
   141  	func() {
   142  		f := moveToTmpDir(t)
   143  		defer f()
   144  
   145  		createTmpGitTag(t, "v1.42.3.24")
   146  
   147  		os.Args = []string{"./go-winres.exe", "patch", "--in", "../icons.json", "--file-version", "git-tag", "temp1.exe"}
   148  		main()
   149  		os.Args = []string{"./go-winres.exe", "patch", "--in", "../test.json", "--product-version", "git-tag", "temp2.exe"}
   150  		main()
   151  	}()
   152  
   153  	checkFile(t, "temp1.exe", []byte{0x70, 0xb9, 0x34, 0x4d, 0x62, 0xe3, 0xdb, 0x62, 0xe9, 0xb5, 0xc8, 0x85, 0x48, 0xaa, 0xe7, 0x65})
   154  	checkFile(t, "temp2.exe", []byte{0xd9, 0x19, 0x0c, 0xc2, 0x72, 0x3c, 0xc4, 0x6b, 0x9e, 0x6e, 0xbe, 0x58, 0xb1, 0x26, 0xa7, 0x4b})
   155  }
   156  
   157  func Test_Simply(t *testing.T) {
   158  	a := os.Args
   159  	defer func() { os.Args = a }()
   160  
   161  	f := makeTmpDir(t)
   162  	defer f()
   163  
   164  	os.Args = []string{
   165  		"./go-winres.exe",
   166  		"simply",
   167  		"--arch",
   168  		" amd64, 386 , arm, arm64 ",
   169  		"--out",
   170  		"_testdata/tmp/simply",
   171  		"--product-version",
   172  		"v42.5.3.8 alpha",
   173  		"--file-version",
   174  		"1.2.3.4.5.6.7",
   175  		"--manifest",
   176  		"gui",
   177  		"--admin",
   178  		"--file-description",
   179  		"description",
   180  		"--product-name",
   181  		"Product name",
   182  		"--copyright",
   183  		"©",
   184  		"--original-filename",
   185  		"xxx.exe",
   186  		"--icon",
   187  		"_testdata/fr.ico",
   188  	}
   189  	main()
   190  	checkFile(t, "simply_windows_arm64.syso", []byte{0xb1, 0x1b, 0x8f, 0x79, 0xea, 0xac, 0x72, 0xae, 0x0e, 0x8a, 0xa6, 0xf2, 0x2c, 0x61, 0x10, 0x8d})
   191  	checkFile(t, "simply_windows_arm.syso", []byte{0x66, 0xe5, 0x83, 0xd1, 0x62, 0xe8, 0x51, 0x10, 0xb1, 0x2e, 0x5b, 0xdc, 0x57, 0x23, 0xd9, 0x8c})
   192  	checkFile(t, "simply_windows_amd64.syso", []byte{0xc4, 0xfe, 0x6e, 0x34, 0xb2, 0xe5, 0x9e, 0x93, 0x00, 0xf7, 0x1f, 0x5a, 0x62, 0x9b, 0xea, 0x37})
   193  	checkFile(t, "simply_windows_386.syso", []byte{0xa0, 0x02, 0x97, 0x0f, 0xc9, 0x0d, 0x2c, 0x28, 0xf1, 0x23, 0xd0, 0x31, 0x6b, 0x3f, 0x0d, 0x73})
   194  }
   195  
   196  func Test_SimplyGitTag(t *testing.T) {
   197  	a := os.Args
   198  	defer func() { os.Args = a }()
   199  
   200  	f := makeTmpDir(t)
   201  	defer f()
   202  
   203  	copyFile(t, "_testdata/cur-32x64.png", "_testdata/tmp/icon.png")
   204  
   205  	func() {
   206  		f := moveToTmpDir(t)
   207  		defer f()
   208  
   209  		createTmpGitTag(t, "v1.42.3.24")
   210  
   211  		os.Args = []string{"./go-winres.exe", "simply", "--arch", "amd64", "--file-version", "git-tag", "--icon", "icon.png"}
   212  		main()
   213  		os.Args = []string{"./go-winres.exe", "simply", "--arch", "arm64", "--product-version", "git-tag", "--icon", "icon.png"}
   214  		main()
   215  	}()
   216  
   217  	checkFile(t, "rsrc_windows_amd64.syso", []byte{0x66, 0x4b, 0xca, 0x71, 0xad, 0x35, 0x0f, 0x91, 0xca, 0xdf, 0xd1, 0x11, 0x9b, 0x5d, 0x42, 0xc7})
   218  	checkFile(t, "rsrc_windows_arm64.syso", []byte{0x29, 0xa1, 0xde, 0x27, 0xf2, 0x5a, 0x96, 0x4e, 0xc2, 0x59, 0xbf, 0xa3, 0x60, 0x11, 0xe0, 0xed})
   219  }
   220  
   221  func Test_Simply_PNGIcon(t *testing.T) {
   222  	a := os.Args
   223  	defer func() { os.Args = a }()
   224  
   225  	f := makeTmpDir(t)
   226  	defer f()
   227  
   228  	os.Args = []string{
   229  		"./go-winres.exe",
   230  		"simply",
   231  		"--out",
   232  		"_testdata/tmp/rsrc.syso",
   233  		"--arch",
   234  		"386",
   235  		"--no-suffix",
   236  		"--icon",
   237  		"icon.png",
   238  	}
   239  	main()
   240  	checkFile(t, "rsrc.syso", []byte{0x8e, 0xc8, 0xe5, 0x44, 0x8e, 0x93, 0xd2, 0xab, 0x84, 0x10, 0x67, 0x16, 0xac, 0x70, 0x1a, 0xad})
   241  }
   242  
   243  func Test_Make(t *testing.T) {
   244  	a := os.Args
   245  	defer func() { os.Args = a }()
   246  
   247  	f := makeTmpDir(t)
   248  	defer f()
   249  
   250  	os.Args = []string{
   251  		"./go-winres.exe",
   252  		"make",
   253  		"--arch",
   254  		" amd64, 386 , arm, arm64 ",
   255  		"--out",
   256  		"_testdata/tmp/make",
   257  		"--product-version",
   258  		"v42.5.3.8 alpha",
   259  		"--file-version",
   260  		"1.2.3.4.5.6.7",
   261  		"--in",
   262  		"_testdata/test.json",
   263  	}
   264  	main()
   265  	checkFile(t, "make_windows_arm64.syso", []byte{0x5e, 0xc2, 0xf1, 0xb3, 0x6c, 0x49, 0x56, 0x25, 0xa8, 0x1e, 0x68, 0x49, 0x5b, 0x92, 0x3d, 0x9c})
   266  	checkFile(t, "make_windows_arm.syso", []byte{0x9e, 0xdf, 0x5a, 0x08, 0x38, 0x95, 0x38, 0x07, 0x13, 0xa1, 0x14, 0xba, 0xd7, 0x35, 0xbf, 0x11})
   267  	checkFile(t, "make_windows_amd64.syso", []byte{0x05, 0x6f, 0xa2, 0x0a, 0x06, 0xef, 0x64, 0x7f, 0xcd, 0x69, 0x07, 0x63, 0xc2, 0xa8, 0xc1, 0xa1})
   268  	checkFile(t, "make_windows_386.syso", []byte{0x35, 0xcc, 0x28, 0x6e, 0x57, 0x1c, 0x58, 0xf4, 0xaf, 0x82, 0x8a, 0xf1, 0x85, 0x5a, 0x9e, 0x61})
   269  }
   270  
   271  func copyFile(t *testing.T, src, dst string) {
   272  	s, err := os.Open(src)
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	defer s.Close()
   277  
   278  	d, err := os.Create(dst)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	defer d.Close()
   283  
   284  	io.Copy(d, s)
   285  }
   286  
   287  func makeTmpDir(t *testing.T) func() {
   288  	os.RemoveAll(tmpDir)
   289  
   290  	err := os.MkdirAll(tmpDir, 0666)
   291  	if err != nil {
   292  		t.Fatal(err)
   293  	}
   294  
   295  	return func() {
   296  		err = os.RemoveAll(tmpDir)
   297  		if err != nil {
   298  			t.Log(err)
   299  		}
   300  	}
   301  }
   302  
   303  func moveToTmpDir(t *testing.T) func() {
   304  	dir, err := os.Getwd()
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  
   309  	err = os.Chdir(tmpDir)
   310  	if err != nil {
   311  		t.Fatal(err)
   312  	}
   313  
   314  	return func() {
   315  		err = os.Chdir(dir)
   316  		if err != nil {
   317  			t.Fatal(err)
   318  		}
   319  	}
   320  }
   321  
   322  func createTmpGitTag(t *testing.T, tag string) {
   323  	err := ioutil.WriteFile("tmp.txt", []byte{}, 0666)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	cmd := exec.Command("git", "init")
   328  	err = cmd.Run()
   329  	if err != nil {
   330  		t.Fatal(err)
   331  	}
   332  	cmd = exec.Command("git", "add", "tmp.txt")
   333  	err = cmd.Run()
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	cmd = exec.Command("git", "commit", "-m", ".")
   338  	err = cmd.Run()
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  	cmd = exec.Command("git", "tag", "-a", tag, "-m", ".")
   343  	err = cmd.Run()
   344  	if err != nil {
   345  		t.Fatal(err)
   346  	}
   347  }
   348  
   349  func loadJSON(t *testing.T, file string) string {
   350  	d, err := ioutil.ReadFile(filepath.Join(tmpDir, file))
   351  	if err != nil {
   352  		t.Fatal(err)
   353  	}
   354  	return string(d)
   355  }
   356  
   357  func checkFile(t *testing.T, file string, hash []byte) {
   358  	f, err := os.Open(filepath.Join(tmpDir, file))
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	defer f.Close()
   363  
   364  	h := md5.New()
   365  	io.Copy(h, f)
   366  	if !bytes.Equal(h.Sum(nil), hash) {
   367  		t.Errorf("wrong hash for %s %x", file, h.Sum(nil))
   368  	}
   369  }
   370  
   371  // language=json
   372  const jsonRHM = `{
   373    "PNG": {
   374      "CUR-64X128": {
   375        "0000": "PNG_CUR-64X128_0000.png"
   376      }
   377    },
   378    "RT_BITMAP": {
   379      "ICON16": {
   380        "0000": "ICON16_0000.bmp"
   381      }
   382    },
   383    "RT_GROUP_CURSOR": {
   384      "CURSOR": {
   385        "0000": "CURSOR_0000.cur"
   386      }
   387    },
   388    "RT_GROUP_ICON": {
   389      "#1": {
   390        "0000": "#1_0000.ico"
   391      },
   392      "APP": {
   393        "0409": "APP_0409.ico",
   394        "040C": "APP_040C.ico"
   395      }
   396    },
   397    "RT_MANIFEST": {
   398      "#1": {
   399        "0000": {
   400          "identity": {},
   401          "description": "",
   402          "minimum-os": "win7",
   403          "execution-level": "",
   404          "ui-access": false,
   405          "auto-elevate": false,
   406          "dpi-awareness": "system",
   407          "disable-theming": false,
   408          "disable-window-filtering": false,
   409          "high-resolution-scrolling-aware": false,
   410          "ultra-high-resolution-scrolling-aware": false,
   411          "long-path-aware": false,
   412          "printer-driver-isolation": false,
   413          "gdi-scaling": false,
   414          "segment-heap": false,
   415          "use-common-controls-v6": false
   416        }
   417      }
   418    },
   419    "RT_VERSION": {
   420      "#1": {
   421        "0409": {
   422          "fixed": {
   423            "file_version": "1.2.3.4",
   424            "product_version": "5.6.7.8"
   425          },
   426          "info": {
   427            "0409": {
   428              "CompanyName": "WinRes Corp.",
   429              "FileDescription": "WinRes",
   430              "FileVersion": "1.2.3.4 (Build.42.42)",
   431              "InternalName": "winres",
   432              "LegalCopyright": "© WinRes.",
   433              "OriginalFilename": "WINRES.EXE",
   434              "ProductName": "WinRes CLI",
   435              "ProductVersion": "5.6.7.8"
   436            }
   437          }
   438        }
   439      }
   440    }
   441  }`
   442  
   443  // language=json
   444  const jsonRH = `{
   445    "PNG": {
   446      "CUR-64X128": {
   447        "0000": "PNG_CUR-64X128_0000.png"
   448      }
   449    },
   450    "RT_BITMAP": {
   451      "ICON16": {
   452        "0000": "ICON16_0000.bmp"
   453      }
   454    },
   455    "RT_GROUP_CURSOR": {
   456      "CURSOR": {
   457        "0000": "CURSOR_0000.cur"
   458      }
   459    },
   460    "RT_GROUP_ICON": {
   461      "#1": {
   462        "0000": "#1_0000.ico"
   463      },
   464      "APP": {
   465        "0409": "APP_0409.ico",
   466        "040C": "APP_040C.ico"
   467      }
   468    },
   469    "RT_MANIFEST": {
   470      "#1": {
   471        "0000": "#1_0000.manifest"
   472      }
   473    },
   474    "RT_VERSION": {
   475      "#1": {
   476        "0409": {
   477          "fixed": {
   478            "file_version": "1.2.3.4",
   479            "product_version": "5.6.7.8"
   480          },
   481          "info": {
   482            "0409": {
   483              "CompanyName": "WinRes Corp.",
   484              "FileDescription": "WinRes",
   485              "FileVersion": "1.2.3.4 (Build.42.42)",
   486              "InternalName": "winres",
   487              "LegalCopyright": "© WinRes.",
   488              "OriginalFilename": "WINRES.EXE",
   489              "ProductName": "WinRes CLI",
   490              "ProductVersion": "5.6.7.8"
   491            }
   492          }
   493        }
   494      }
   495    }
   496  }`