mirror of
https://github.com/go-i2p/go-sam-go.git
synced 2025-12-01 09:54:58 -05:00
497 lines
15 KiB
Go
497 lines
15 KiB
Go
package sam3
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/go-i2p/go-sam-go/common"
|
|
"github.com/go-i2p/go-sam-go/datagram"
|
|
"github.com/go-i2p/go-sam-go/primary"
|
|
"github.com/go-i2p/go-sam-go/raw"
|
|
"github.com/go-i2p/go-sam-go/stream"
|
|
)
|
|
|
|
// TestTypeAliases_Compilation verifies that all type aliases compile correctly
|
|
// and maintain proper type identity with their underlying types.
|
|
func TestTypeAliases_Compilation(t *testing.T) {
|
|
// This test ensures that type aliases are properly defined and
|
|
// can be used interchangeably with their underlying types
|
|
|
|
// Test that we can create instances of aliased types
|
|
var sam *SAM
|
|
var resolver *SAMResolver
|
|
var config *I2PConfig
|
|
var emit *SAMEmit
|
|
var options Options
|
|
var streamSession *StreamSession
|
|
var datagramSession *DatagramSession
|
|
var rawSession *RawSession
|
|
var samConn *SAMConn
|
|
var streamListener *StreamListener
|
|
var primarySession *PrimarySession
|
|
var baseSession *BaseSession
|
|
|
|
// Verify these are nil initially (proper zero values)
|
|
if sam != nil || resolver != nil || config != nil || emit != nil ||
|
|
streamSession != nil || datagramSession != nil || rawSession != nil ||
|
|
samConn != nil || streamListener != nil || primarySession != nil ||
|
|
baseSession != nil {
|
|
t.Error("Type aliases should have nil zero values")
|
|
}
|
|
|
|
// Verify options map can be initialized
|
|
if options == nil {
|
|
options = make(Options)
|
|
}
|
|
options["test"] = "value"
|
|
if options["test"] != "value" {
|
|
t.Error("Options type alias should work as map")
|
|
}
|
|
}
|
|
|
|
// TestTypeAliases_Identity verifies that pure type aliases maintain proper type identity
|
|
// and can be used interchangeably with their underlying types from sub-packages.
|
|
// Note: This test excludes wrapper structs like SAM which intentionally have different types.
|
|
func TestTypeAliases_Identity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
aliasType reflect.Type
|
|
sourceType reflect.Type
|
|
}{
|
|
{
|
|
name: "SAMResolver alias identity",
|
|
aliasType: reflect.TypeOf((*SAMResolver)(nil)),
|
|
sourceType: reflect.TypeOf((*common.SAMResolver)(nil)),
|
|
},
|
|
{
|
|
name: "I2PConfig alias identity",
|
|
aliasType: reflect.TypeOf((*I2PConfig)(nil)),
|
|
sourceType: reflect.TypeOf((*common.I2PConfig)(nil)),
|
|
},
|
|
{
|
|
name: "SAMEmit alias identity",
|
|
aliasType: reflect.TypeOf((*SAMEmit)(nil)),
|
|
sourceType: reflect.TypeOf((*common.SAMEmit)(nil)),
|
|
},
|
|
{
|
|
name: "Options alias identity",
|
|
aliasType: reflect.TypeOf((*Options)(nil)),
|
|
sourceType: reflect.TypeOf((*common.Options)(nil)),
|
|
},
|
|
{
|
|
name: "Option alias identity",
|
|
aliasType: reflect.TypeOf((*Option)(nil)),
|
|
sourceType: reflect.TypeOf((*common.Option)(nil)),
|
|
},
|
|
{
|
|
name: "StreamSession alias identity",
|
|
aliasType: reflect.TypeOf((*StreamSession)(nil)),
|
|
sourceType: reflect.TypeOf((*stream.StreamSession)(nil)),
|
|
},
|
|
{
|
|
name: "DatagramSession alias identity",
|
|
aliasType: reflect.TypeOf((*DatagramSession)(nil)),
|
|
sourceType: reflect.TypeOf((*datagram.DatagramSession)(nil)),
|
|
},
|
|
{
|
|
name: "RawSession alias identity",
|
|
aliasType: reflect.TypeOf((*RawSession)(nil)),
|
|
sourceType: reflect.TypeOf((*raw.RawSession)(nil)),
|
|
},
|
|
{
|
|
name: "SAMConn alias identity",
|
|
aliasType: reflect.TypeOf((*SAMConn)(nil)),
|
|
sourceType: reflect.TypeOf((*stream.StreamConn)(nil)),
|
|
},
|
|
{
|
|
name: "StreamListener alias identity",
|
|
aliasType: reflect.TypeOf((*StreamListener)(nil)),
|
|
sourceType: reflect.TypeOf((*stream.StreamListener)(nil)),
|
|
},
|
|
{
|
|
name: "BaseSession alias identity",
|
|
aliasType: reflect.TypeOf((*BaseSession)(nil)),
|
|
sourceType: reflect.TypeOf((*common.BaseSession)(nil)),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.aliasType != tt.sourceType {
|
|
t.Errorf("Type alias %s does not match source type %s",
|
|
tt.aliasType, tt.sourceType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestWrapperStructs_Behavior verifies that wrapper structs like SAM work correctly
|
|
// and provide proper access to embedded functionality while maintaining their own type identity.
|
|
func TestWrapperStructs_Behavior(t *testing.T) {
|
|
t.Run("SAM wrapper struct", func(t *testing.T) {
|
|
// Verify SAM is a wrapper struct, not a pure alias
|
|
samType := reflect.TypeOf((*SAM)(nil))
|
|
commonSAMType := reflect.TypeOf((*common.SAM)(nil))
|
|
|
|
// They should be different types (wrapper vs original)
|
|
if samType == commonSAMType {
|
|
t.Error("SAM should be a wrapper struct, not a pure type alias")
|
|
}
|
|
|
|
// But SAM should embed *common.SAM
|
|
samStructType := samType.Elem()
|
|
if samStructType.Kind() != reflect.Struct {
|
|
t.Error("SAM should be a struct type")
|
|
}
|
|
|
|
// Check that it has an embedded *common.SAM field
|
|
foundEmbedded := false
|
|
for i := 0; i < samStructType.NumField(); i++ {
|
|
field := samStructType.Field(i)
|
|
if field.Anonymous && field.Type == reflect.TypeOf((*common.SAM)(nil)) {
|
|
foundEmbedded = true
|
|
break
|
|
}
|
|
}
|
|
if !foundEmbedded {
|
|
t.Error("SAM should embed *common.SAM")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_Convertibility verifies that type aliases can be converted
|
|
// between the root package types and sub-package types seamlessly.
|
|
func TestTypeAliases_Convertibility(t *testing.T) {
|
|
// Test Options convertibility
|
|
t.Run("Options conversion", func(t *testing.T) {
|
|
var rootOptions Options = make(Options)
|
|
var commonOptions common.Options = rootOptions
|
|
var backToRoot Options = commonOptions
|
|
|
|
rootOptions["test"] = "value"
|
|
if commonOptions["test"] != "value" {
|
|
t.Error("Options conversion failed")
|
|
}
|
|
if backToRoot["test"] != "value" {
|
|
t.Error("Options back-conversion failed")
|
|
}
|
|
})
|
|
|
|
// Test that we can pass aliased types to functions expecting sub-package types
|
|
t.Run("Function parameter compatibility", func(t *testing.T) {
|
|
// This test verifies that aliased types can be passed to functions
|
|
// expecting the original sub-package types
|
|
|
|
// Create a function that accepts common.Options
|
|
processOptions := func(opts common.Options) string {
|
|
return opts["key"]
|
|
}
|
|
|
|
// Create Options using root package alias
|
|
var rootOptions Options = make(Options)
|
|
rootOptions["key"] = "test-value"
|
|
|
|
// Verify we can pass the aliased type to the function
|
|
result := processOptions(rootOptions)
|
|
if result != "test-value" {
|
|
t.Errorf("Expected 'test-value', got %s", result)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestPrimarySession_Structure verifies that PrimarySession is properly aliased
|
|
// to the primary package implementation and can be used as expected.
|
|
func TestPrimarySession_Structure(t *testing.T) {
|
|
t.Run("PrimarySession alias", func(t *testing.T) {
|
|
// PrimarySession is now a type alias to primary.PrimarySession
|
|
// We can't directly instantiate it here since it requires proper initialization
|
|
// through the primary package, but we can verify the type exists
|
|
var ps *PrimarySession
|
|
if ps != nil {
|
|
t.Error("This should not happen - ps should be nil")
|
|
}
|
|
|
|
// Verify that PrimarySession is the correct type alias
|
|
var primaryPS *primary.PrimarySession
|
|
ps = primaryPS // This should compile without error if the alias is correct
|
|
|
|
t.Log("✓ PrimarySession type alias works correctly")
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_InterfaceCompatibility verifies that pure type aliases
|
|
// implement the same interfaces as their source types.
|
|
// Note: This excludes wrapper structs like SAM which have different method sets by design.
|
|
func TestTypeAliases_InterfaceCompatibility(t *testing.T) {
|
|
// This test ensures that pure type aliases maintain interface compatibility
|
|
// Note: We can't test actual interface implementation without instances,
|
|
// but we can verify type structure compatibility
|
|
|
|
t.Run("Pure alias method sets", func(t *testing.T) {
|
|
// Test SAMResolver (a pure alias)
|
|
samResolverType := reflect.TypeOf((*SAMResolver)(nil))
|
|
commonSAMResolverType := reflect.TypeOf((*common.SAMResolver)(nil))
|
|
|
|
if samResolverType != commonSAMResolverType {
|
|
t.Error("SAMResolver type alias does not match common.SAMResolver")
|
|
}
|
|
|
|
// Test Options (a pure alias)
|
|
optionsType := reflect.TypeOf((*Options)(nil))
|
|
commonOptionsType := reflect.TypeOf((*common.Options)(nil))
|
|
|
|
if optionsType != commonOptionsType {
|
|
t.Error("Options type alias does not match common.Options")
|
|
}
|
|
})
|
|
|
|
t.Run("Wrapper struct compatibility", func(t *testing.T) {
|
|
// For wrapper structs like SAM, verify they provide access to embedded functionality
|
|
// without requiring exact method set matching
|
|
|
|
samType := reflect.TypeOf((*SAM)(nil))
|
|
if samType.Elem().Kind() != reflect.Struct {
|
|
t.Error("SAM should be a struct type for method extension")
|
|
}
|
|
|
|
// Verify SAM has embedded *common.SAM field for delegation
|
|
samStruct := samType.Elem()
|
|
hasEmbedded := false
|
|
for i := 0; i < samStruct.NumField(); i++ {
|
|
field := samStruct.Field(i)
|
|
if field.Anonymous && field.Type == reflect.TypeOf((*common.SAM)(nil)) {
|
|
hasEmbedded = true
|
|
break
|
|
}
|
|
}
|
|
if !hasEmbedded {
|
|
t.Error("SAM should embed *common.SAM for delegation")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_PackageDocumentation verifies that all exported types
|
|
// have proper documentation and follow Go documentation conventions.
|
|
func TestTypeAliases_PackageDocumentation(t *testing.T) {
|
|
// This test serves as documentation verification and ensures all
|
|
// types are properly exported and documented
|
|
|
|
expectedTypes := []string{
|
|
"SAM", "SAMResolver", "I2PConfig", "SAMEmit", "Options", "Option",
|
|
"StreamSession", "DatagramSession", "RawSession", "SAMConn",
|
|
"StreamListener", "PrimarySession", "BaseSession",
|
|
}
|
|
|
|
// Use reflection to get package types
|
|
// Note: This is a compile-time verification that all types exist
|
|
for _, typeName := range expectedTypes {
|
|
t.Run("Type_"+typeName, func(t *testing.T) {
|
|
// This test ensures the type exists and is properly exported
|
|
// The mere fact that the test compiles verifies the type exists
|
|
switch typeName {
|
|
case "SAM":
|
|
var _ *SAM
|
|
case "SAMResolver":
|
|
var _ *SAMResolver
|
|
case "I2PConfig":
|
|
var _ *I2PConfig
|
|
case "SAMEmit":
|
|
var _ *SAMEmit
|
|
case "Options":
|
|
var _ Options
|
|
case "Option":
|
|
var _ Option
|
|
case "StreamSession":
|
|
var _ *StreamSession
|
|
case "DatagramSession":
|
|
var _ *DatagramSession
|
|
case "RawSession":
|
|
var _ *RawSession
|
|
case "SAMConn":
|
|
var _ *SAMConn
|
|
case "StreamListener":
|
|
var _ *StreamListener
|
|
case "PrimarySession":
|
|
var _ *PrimarySession
|
|
case "BaseSession":
|
|
var _ *BaseSession
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestTypeAliases_MemoryLayout verifies that type aliases have the same
|
|
// memory layout and size as their underlying types.
|
|
func TestTypeAliases_MemoryLayout(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
aliasSize uintptr
|
|
sourceSize uintptr
|
|
}{
|
|
{
|
|
name: "Options memory layout",
|
|
aliasSize: reflect.TypeOf((*Options)(nil)).Elem().Size(),
|
|
sourceSize: reflect.TypeOf((*common.Options)(nil)).Elem().Size(),
|
|
},
|
|
// Note: Other types are pointers, so their sizes would be pointer size
|
|
// The important thing is that they alias correctly, which is tested elsewhere
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.aliasSize != tt.sourceSize {
|
|
t.Errorf("Memory layout differs: alias=%d, source=%d",
|
|
tt.aliasSize, tt.sourceSize)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkTypeAliases_Performance verifies that type aliases have no
|
|
// performance overhead compared to direct use of sub-package types.
|
|
func BenchmarkTypeAliases_Performance(b *testing.B) {
|
|
b.Run("Options_RootPackage", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
opts := make(Options)
|
|
opts["key"] = "value"
|
|
_ = opts["key"]
|
|
}
|
|
})
|
|
|
|
b.Run("Options_CommonPackage", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
opts := make(common.Options)
|
|
opts["key"] = "value"
|
|
_ = opts["key"]
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_APICompatibility ensures that the type aliases provide
|
|
// the exact API surface expected by sam3 compatibility.
|
|
func TestTypeAliases_APICompatibility(t *testing.T) {
|
|
// This test verifies that our type aliases match the expected sam3 API
|
|
// by checking that all required types are available at package level
|
|
|
|
t.Run("Required types exist", func(t *testing.T) {
|
|
// These should all compile without error
|
|
var (
|
|
_ *SAM
|
|
_ *StreamSession
|
|
_ *DatagramSession
|
|
_ *RawSession
|
|
_ *SAMConn
|
|
_ *StreamListener
|
|
_ *PrimarySession
|
|
_ *SAMResolver
|
|
_ *I2PConfig
|
|
_ *SAMEmit
|
|
_ Options
|
|
_ Option
|
|
_ *BaseSession
|
|
)
|
|
})
|
|
|
|
t.Run("SAMConn is StreamConn alias", func(t *testing.T) {
|
|
// Verify that SAMConn properly aliases stream.StreamConn
|
|
samConnType := reflect.TypeOf((*SAMConn)(nil))
|
|
streamConnType := reflect.TypeOf((*stream.StreamConn)(nil))
|
|
|
|
if samConnType != streamConnType {
|
|
t.Error("SAMConn should be an alias for stream.StreamConn")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_ZeroValues verifies that all type aliases have proper
|
|
// zero values and can be safely used in their zero state.
|
|
func TestTypeAliases_ZeroValues(t *testing.T) {
|
|
t.Run("Pointer types zero values", func(t *testing.T) {
|
|
var (
|
|
sam *SAM
|
|
resolver *SAMResolver
|
|
config *I2PConfig
|
|
emit *SAMEmit
|
|
streamSession *StreamSession
|
|
datagramSession *DatagramSession
|
|
rawSession *RawSession
|
|
samConn *SAMConn
|
|
streamListener *StreamListener
|
|
primarySession *PrimarySession
|
|
baseSession *BaseSession
|
|
)
|
|
|
|
// All should be nil
|
|
if sam != nil || resolver != nil || config != nil || emit != nil ||
|
|
streamSession != nil || datagramSession != nil || rawSession != nil ||
|
|
samConn != nil || streamListener != nil || primarySession != nil ||
|
|
baseSession != nil {
|
|
t.Error("Pointer type aliases should have nil zero values")
|
|
}
|
|
})
|
|
|
|
t.Run("Value types zero values", func(t *testing.T) {
|
|
var (
|
|
options Options
|
|
option Option
|
|
)
|
|
|
|
// Options should be nil map
|
|
if options != nil {
|
|
t.Error("Options should have nil zero value")
|
|
}
|
|
|
|
// Option should be nil function
|
|
if option != nil {
|
|
t.Error("Option should have nil zero value")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestTypeAliases_ImportPaths verifies that the type aliases properly
|
|
// reference the correct sub-package types and maintain clean imports.
|
|
func TestTypeAliases_ImportPaths(t *testing.T) {
|
|
// This is a compile-time test that ensures we're importing the right packages
|
|
// and that all type aliases resolve correctly
|
|
|
|
t.Run("Common package types", func(t *testing.T) {
|
|
// Verify common package aliases work
|
|
// Note: SAM is now an embedded struct, not a direct alias
|
|
var sam *SAM = &SAM{SAM: &common.SAM{}}
|
|
if sam.SAM == nil {
|
|
t.Error("SAM embedding failed")
|
|
}
|
|
var resolver *common.SAMResolver = (*SAMResolver)(nil)
|
|
var config *common.I2PConfig = (*I2PConfig)(nil)
|
|
var emit *common.SAMEmit = (*SAMEmit)(nil)
|
|
var options common.Options = Options(nil)
|
|
var option common.Option = Option(nil)
|
|
var baseSession *common.BaseSession = (*BaseSession)(nil)
|
|
|
|
// These assignments should compile without error
|
|
_ = sam
|
|
_ = resolver
|
|
_ = config
|
|
_ = emit
|
|
_ = options
|
|
_ = option
|
|
_ = baseSession
|
|
})
|
|
|
|
t.Run("Sub-package types", func(t *testing.T) {
|
|
// Verify sub-package aliases work
|
|
var streamSession *stream.StreamSession = (*StreamSession)(nil)
|
|
var datagramSession *datagram.DatagramSession = (*DatagramSession)(nil)
|
|
var rawSession *raw.RawSession = (*RawSession)(nil)
|
|
var samConn *stream.StreamConn = (*SAMConn)(nil)
|
|
var streamListener *stream.StreamListener = (*StreamListener)(nil)
|
|
|
|
// These assignments should compile without error
|
|
_ = streamSession
|
|
_ = datagramSession
|
|
_ = rawSession
|
|
_ = samConn
|
|
_ = streamListener
|
|
})
|
|
}
|