improve validate and tests
This commit is contained in:
parent
92640d1ad0
commit
6d3408f34c
@ -2,6 +2,7 @@ package sensors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -13,6 +14,12 @@ func (s *Sensor) Validate() error {
|
||||
return ErrInvalidSensorType
|
||||
}
|
||||
|
||||
validTypes := []SType{Temperature, Humidity, CarbonDioxide, Pressure, Proximity, Light}
|
||||
isValid := slices.Contains(validTypes, s.SensorType)
|
||||
if !isValid {
|
||||
return ErrInvalidSensorType
|
||||
}
|
||||
|
||||
if s.SamplingInterval == nil {
|
||||
defaultInterval := time.Second * 3600
|
||||
s.SamplingInterval = &defaultInterval
|
||||
|
||||
652
internal/domains/sensors/domain_test.go
Normal file
652
internal/domains/sensors/domain_test.go
Normal file
@ -0,0 +1,652 @@
|
||||
package sensors
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_SensorValidate(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
given Sensor
|
||||
expected Sensor
|
||||
expecErr bool
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "success with all fields",
|
||||
given: Sensor{
|
||||
SensorID: "temp-001",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Hour * 24),
|
||||
ThresholdAbove: ptr(50.0),
|
||||
ThresholdBelow: ptr(-10.0),
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-001",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Hour * 24),
|
||||
ThresholdAbove: ptr(50.0),
|
||||
ThresholdBelow: ptr(-10.0),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "error when sensor_id is empty",
|
||||
given: Sensor{
|
||||
SensorID: "",
|
||||
SensorType: "temperature",
|
||||
},
|
||||
expecErr: true,
|
||||
},
|
||||
{
|
||||
name: "error when sensor_type is empty",
|
||||
given: Sensor{
|
||||
SensorID: "temp-001",
|
||||
SensorType: "",
|
||||
},
|
||||
expecErr: true,
|
||||
},
|
||||
{
|
||||
name: "sensor type not in const",
|
||||
given: Sensor{
|
||||
SensorID: "temp-001",
|
||||
SensorType: "unknown",
|
||||
},
|
||||
expecErr: true,
|
||||
},
|
||||
{
|
||||
name: "default sampling_interval when nil",
|
||||
given: Sensor{
|
||||
SensorID: "temp-002",
|
||||
SensorType: "humidity",
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-002",
|
||||
SensorType: "humidity",
|
||||
SamplingInterval: ptr(time.Second * 3600),
|
||||
ThresholdAbove: ptr(100.0),
|
||||
ThresholdBelow: ptr(0.0),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "default threshold_above when nil",
|
||||
given: Sensor{
|
||||
SensorID: "temp-003",
|
||||
SensorType: "pressure",
|
||||
SamplingInterval: ptr(time.Minute * 5),
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-003",
|
||||
SensorType: "pressure",
|
||||
SamplingInterval: ptr(time.Minute * 5),
|
||||
ThresholdAbove: ptr(100.0),
|
||||
ThresholdBelow: ptr(0.0),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "default threshold_below when nil",
|
||||
given: Sensor{
|
||||
SensorID: "temp-004",
|
||||
SensorType: "light",
|
||||
SamplingInterval: ptr(time.Second * 30),
|
||||
ThresholdAbove: ptr(200.0),
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-004",
|
||||
SensorType: "light",
|
||||
SamplingInterval: ptr(time.Second * 30),
|
||||
ThresholdAbove: ptr(200.0),
|
||||
ThresholdBelow: ptr(0.0),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "zero values are preserved",
|
||||
given: Sensor{
|
||||
SensorID: "temp-005",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Second * 10),
|
||||
ThresholdAbove: ptr(0.0),
|
||||
ThresholdBelow: ptr(0.0),
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-005",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Second * 10),
|
||||
ThresholdAbove: ptr(0.0),
|
||||
ThresholdBelow: ptr(0.0),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "negative threshold_below is valid",
|
||||
given: Sensor{
|
||||
SensorID: "temp-006",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Minute * 2),
|
||||
ThresholdAbove: ptr(35.0),
|
||||
ThresholdBelow: ptr(-20.5),
|
||||
},
|
||||
expected: Sensor{
|
||||
SensorID: "temp-006",
|
||||
SensorType: "temperature",
|
||||
SamplingInterval: ptr(time.Minute * 2),
|
||||
ThresholdAbove: ptr(35.0),
|
||||
ThresholdBelow: ptr(-20.5),
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.given.Validate()
|
||||
|
||||
if tt.expecErr && err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.expecErr && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expecErr {
|
||||
return
|
||||
}
|
||||
|
||||
if tt.given.SensorID != tt.expected.SensorID {
|
||||
t.Errorf("SensorID: expected %q, got %q", tt.expected.SensorID, tt.given.SensorID)
|
||||
}
|
||||
|
||||
if tt.given.SensorType != tt.expected.SensorType {
|
||||
t.Errorf("expected %q, got %q", tt.expected.SensorType, tt.given.SensorType)
|
||||
}
|
||||
|
||||
if tt.given.SamplingInterval == nil || tt.expected.SamplingInterval == nil {
|
||||
if tt.given.SamplingInterval != tt.expected.SamplingInterval {
|
||||
t.Errorf("expected %v, got %v", tt.expected.SamplingInterval, tt.given.SamplingInterval)
|
||||
}
|
||||
} else if *tt.given.SamplingInterval != *tt.expected.SamplingInterval {
|
||||
t.Errorf("expected %v, got %v", *tt.expected.SamplingInterval, *tt.given.SamplingInterval)
|
||||
}
|
||||
|
||||
if tt.given.ThresholdAbove == nil || tt.expected.ThresholdAbove == nil {
|
||||
if tt.given.ThresholdAbove != tt.expected.ThresholdAbove {
|
||||
t.Errorf("expected %v, got %v", tt.expected.ThresholdAbove, tt.given.ThresholdAbove)
|
||||
}
|
||||
} else if *tt.given.ThresholdAbove != *tt.expected.ThresholdAbove {
|
||||
t.Errorf("expected %v, got %v", *tt.expected.ThresholdAbove, *tt.given.ThresholdAbove)
|
||||
}
|
||||
|
||||
if tt.given.ThresholdBelow == nil || tt.expected.ThresholdBelow == nil {
|
||||
if tt.given.ThresholdBelow != tt.expected.ThresholdBelow {
|
||||
t.Errorf("expected %v, got %v", tt.expected.ThresholdBelow, tt.given.ThresholdBelow)
|
||||
}
|
||||
} else if *tt.given.ThresholdBelow != *tt.expected.ThresholdBelow {
|
||||
t.Errorf("expected %v, got %v", *tt.expected.ThresholdBelow, *tt.given.ThresholdBelow)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SensorData_IsOutOfRangeAbove(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
data SensorData
|
||||
sensor Sensor
|
||||
expected bool
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "value above threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 150.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdAbove: ptr(100.0),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value below threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 50.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdAbove: ptr(100.0),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value equal to threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 100.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdAbove: ptr(100.0),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "negative value above negative threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: -5.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdAbove: ptr(-10.0),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.data.IsOutOfRangeAbove(tt.sensor)
|
||||
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SensorData_IsOutOfRangeBelow(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
data SensorData
|
||||
sensor Sensor
|
||||
expected bool
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "value below threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 5.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdBelow: ptr(10.0),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value above threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 50.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdBelow: ptr(10.0),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value equal to threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 10.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdBelow: ptr(10.0),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "negative value below threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: -15.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdBelow: ptr(-10.0),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "zero value below positive threshold",
|
||||
data: SensorData{
|
||||
SensorID: "temp-001",
|
||||
Value: 0.0,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
sensor: Sensor{
|
||||
SensorID: "temp-001",
|
||||
ThresholdBelow: ptr(5.0),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.data.IsOutOfRangeBelow(tt.sensor)
|
||||
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SensorRequest_Validate(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
given SensorRequest
|
||||
expecErr bool
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "valid request with sensor_id",
|
||||
given: SensorRequest{
|
||||
SensorID: "temp-001",
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "error when sensor_id is empty",
|
||||
given: SensorRequest{
|
||||
SensorID: "",
|
||||
},
|
||||
expecErr: true,
|
||||
},
|
||||
{
|
||||
name: "valid request with long sensor_id",
|
||||
given: SensorRequest{
|
||||
SensorID: "sensor-with-very-long-identifier-12345",
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid request with special characters",
|
||||
given: SensorRequest{
|
||||
SensorID: "sensor-001_test",
|
||||
},
|
||||
expecErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.given.Validate()
|
||||
|
||||
if tt.expecErr && err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.expecErr && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SensorDataRequest_Validate(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
given SensorDataRequest
|
||||
expecErr bool
|
||||
checkFn func(t *testing.T, req SensorDataRequest)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
weekAgo := now.AddDate(0, 0, -7)
|
||||
validFrom := weekAgo.Format(time.RFC3339)
|
||||
validTo := now.Format(time.RFC3339)
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "valid request with all fields",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr(validFrom),
|
||||
To: ptr(validTo),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.From == nil || *req.From != validFrom {
|
||||
t.Errorf("expected From to be %q, got %v", validFrom, req.From)
|
||||
}
|
||||
if req.To == nil || *req.To != validTo {
|
||||
t.Errorf("expected To to be %q, got %v", validTo, req.To)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error when sensor_id is empty",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "",
|
||||
From: ptr(validFrom),
|
||||
To: ptr(validTo),
|
||||
},
|
||||
expecErr: true,
|
||||
},
|
||||
{
|
||||
name: "default To when nil",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr(validFrom),
|
||||
To: nil,
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.To == nil {
|
||||
t.Error("expected To to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.To)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format, got error: %v", err)
|
||||
}
|
||||
if time.Since(parsed) > time.Minute {
|
||||
t.Error("expected To to be approximately now")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default To when empty string",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr(validFrom),
|
||||
To: ptr(""),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.To == nil {
|
||||
t.Error("expected To to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.To)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format, got error: %v", err)
|
||||
}
|
||||
if time.Since(parsed) > time.Minute {
|
||||
t.Error("expected To to be approximately now")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default From when nil",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: nil,
|
||||
To: ptr(validTo),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.From == nil {
|
||||
t.Error("expected From to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.From)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format, got error: %v", err)
|
||||
}
|
||||
expectedFrom := time.Now().AddDate(0, 0, -7)
|
||||
diff := expectedFrom.Sub(parsed)
|
||||
if diff > time.Hour || diff < -time.Hour {
|
||||
t.Errorf("expected From to be approximately 7 days ago, got %v", parsed)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default From when empty string",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr(""),
|
||||
To: ptr(validTo),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.From == nil {
|
||||
t.Error("expected From to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.From)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format, got error: %v", err)
|
||||
}
|
||||
expectedFrom := time.Now().AddDate(0, 0, -7)
|
||||
diff := expectedFrom.Sub(parsed)
|
||||
if diff > time.Hour || diff < -time.Hour {
|
||||
t.Errorf("expected From to be approximately 7 days ago, got %v", parsed)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid From format sets default",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr("invalid-date"),
|
||||
To: ptr(validTo),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.From == nil {
|
||||
t.Error("expected From to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.From)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format after correction, got error: %v", err)
|
||||
}
|
||||
expectedFrom := time.Now().AddDate(0, 0, -7)
|
||||
diff := expectedFrom.Sub(parsed)
|
||||
if diff > time.Hour || diff < -time.Hour {
|
||||
t.Errorf("expected From to be approximately 7 days ago after correction, got %v", parsed)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid To format sets default",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: ptr(validFrom),
|
||||
To: ptr("not-a-date"),
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.To == nil {
|
||||
t.Error("expected To to be set with default value")
|
||||
return
|
||||
}
|
||||
parsed, err := time.Parse(time.RFC3339, *req.To)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format after correction, got error: %v", err)
|
||||
}
|
||||
if time.Since(parsed) > time.Minute {
|
||||
t.Error("expected To to be approximately now after correction")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all defaults when From and To are nil",
|
||||
given: SensorDataRequest{
|
||||
SensorID: "temp-001",
|
||||
From: nil,
|
||||
To: nil,
|
||||
},
|
||||
expecErr: false,
|
||||
checkFn: func(t *testing.T, req SensorDataRequest) {
|
||||
if req.From == nil || req.To == nil {
|
||||
t.Error("expected both From and To to be set with defaults")
|
||||
return
|
||||
}
|
||||
parsedFrom, err := time.Parse(time.RFC3339, *req.From)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format for From, got error: %v", err)
|
||||
}
|
||||
parsedTo, err := time.Parse(time.RFC3339, *req.To)
|
||||
if err != nil {
|
||||
t.Errorf("expected valid RFC3339 format for To, got error: %v", err)
|
||||
}
|
||||
expectedFrom := time.Now().AddDate(0, 0, -7)
|
||||
diff := expectedFrom.Sub(parsedFrom)
|
||||
if diff > time.Hour || diff < -time.Hour {
|
||||
t.Errorf("expected From to be approximately 7 days ago, got %v", parsedFrom)
|
||||
}
|
||||
if time.Since(parsedTo) > time.Minute {
|
||||
t.Error("expected To to be approximately now")
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.given.Validate()
|
||||
|
||||
if tt.expecErr && err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.expecErr && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expecErr {
|
||||
return
|
||||
}
|
||||
|
||||
if tt.checkFn != nil {
|
||||
tt.checkFn(t, tt.given)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user