header_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package header
  2. import (
  3. "reflect"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/require"
  7. )
  8. type headerTest struct {
  9. expectedBytes []byte
  10. *H
  11. }
  12. // 0001 0010 00010010
  13. var headerBigEndianTests = []headerTest{{
  14. expectedBytes: []byte{0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9},
  15. // 1010 0000
  16. H: &H{
  17. // 1111 1+2+4+8 = 15
  18. Version: 5,
  19. Type: 4,
  20. Subtype: 0,
  21. Reserved: 0,
  22. RemoteIndex: 10,
  23. MessageCounter: 9,
  24. },
  25. },
  26. }
  27. func TestEncode(t *testing.T) {
  28. for _, tt := range headerBigEndianTests {
  29. b, err := tt.Encode(make([]byte, Len))
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. assert.Equal(t, tt.expectedBytes, b)
  34. }
  35. }
  36. func TestParse(t *testing.T) {
  37. for _, tt := range headerBigEndianTests {
  38. b := tt.expectedBytes
  39. parsedHeader := &H{}
  40. parsedHeader.Parse(b)
  41. if !reflect.DeepEqual(tt.H, parsedHeader) {
  42. t.Fatalf("got %#v; want %#v", parsedHeader, tt.H)
  43. }
  44. }
  45. }
  46. func TestTypeName(t *testing.T) {
  47. assert.Equal(t, "test", TypeName(Test))
  48. assert.Equal(t, "test", (&H{Type: Test}).TypeName())
  49. assert.Equal(t, "unknown", TypeName(99))
  50. assert.Equal(t, "unknown", (&H{Type: 99}).TypeName())
  51. }
  52. func TestSubTypeName(t *testing.T) {
  53. assert.Equal(t, "testRequest", SubTypeName(Test, TestRequest))
  54. assert.Equal(t, "testRequest", (&H{Type: Test, Subtype: TestRequest}).SubTypeName())
  55. assert.Equal(t, "unknown", SubTypeName(99, TestRequest))
  56. assert.Equal(t, "unknown", (&H{Type: 99, Subtype: TestRequest}).SubTypeName())
  57. assert.Equal(t, "unknown", SubTypeName(Test, 99))
  58. assert.Equal(t, "unknown", (&H{Type: Test, Subtype: 99}).SubTypeName())
  59. assert.Equal(t, "none", SubTypeName(Message, 0))
  60. assert.Equal(t, "none", (&H{Type: Message, Subtype: 0}).SubTypeName())
  61. }
  62. func TestTypeMap(t *testing.T) {
  63. // Force people to document this stuff
  64. assert.Equal(t, map[MessageType]string{
  65. Handshake: "handshake",
  66. Message: "message",
  67. RecvError: "recvError",
  68. LightHouse: "lightHouse",
  69. Test: "test",
  70. CloseTunnel: "closeTunnel",
  71. Control: "control",
  72. }, typeMap)
  73. assert.Equal(t, map[MessageType]*map[MessageSubType]string{
  74. Message: {
  75. MessageNone: "none",
  76. MessageRelay: "relay",
  77. },
  78. RecvError: &subTypeNoneMap,
  79. LightHouse: &subTypeNoneMap,
  80. Test: &subTypeTestMap,
  81. CloseTunnel: &subTypeNoneMap,
  82. Handshake: {
  83. HandshakeIXPSK0: "ix_psk0",
  84. HandshakeIXPSK2MLKEM1024: "ix_psk2_mlkem1024",
  85. },
  86. Control: &subTypeNoneMap,
  87. }, subTypeMap)
  88. }
  89. // mapIsValidSubType is the pre-refactor, map-driven definition of a valid
  90. // subtype. IsValidSubType was reimplemented as an explicit switch; this keeps
  91. // the original behavior around so we can prove the switch is equivalent to it.
  92. func mapIsValidSubType(t MessageType, s MessageSubType) bool {
  93. if n, ok := subTypeMap[t]; ok {
  94. if _, ok := (*n)[s]; ok {
  95. return true
  96. }
  97. }
  98. return false
  99. }
  100. func TestIsValidSubType(t *testing.T) {
  101. // Explicit intent table: documents exactly which subtypes are valid so the
  102. // test stays meaningful even if both the switch and subTypeMap change.
  103. assert.True(t, IsValidSubType(Message, MessageNone))
  104. assert.True(t, IsValidSubType(Message, MessageRelay))
  105. assert.False(t, IsValidSubType(Message, 2))
  106. assert.True(t, IsValidSubType(Handshake, HandshakeIXPSK0))
  107. assert.True(t, IsValidSubType(Handshake, HandshakeIXPSK2MLKEM1024))
  108. // HandshakeXXPSK0 is defined but not a wire-valid subtype.
  109. assert.False(t, IsValidSubType(Handshake, HandshakeXXPSK0))
  110. assert.True(t, IsValidSubType(Test, TestRequest))
  111. assert.True(t, IsValidSubType(Test, TestReply))
  112. assert.False(t, IsValidSubType(Test, 2))
  113. // These types only ever carry subtype 0.
  114. for _, mt := range []MessageType{Control, CloseTunnel, RecvError, LightHouse} {
  115. assert.True(t, IsValidSubType(mt, 0), "type %d subtype 0 should be valid", mt)
  116. assert.False(t, IsValidSubType(mt, 1), "type %d subtype 1 should be invalid", mt)
  117. }
  118. // Unknown/unassigned types are never valid.
  119. assert.False(t, IsValidSubType(99, 0))
  120. // Exhaustive proof of equivalence with the original map-driven logic across
  121. // the entire (type, subtype) input space.
  122. for ti := 0; ti <= 0xff; ti++ {
  123. for si := 0; si <= 0xff; si++ {
  124. mt, mst := MessageType(ti), MessageSubType(si)
  125. assert.Equalf(t, mapIsValidSubType(mt, mst), IsValidSubType(mt, mst),
  126. "IsValidSubType(%d, %d) diverged from map-driven definition", ti, si)
  127. }
  128. }
  129. // H method must delegate to the package function.
  130. assert.True(t, (&H{Type: Test, Subtype: TestReply}).IsValidSubType())
  131. assert.False(t, (&H{Type: Handshake, Subtype: HandshakeXXPSK0}).IsValidSubType())
  132. }
  133. func TestHeader_String(t *testing.T) {
  134. assert.Equal(
  135. t,
  136. "ver=100 type=test subtype=testRequest reserved=0x63 remoteindex=98 messagecounter=97",
  137. (&H{100, Test, TestRequest, 99, 98, 97}).String(),
  138. )
  139. }
  140. func TestHeader_MarshalJSON(t *testing.T) {
  141. b, err := (&H{100, Test, TestRequest, 99, 98, 97}).MarshalJSON()
  142. require.NoError(t, err)
  143. assert.Equal(
  144. t,
  145. "{\"messageCounter\":97,\"remoteIndex\":98,\"reserved\":99,\"subType\":\"testRequest\",\"type\":\"test\",\"version\":100}",
  146. string(b),
  147. )
  148. }