github.com/Ptt-official-app/go-bbs@v0.12.0/pttbbs/passwd_test.go (about)

     1  // Copyright 2020 Pichu Chen, The PTT APP Authors
     2  
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package pttbbs
    16  
    17  import (
    18  	"encoding/hex"
    19  	"testing"
    20  	"time"
    21  )
    22  
    23  func TestOpenUserecFile(t *testing.T) {
    24  
    25  	actualUserecs, err := OpenUserecFile("testcase/passwd/01.PASSWDS")
    26  	if err != nil {
    27  		t.Errorf("OpenUserecFile() error = %v", err)
    28  		return
    29  	}
    30  	expected := []Userec{
    31  		{
    32  			Version:       4194,
    33  			userID:        "SYSOP",
    34  			realName:      "CodingMan",
    35  			nickname:      "神",
    36  			password:      "bhwvOJtfT1TAI",
    37  			userFlag:      0x02000A60,
    38  			UserLevel:     0x20000407,
    39  			numLoginDays:  2,
    40  			numPosts:      0,
    41  			firstLogin:    time.Date(2020, 9, 21, 9, 41, 28, 0, time.UTC),
    42  			lastLogin:     time.Date(2020, 9, 22, 6, 28, 14, 0, time.UTC),
    43  			lastHost:      "59.124.167.226",
    44  			money:         0,
    45  			Address:       "新竹縣子虛鄉烏有村543號",
    46  			Over18:        true,
    47  			Pager:         1,
    48  			Invisible:     false,
    49  			Career:        "全景軟體",
    50  			LastSeen:      time.Date(2020, 9, 21, 9, 41, 28, 0, time.UTC),
    51  			TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
    52  			TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
    53  			LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
    54  
    55  			TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
    56  			TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
    57  			BadPost:           0x01,
    58  			ViolateLaw:        0x01,
    59  			Five: GameScore{
    60  				Win:  0x0001,
    61  				Lose: 0x0002,
    62  				Tie:  0x0003,
    63  			},
    64  			ChineseChess: GameScore{
    65  				Win:  0x0004,
    66  				Lose: 0x0005,
    67  				Tie:  0x0006,
    68  			},
    69  			Conn6: GameScore{
    70  				Win:  0x0007,
    71  				Lose: 0x0008,
    72  				Tie:  0x0009,
    73  			},
    74  			GoChess: GameScore{
    75  				Win:  0x000a,
    76  				Lose: 0x000b,
    77  				Tie:  0x000c,
    78  			},
    79  			DarkChess: GameScore{
    80  				Win:  0x000d,
    81  				Lose: 0x000e,
    82  				Tie:  0x000f,
    83  			},
    84  			MyAngel: "SYSOP",
    85  		},
    86  		{
    87  			Version:       4194,
    88  			userID:        "CodingMan",
    89  			realName:      "朱元璋",
    90  			nickname:      "程式俠",
    91  			password:      "u8mLG.ktfOk3w",
    92  			userFlag:      0x02000AE0,
    93  			UserLevel:     0x0000001F,
    94  			numLoginDays:  1,
    95  			numPosts:      0,
    96  			firstLogin:    time.Date(2020, 9, 22, 1, 20, 59, 0, time.UTC),
    97  			lastLogin:     time.Date(2020, 9, 22, 1, 26, 00, 0, time.UTC),
    98  			lastHost:      "59.124.167.226",
    99  			Email:         "x",
   100  			Address:       "新竹縣子虛鄉烏有村543號",
   101  			Justify:       "[SYSOP] 09/22/2020 01:25:53 Tue",
   102  			Over18:        true,
   103  			Pager:         1,
   104  			Career:        "全景軟體",
   105  			LastSeen:      time.Date(2020, 9, 22, 1, 26, 00, 0, time.UTC),
   106  			TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   107  			TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   108  			LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   109  
   110  			TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   111  			TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   112  			BadPost:           0x02,
   113  			ViolateLaw:        0x02,
   114  			Five: GameScore{
   115  				Win:  0x0101,
   116  				Lose: 0x0102,
   117  				Tie:  0x0103,
   118  			},
   119  			ChineseChess: GameScore{
   120  				Win:  0x0104,
   121  				Lose: 0x0105,
   122  				Tie:  0x0106,
   123  			},
   124  			Conn6: GameScore{
   125  				Win:  0x0107,
   126  				Lose: 0x0108,
   127  				Tie:  0x0109,
   128  			},
   129  			GoChess: GameScore{
   130  				Win:  0x010a,
   131  				Lose: 0x010b,
   132  				Tie:  0x010c,
   133  			},
   134  			DarkChess: GameScore{
   135  				Win:  0x010d,
   136  				Lose: 0x010e,
   137  				Tie:  0x010f,
   138  			},
   139  			MyAngel: "CodingMan",
   140  		},
   141  		{
   142  			Version:       4194,
   143  			userID:        "pichu",
   144  			realName:      "Pichu",
   145  			nickname:      "Pichu",
   146  			password:      "KO27TyME.3/tw",
   147  			userFlag:      0x02000AE0,
   148  			UserLevel:     0x00000007,
   149  			numLoginDays:  1,
   150  			numPosts:      0,
   151  			firstLogin:    time.Date(2020, 9, 22, 6, 21, 15, 0, time.UTC),
   152  			lastLogin:     time.Date(2020, 9, 22, 9, 16, 44, 0, time.UTC),
   153  			lastHost:      "103.246.218.43",
   154  			Career:        "台灣智慧家庭",
   155  			LastSeen:      time.Date(2020, 9, 22, 9, 16, 44, 0, time.UTC),
   156  			TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   157  			TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   158  			LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   159  			Email:         "pichu@tih.tw",
   160  			Address:       "北市蘆洲區123路3號",
   161  			Justify:       "<Email>",
   162  			Over18:        true,
   163  			Pager:         1,
   164  
   165  			TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   166  			TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   167  			BadPost:           0x03,
   168  			ViolateLaw:        0x03,
   169  			Five: GameScore{
   170  				Win:  0x0011,
   171  				Lose: 0x0012,
   172  				Tie:  0x0013,
   173  			},
   174  			ChineseChess: GameScore{
   175  				Win:  0x0014,
   176  				Lose: 0x0015,
   177  				Tie:  0x0016,
   178  			},
   179  			Conn6: GameScore{
   180  				Win:  0x0017,
   181  				Lose: 0x0018,
   182  				Tie:  0x0019,
   183  			},
   184  			GoChess: GameScore{
   185  				Win:  0x001a,
   186  				Lose: 0x001b,
   187  				Tie:  0x001c,
   188  			},
   189  			DarkChess: GameScore{
   190  				Win:  0x001d,
   191  				Lose: 0x001e,
   192  				Tie:  0x001f,
   193  			},
   194  			MyAngel: "pichu",
   195  		},
   196  		{
   197  			Version:       4194,
   198  			userID:        "Kahou",
   199  			realName:      "林嘉豪",
   200  			nickname:      "Kahou",
   201  			password:      "V3nkaYTLnDPUA",
   202  			userFlag:      0x02000AE0,
   203  			UserLevel:     0x00000007,
   204  			numLoginDays:  1,
   205  			numPosts:      0,
   206  			firstLogin:    time.Date(2020, 9, 22, 7, 4, 26, 0, time.UTC),
   207  			lastLogin:     time.Date(2020, 9, 22, 7, 4, 26, 0, time.UTC),
   208  			lastHost:      "180.217.174.18",
   209  			Career:        "我的服務單位",
   210  			LastSeen:      time.Date(2020, 9, 22, 7, 4, 26, 0, time.UTC),
   211  			TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   212  			TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   213  			LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   214  			Email:         "creator.kahou@gmail.com",
   215  			Address:       "新北市板橋信義路111號",
   216  			Justify:       "<Email>",
   217  			Over18:        true,
   218  			Pager:         1,
   219  
   220  			TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   221  			TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   222  			BadPost:           0x04,
   223  			ViolateLaw:        0x04,
   224  			Five: GameScore{
   225  				Win:  0x0111,
   226  				Lose: 0x0112,
   227  				Tie:  0x0113,
   228  			},
   229  			ChineseChess: GameScore{
   230  				Win:  0x0114,
   231  				Lose: 0x0115,
   232  				Tie:  0x0116,
   233  			},
   234  			Conn6: GameScore{
   235  				Win:  0x0117,
   236  				Lose: 0x0118,
   237  				Tie:  0x0119,
   238  			},
   239  			GoChess: GameScore{
   240  				Win:  0x011a,
   241  				Lose: 0x011b,
   242  				Tie:  0x011c,
   243  			},
   244  			DarkChess: GameScore{
   245  				Win:  0x011d,
   246  				Lose: 0x011e,
   247  				Tie:  0x011f,
   248  			},
   249  			MyAngel: "Kahou",
   250  		},
   251  		{
   252  			Version:       4194,
   253  			userID:        "Kahou2",
   254  			realName:      "Kahou",
   255  			nickname:      "kahou",
   256  			password:      "R7shIAOZgQCKs",
   257  			userFlag:      0x02000AE0,
   258  			UserLevel:     0x0000001F,
   259  			numLoginDays:  1,
   260  			numPosts:      0,
   261  			firstLogin:    time.Date(2020, 9, 22, 7, 15, 39, 0, time.UTC),
   262  			lastLogin:     time.Date(2020, 9, 22, 7, 40, 1, 0, time.UTC),
   263  			lastHost:      "180.217.174.18",
   264  			Career:        "我的服務單位",
   265  			LastSeen:      time.Date(2020, 9, 22, 7, 40, 01, 0, time.UTC),
   266  			TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   267  			TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   268  			LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   269  			Email:         "x",
   270  			Address:       "新北市板橋區信義路111號",
   271  			Justify:       "[SYSOP] 09/22/2020 07:51:12 Tue",
   272  			Over18:        true,
   273  			Pager:         1,
   274  
   275  			TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   276  			TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   277  			BadPost:           0x05,
   278  			ViolateLaw:        0x05,
   279  			Five: GameScore{
   280  				Win:  0x0021,
   281  				Lose: 0x0022,
   282  				Tie:  0x0023,
   283  			},
   284  			ChineseChess: GameScore{
   285  				Win:  0x0024,
   286  				Lose: 0x0025,
   287  				Tie:  0x0026,
   288  			},
   289  			Conn6: GameScore{
   290  				Win:  0x0027,
   291  				Lose: 0x0028,
   292  				Tie:  0x0029,
   293  			},
   294  			GoChess: GameScore{
   295  				Win:  0x002a,
   296  				Lose: 0x002b,
   297  				Tie:  0x002c,
   298  			},
   299  			DarkChess: GameScore{
   300  				Win:  0x002d,
   301  				Lose: 0x002e,
   302  				Tie:  0x002f,
   303  			},
   304  			MyAngel: "Kahou2",
   305  		},
   306  	}
   307  
   308  	for index, actual := range actualUserecs {
   309  
   310  		ok := index < len(expected)
   311  		if !ok {
   312  			t.Logf("expected case %d not exist, assume all 0", index)
   313  			break
   314  		}
   315  		expected := expected[index]
   316  
   317  		if actual.Version != expected.Version {
   318  			t.Errorf("Version not match with index %d, expected: %v, got: %v", index, expected.Version, actual.Version)
   319  		}
   320  
   321  		if actual.userID != expected.userID {
   322  			t.Errorf("UserID not match with index %d, expected: %v, got: %v", index, expected.userID, actual.userID)
   323  		}
   324  
   325  		if actual.realName != expected.realName {
   326  			t.Errorf("RealName not match with index %d, expected: %v, got: %v", index, expected.realName, actual.realName)
   327  		}
   328  
   329  		if actual.nickname != expected.nickname {
   330  			t.Errorf("Nickname not match with index %d, expected: %v, got: %v", index, expected.nickname, actual.nickname)
   331  		}
   332  
   333  		if actual.password != expected.password {
   334  			t.Errorf("Password not match with index %d, expected: %v, got: %v", index, expected.password, actual.password)
   335  		}
   336  
   337  		if actual.userFlag != expected.userFlag {
   338  			t.Errorf("userFlag not match with index %d, expected: 0x%08X, got: 0x%08X", index, expected.userFlag, actual.userFlag)
   339  		}
   340  
   341  		if actual.UserLevel != expected.UserLevel {
   342  			t.Errorf("UserLevel not match with index %d, expected: 0x%08X, got: 0x%08X", index, expected.UserLevel, actual.UserLevel)
   343  		}
   344  
   345  		if actual.numLoginDays != expected.numLoginDays {
   346  			t.Errorf("NumLoginDays not match with index %d, expected: %v, got: %v", index, expected.numLoginDays, actual.numLoginDays)
   347  		}
   348  
   349  		if actual.numPosts != expected.numPosts {
   350  			t.Errorf("NumPosts not match with index %d, expected: %v, got: %v", index, expected.numPosts, actual.numPosts)
   351  		}
   352  
   353  		if actual.firstLogin.Sub(expected.firstLogin) != 0 {
   354  			t.Errorf("FirstLogin not match with index %d, expected: %v, got: %v", index, expected.firstLogin, actual.firstLogin)
   355  		}
   356  
   357  		if actual.lastLogin.Sub(expected.lastLogin) != 0 {
   358  			t.Errorf("LastLogin not match with index %d, expected: %v, got: %v", index, expected.lastLogin, actual.lastLogin)
   359  		}
   360  
   361  		if actual.lastHost != expected.lastHost {
   362  			t.Errorf("LastHost not match with index %d, expected: %v, got: %v", index, expected.lastHost, actual.lastHost)
   363  		}
   364  
   365  		if actual.money != expected.money {
   366  			t.Errorf("Money not match with index %d, expected: %v, got: %v", index, expected.money, actual.money)
   367  		}
   368  
   369  		if actual.Email != expected.Email {
   370  			t.Errorf("Email not match with index %d, expected: %v, got: %v", index, expected.Email, actual.Email)
   371  		}
   372  
   373  		if actual.Address != expected.Address {
   374  			t.Errorf("Address not match with index %d, expected: %v, got: %v", index, expected.Address, actual.Address)
   375  		}
   376  
   377  		if actual.Justify != expected.Justify {
   378  			t.Errorf("Justify not match with index %d, expected: %v, got: %v", index, expected.Justify, actual.Justify)
   379  		}
   380  
   381  		if actual.Over18 != expected.Over18 {
   382  			t.Errorf("Over18 not match with index %d, expected: %v, got: %v", index, expected.Over18, actual.Over18)
   383  		}
   384  
   385  		if actual.PagerUIType != expected.PagerUIType {
   386  			t.Errorf("PagerUIType not match with index %d, expected: %v, got: %v", index, expected.PagerUIType, actual.PagerUIType)
   387  		}
   388  
   389  		if actual.Pager != expected.Pager {
   390  			t.Errorf("Pager not match with index %d, expected: %v, got: %v", index, expected.Pager, actual.Pager)
   391  		}
   392  
   393  		if actual.Invisible != expected.Invisible {
   394  			t.Errorf("Invisible not match with index %d, expected: %v, got: %v", index, expected.Invisible, actual.Invisible)
   395  		}
   396  
   397  		if actual.ExMailBox != expected.ExMailBox {
   398  			t.Errorf("ExMailBox not match with index %d, expected: %v, got: %v", index, expected.ExMailBox, actual.ExMailBox)
   399  		}
   400  
   401  		if actual.Career != expected.Career {
   402  			t.Errorf("Career not match with index %d, expected: %v, got: %v", index, expected.Career, actual.Career)
   403  		}
   404  
   405  		if actual.Role != expected.Role {
   406  			t.Errorf("Role not match with index %d, expected: %v, got: %v", index, expected.Role, actual.Role)
   407  		}
   408  
   409  		if actual.LastSeen.Sub(expected.LastSeen) != 0 {
   410  			t.Errorf("LastSeen not match with index %d, expected: %v, got: %v", index, expected.LastSeen, actual.LastSeen)
   411  		}
   412  
   413  		if actual.TimeSetAngel.Sub(expected.TimeSetAngel) != 0 {
   414  			t.Errorf("TimeSetAngel not match with index %d, expected: %v, got: %v", index, expected.TimeSetAngel, actual.TimeSetAngel)
   415  		}
   416  
   417  		if actual.TimePlayAngel.Sub(expected.TimePlayAngel) != 0 {
   418  			t.Errorf("TimePlayAngel not match with index %d, expected: %v, got: %v", index, expected.TimePlayAngel, actual.TimePlayAngel)
   419  		}
   420  
   421  		if actual.LastSong.Sub(expected.LastSong) != 0 {
   422  			t.Errorf("LastSong not match with index %d, expected: %v, got: %v", index, expected.LastSong, actual.LastSong)
   423  		}
   424  
   425  		if actual.LoginView != expected.LoginView {
   426  			t.Errorf("LoginView not match with index %d, expected: %v, got: %v", index, expected.LoginView, actual.LoginView)
   427  		}
   428  
   429  		if actual.ViolateLaw != expected.ViolateLaw {
   430  			t.Errorf("ViolateLaw not match with index %d, expected: %v, got: %v", index, expected.ViolateLaw, actual.ViolateLaw)
   431  		}
   432  
   433  		if actual.Five.Win != expected.Five.Win {
   434  			t.Errorf("Five.Win not match with index %d, expected: %v, got: %v", index, expected.Five.Win, actual.Five.Win)
   435  		}
   436  
   437  		if actual.Five.Lose != expected.Five.Lose {
   438  			t.Errorf("Five.Lose not match with index %d, expected: %v, got: %v", index, expected.Five.Lose, actual.Five.Lose)
   439  		}
   440  
   441  		if actual.Five.Tie != expected.Five.Tie {
   442  			t.Errorf("Five.Tie not match with index %d, expected: %v, got: %v", index, expected.Five.Tie, actual.Five.Tie)
   443  		}
   444  
   445  		if actual.ChineseChess.Win != expected.ChineseChess.Win {
   446  			t.Errorf("ChineseChess.Win not match with index %d, expected: %v, got: %v", index, expected.ChineseChess.Win, actual.ChineseChess.Win)
   447  		}
   448  
   449  		if actual.ChineseChess.Lose != expected.ChineseChess.Lose {
   450  			t.Errorf("ChineseChess.Lose not match with index %d, expected: %v, got: %v", index, expected.ChineseChess.Lose, actual.ChineseChess.Lose)
   451  		}
   452  
   453  		if actual.ChineseChess.Tie != expected.ChineseChess.Tie {
   454  			t.Errorf("ChineseChess.Tie not match with index %d, expected: %v, got: %v", index, expected.ChineseChess.Tie, actual.ChineseChess.Tie)
   455  		}
   456  
   457  		if actual.Conn6.Win != expected.Conn6.Win {
   458  			t.Errorf("Conn6.Win not match with index %d, expected: %v, got: %v", index, expected.Conn6.Win, actual.Conn6.Win)
   459  		}
   460  
   461  		if actual.Conn6.Lose != expected.Conn6.Lose {
   462  			t.Errorf("Conn6.Lose not match with index %d, expected: %v, got: %v", index, expected.Conn6.Lose, actual.Conn6.Lose)
   463  		}
   464  
   465  		if actual.Conn6.Tie != expected.Conn6.Tie {
   466  			t.Errorf("Conn6.Tie not match with index %d, expected: %v, got: %v", index, expected.Conn6.Tie, actual.Conn6.Tie)
   467  		}
   468  
   469  		if actual.GoChess.Win != expected.GoChess.Win {
   470  			t.Errorf("GoChess.Win not match with index %d, expected: %v, got: %v", index, expected.GoChess.Win, actual.GoChess.Win)
   471  		}
   472  
   473  		if actual.GoChess.Lose != expected.GoChess.Lose {
   474  			t.Errorf("GoChess.Lose not match with index %d, expected: %v, got: %v", index, expected.GoChess.Lose, actual.GoChess.Lose)
   475  		}
   476  
   477  		if actual.GoChess.Tie != expected.GoChess.Tie {
   478  			t.Errorf("GoChess.Tie not match with index %d, expected: %v, got: %v", index, expected.GoChess.Tie, actual.GoChess.Tie)
   479  		}
   480  
   481  		if actual.DarkChess.Win != expected.DarkChess.Win {
   482  			t.Errorf("DarkChess.Win not match with index %d, expected: %v, got: %v", index, expected.DarkChess.Win, actual.DarkChess.Win)
   483  		}
   484  
   485  		if actual.DarkChess.Lose != expected.DarkChess.Lose {
   486  			t.Errorf("DarkChess.Lose not match with index %d, expected: %v, got: %v", index, expected.DarkChess.Lose, actual.DarkChess.Lose)
   487  		}
   488  
   489  		if actual.UaVersion != expected.UaVersion {
   490  			t.Errorf("UaVersion not match with index %d, expected: %v, got: %v", index, expected.UaVersion, actual.UaVersion)
   491  		}
   492  
   493  		if actual.Signature != expected.Signature {
   494  			t.Errorf("Signature not match with index %d, expected: %v, got: %v", index, expected.Signature, actual.Signature)
   495  		}
   496  
   497  		if actual.BadPost != expected.BadPost {
   498  			t.Errorf("BadPost not match with index %d, expected: %v, got: %v", index, expected.BadPost, actual.BadPost)
   499  		}
   500  
   501  		if actual.DarkChess.Tie != expected.DarkChess.Tie {
   502  			t.Errorf("DarkChess.Tie not match with index %d, expected: %v, got: %v", index, expected.DarkChess.Tie, actual.DarkChess.Tie)
   503  		}
   504  
   505  		if actual.MyAngel != expected.MyAngel {
   506  			t.Errorf("MyAngel not match with index %d, expected: %v, got: %v", index, expected.MyAngel, actual.MyAngel)
   507  		}
   508  
   509  		if actual.ChessEloRating != expected.ChessEloRating {
   510  			t.Errorf("ChessEloRating not match with index %d, expected: %v, got: %v", index, expected.ChessEloRating, actual.ChessEloRating)
   511  		}
   512  
   513  		if actual.WithMe != expected.WithMe {
   514  			t.Errorf("WithMe not match with index %d, expected: %v, got: %v", index, expected.WithMe, actual.WithMe)
   515  		}
   516  
   517  		if actual.TimeRemoveBadPost.Sub(expected.TimeRemoveBadPost) != 0 {
   518  			t.Errorf("TimeRemoveBadPost not match with index %d, expected: %v, got: %v", index, expected.TimeRemoveBadPost, actual.TimeRemoveBadPost)
   519  		}
   520  
   521  		if actual.TimeViolateLaw.Sub(expected.TimeViolateLaw) != 0 {
   522  			t.Errorf("TimeViolateLaw not match with index %d, expected: %v, got: %v", index, expected.TimeViolateLaw, actual.TimeViolateLaw)
   523  		}
   524  
   525  	}
   526  
   527  }
   528  
   529  func TestMarshalBinaryUserec(t *testing.T) {
   530  	type TestCase struct {
   531  		Input    Userec
   532  		Expected []byte
   533  	}
   534  
   535  	testcase := []TestCase{
   536  		{
   537  			Input: Userec{
   538  				Version:       4194,
   539  				userID:        "SYSOP",
   540  				realName:      "CodingMan",
   541  				nickname:      "神",
   542  				password:      "bhwvOJtfT1TAI",
   543  				userFlag:      0x02000A60,
   544  				UserLevel:     0x20000407,
   545  				numLoginDays:  2,
   546  				numPosts:      0,
   547  				firstLogin:    time.Date(2020, 9, 21, 9, 41, 28, 0, time.UTC),
   548  				lastLogin:     time.Date(2020, 9, 22, 6, 28, 14, 0, time.UTC),
   549  				lastHost:      "59.124.167.226",
   550  				money:         0,
   551  				Address:       "新竹縣子虛鄉烏有村543號",
   552  				Over18:        true,
   553  				Pager:         1,
   554  				Invisible:     false,
   555  				Career:        "全景軟體",
   556  				LastSeen:      time.Date(2020, 9, 21, 9, 41, 28, 0, time.UTC),
   557  				TimeSetAngel:  time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   558  				TimePlayAngel: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   559  				LastSong:      time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   560  
   561  				TimeRemoveBadPost: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   562  				TimeViolateLaw:    time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
   563  				BadPost:           0x01,
   564  				ViolateLaw:        0x01,
   565  				Five: GameScore{
   566  					Win:  0x0001,
   567  					Lose: 0x0002,
   568  					Tie:  0x0003,
   569  				},
   570  				ChineseChess: GameScore{
   571  					Win:  0x0004,
   572  					Lose: 0x0005,
   573  					Tie:  0x0006,
   574  				},
   575  				Conn6: GameScore{
   576  					Win:  0x0007,
   577  					Lose: 0x0008,
   578  					Tie:  0x0009,
   579  				},
   580  				GoChess: GameScore{
   581  					Win:  0x000a,
   582  					Lose: 0x000b,
   583  					Tie:  0x000c,
   584  				},
   585  				DarkChess: GameScore{
   586  					Win:  0x000d,
   587  					Lose: 0x000e,
   588  					Tie:  0x000f,
   589  				},
   590  				MyAngel: "SYSOP",
   591  			},
   592  			Expected: hexToByte(`
   593  			6210 0000 5359 534f 5000 0000 0000 0000
   594  0043 6f64 696e 674d 616e 0000 0000 0000
   595  0000 0000 00af ab00 0000 0000 0000 0000
   596  0000 0000 0000 0000 0000 0000 0062 6877
   597  764f 4a74 6654 3154 4149 0000 600a 0002
   598  0000 0000 0704 0020 0200 0000 0000 0000
   599  4875 685f 7e99 695f 3539 2e31 3234 2e31
   600  3637 2e32 3236 0000 0000 0000 0000 0000
   601  0000 0000 0000 0000 0000 0000 0000 0000
   602  0000 0000 0000 0000 0000 0000 0000 0000
   603  0000 0000 0000 0000 0000 0000 0000 0000
   604  0000 b773 a6cb bfa4 a46c b5ea b66d af51
   605  a6b3 a7f8 3534 33b8 b900 0000 0000 0000
   606  0000 0000 0000 0000 0000 0000 0000 0000
   607  0000 0000 0000 0000 0000 0000 0000 0000
   608  0000 0000 0000 0000 0000 0000 0000 0000
   609  0000 0000 0000 0000 0000 0000 0000 0100
   610  0100 0000 0000 0000 0000 0000 a5fe b4ba
   611  b36e c5e9 0000 0000 0000 0000 0000 0000
   612  0000 0000 0000 0000 0000 0000 0000 0000
   613  0000 0000 0000 0000 0000 0000 0000 0000
   614  0000 0000 0000 0000 0000 0000 0000 0000
   615  0000 0000 0000 0000 0000 0000 0000 0000
   616  0000 0000 0000 0000 0000 0000 0000 0000
   617  0000 0000 0000 0000 0000 0000 4875 685f
   618  0000 0000 0000 0000 0000 0000 0000 0000
   619  0000 0100 0100 0200 0300 0400 0500 0600
   620  0700 0800 0900 0000 0a00 0b00 0c00 0d00
   621  0e00 0000 0001 0f00 5359 534F 5000 0000
   622  0000 0000 0000 0000 0000 0000 0000 0000
   623  0000 0000 0000 0000 0000 0000 0000 0000
   624  0000 0000 0000 0000 0000 0000 0000 0000
   625  			`),
   626  		},
   627  	}
   628  
   629  	for index, c := range testcase {
   630  		b, err := c.Input.MarshalBinary()
   631  		t.Logf("log: %q, %q", b, err)
   632  		if hex.Dump(b) != hex.Dump(c.Expected) {
   633  			t.Errorf("Expected byte not match in index %d, expected: \n%s\n, got: \n%s", index, hex.Dump(c.Expected), hex.Dump(b))
   634  		}
   635  
   636  	}
   637  
   638  }