initial commits
parent
c47b8d7cdb
commit
0cf3d1e617
|
@ -0,0 +1,82 @@
|
|||
package nul
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Nullable[T any] struct {
|
||||
value T
|
||||
isnull bool
|
||||
something bool
|
||||
}
|
||||
|
||||
func Nothing[T any]() Nullable[T] {
|
||||
var nothing Nullable[T]
|
||||
|
||||
return nothing
|
||||
}
|
||||
|
||||
func Null[T any]() Nullable[T] {
|
||||
return Nullable[T]{
|
||||
isnull:true,
|
||||
}
|
||||
}
|
||||
|
||||
func Something[T any](value T) Nullable[T] {
|
||||
return Nullable[T]{
|
||||
something:true,
|
||||
value:value,
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) isnothing() bool {
|
||||
return !receiver.something && !receiver.isnull
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) Filter(fn func(T)bool) Nullable[T] {
|
||||
if receiver.isnothing() {
|
||||
return Nothing[T]()
|
||||
}
|
||||
if receiver.isnull {
|
||||
return Nothing[T]()
|
||||
}
|
||||
|
||||
if !fn(receiver.value) {
|
||||
return Nothing[T]()
|
||||
}
|
||||
|
||||
return receiver
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) Get() (T, bool) {
|
||||
return receiver.value, receiver.something
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) GoString() string {
|
||||
if receiver.isnothing() {
|
||||
return fmt.Sprintf("nul.Nothing[%T]()", receiver.value)
|
||||
}
|
||||
if receiver.isnull {
|
||||
return fmt.Sprintf("nul.Null[%T]()", receiver.value)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("nul.Something[%T](%#v)", receiver.value, receiver.value)
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) WhenNothing(fn func()) {
|
||||
if receiver.isnothing() {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) WhenNull(fn func()) {
|
||||
if receiver.isnull {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver Nullable[T]) WhenSomething(fn func(T)) {
|
||||
if receiver.something {
|
||||
fn(receiver.value)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,380 @@
|
|||
package nul_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sourcecode.social/reiver/go-nul"
|
||||
)
|
||||
|
||||
func TestOptional_Get_string(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Nullable nul.Nullable[string]
|
||||
ExpectedValue string
|
||||
ExpectedSomething bool
|
||||
}{
|
||||
{
|
||||
Nullable: nul.Nothing[string](),
|
||||
ExpectedValue: "",
|
||||
ExpectedSomething: false,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Something(""),
|
||||
ExpectedValue: "",
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something("once twice thrice fource"),
|
||||
ExpectedValue: "once twice thrice fource",
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something("😈"),
|
||||
ExpectedValue: "😈",
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something("۰۱۲۳۴۵۶۷۸۹"),
|
||||
ExpectedValue: "۰۱۲۳۴۵۶۷۸۹",
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
value, something := test.Nullable.Get()
|
||||
|
||||
{
|
||||
expected := test.ExpectedSomething
|
||||
actual := something
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual something-flag is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED FLAG: %t", expected)
|
||||
t.Logf("ACTUAL FLAG: %t", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
expected := test.ExpectedValue
|
||||
actual := value
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED VALUE: %q", expected)
|
||||
t.Logf("ACTUAL VALUE: %q", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptional_Get_int8(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Nullable nul.Nullable[int8]
|
||||
ExpectedValue int8
|
||||
ExpectedSomething bool
|
||||
}{
|
||||
{
|
||||
Nullable: nul.Nothing[int8](),
|
||||
ExpectedValue: 0,
|
||||
ExpectedSomething: false,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Something(int8(-127)),
|
||||
ExpectedValue: int8(-127),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-126)),
|
||||
ExpectedValue: int8(-126),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-125)),
|
||||
ExpectedValue: int8(-125),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-124)),
|
||||
ExpectedValue: int8(-124),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-123)),
|
||||
ExpectedValue: int8(-123),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-122)),
|
||||
ExpectedValue: int8(-122),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-121)),
|
||||
ExpectedValue: int8(-121),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-120)),
|
||||
ExpectedValue: int8(-120),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-9)),
|
||||
ExpectedValue: int8(-9),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-8)),
|
||||
ExpectedValue: int8(-8),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-7)),
|
||||
ExpectedValue: int8(-7),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-6)),
|
||||
ExpectedValue: int8(-6),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-5)),
|
||||
ExpectedValue: int8(-5),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-4)),
|
||||
ExpectedValue: int8(-4),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-3)),
|
||||
ExpectedValue: int8(-3),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-2)),
|
||||
ExpectedValue: int8(-2),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(-1)),
|
||||
ExpectedValue: int8(-1),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(0)),
|
||||
ExpectedValue: int8(0),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(1)),
|
||||
ExpectedValue: int8(1),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(2)),
|
||||
ExpectedValue: int8(2),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(3)),
|
||||
ExpectedValue: int8(3),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(4)),
|
||||
ExpectedValue: int8(4),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(5)),
|
||||
ExpectedValue: int8(5),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(6)),
|
||||
ExpectedValue: int8(6),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(7)),
|
||||
ExpectedValue: int8(7),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(8)),
|
||||
ExpectedValue: int8(8),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(9)),
|
||||
ExpectedValue: int8(9),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(120)),
|
||||
ExpectedValue: int8(120),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(121)),
|
||||
ExpectedValue: int8(121),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(122)),
|
||||
ExpectedValue: int8(122),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(123)),
|
||||
ExpectedValue: int8(123),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(124)),
|
||||
ExpectedValue: int8(124),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(125)),
|
||||
ExpectedValue: int8(125),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(126)),
|
||||
ExpectedValue: int8(126),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(int8(127)),
|
||||
ExpectedValue: int8(127),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
value, something := test.Nullable.Get()
|
||||
|
||||
{
|
||||
expected := test.ExpectedSomething
|
||||
actual := something
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual something-flag is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED FLAG: %t", expected)
|
||||
t.Logf("ACTUAL FLAG: %t", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
expected := test.ExpectedValue
|
||||
actual := value
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED VALUE: %q", expected)
|
||||
t.Logf("ACTUAL VALUE: %q", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptional_Get_uint8(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Nullable nul.Nullable[uint8]
|
||||
ExpectedValue uint8
|
||||
ExpectedSomething bool
|
||||
}{
|
||||
{
|
||||
Nullable: nul.Nothing[uint8](),
|
||||
ExpectedValue: 0,
|
||||
ExpectedSomething: false,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Something(uint8(0)),
|
||||
ExpectedValue: uint8(0),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(uint8(1)),
|
||||
ExpectedValue: uint8(1),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(uint8(2)),
|
||||
ExpectedValue: uint8(2),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(uint8(254)),
|
||||
ExpectedValue: uint8(254),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Something(uint8(255)),
|
||||
ExpectedValue: uint8(255),
|
||||
ExpectedSomething: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
value, something := test.Nullable.Get()
|
||||
|
||||
{
|
||||
expected := test.ExpectedSomething
|
||||
actual := something
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual something-flag is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED FLAG: %t", expected)
|
||||
t.Logf("ACTUAL FLAG: %t", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
expected := test.ExpectedValue
|
||||
actual := value
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED VALUE: %q", expected)
|
||||
t.Logf("ACTUAL VALUE: %q", actual)
|
||||
t.Logf("NULLABLE: %#v", test.Nullable)
|
||||
/////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package nul_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
|
||||
"sourcecode.social/reiver/go-nul"
|
||||
)
|
||||
|
||||
func TestNullable_GoString(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Value any
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Value: "",
|
||||
Expected: `nul.Something[string]("")`,
|
||||
},
|
||||
{
|
||||
Value: "once twice thrice fource",
|
||||
Expected: `nul.Something[string]("once twice thrice fource")`,
|
||||
},
|
||||
{
|
||||
Value: "apple banana cherry",
|
||||
Expected: `nul.Something[string]("apple banana cherry")`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint8 (0x0),
|
||||
Expected: `nul.Something[uint8](0x0)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x1),
|
||||
Expected: `nul.Something[uint8](0x1)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0x2),
|
||||
Expected: `nul.Something[uint8](0x2)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xfe),
|
||||
Expected: `nul.Something[uint8](0xfe)`,
|
||||
},
|
||||
{
|
||||
Value: uint8 (0xff),
|
||||
Expected: `nul.Something[uint8](0xff)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: uint16 (0x0),
|
||||
Expected: `nul.Something[uint16](0x0)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x1),
|
||||
Expected: `nul.Something[uint16](0x1)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x2),
|
||||
Expected: `nul.Something[uint16](0x2)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfe),
|
||||
Expected: `nul.Something[uint16](0xfe)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xff),
|
||||
Expected: `nul.Something[uint16](0xff)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x100),
|
||||
Expected: `nul.Something[uint16](0x100)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x101),
|
||||
Expected: `nul.Something[uint16](0x101)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0x102),
|
||||
Expected: `nul.Something[uint16](0x102)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xfffe),
|
||||
Expected: `nul.Something[uint16](0xfffe)`,
|
||||
},
|
||||
{
|
||||
Value: uint16 (0xffff),
|
||||
Expected: `nul.Something[uint16](0xffff)`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Value: struct { A string; B int }{A:"joeblow",B:7},
|
||||
Expected: `nul.Something[struct { A string; B int }](struct { A string; B int }{A:"joeblow", B:7})`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
op := nul.Something(test.Value)
|
||||
gostring := op.GoString()
|
||||
|
||||
|
||||
{
|
||||
expected := test.Expected
|
||||
actual := gostring
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED: %q", expected)
|
||||
t.Logf("ACTUAL: %q", actual)
|
||||
t.Logf("VALUE-TYPE: %T", test.Value)
|
||||
t.Logf("VALUE: %#v", test.Value)
|
||||
//////////////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNullable_GoString_nothing(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Nullable fmt.GoStringer
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Nullable: nul.Nothing[string](),
|
||||
Expected: `nul.Nothing[string]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Nothing[int8](),
|
||||
Expected: `nul.Nothing[int8]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[int16](),
|
||||
Expected: `nul.Nothing[int16]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[int32](),
|
||||
Expected: `nul.Nothing[int32]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[int64](),
|
||||
Expected: `nul.Nothing[int64]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Nothing[uint8](),
|
||||
Expected: `nul.Nothing[uint8]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[uint16](),
|
||||
Expected: `nul.Nothing[uint16]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[uint32](),
|
||||
Expected: `nul.Nothing[uint32]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Nothing[uint64](),
|
||||
Expected: `nul.Nothing[uint64]()`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
expected := test.Expected
|
||||
actual := test.Nullable.GoString()
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED GO-STRING: %q", expected)
|
||||
t.Logf("ACTUAL GO-STRING: %q", actual)
|
||||
t.Logf("TYPE: %T", test.Nullable)
|
||||
/////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNullable_GoString_null(t *testing.T) {
|
||||
|
||||
tests := []struct{
|
||||
Nullable fmt.GoStringer
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Nullable: nul.Null[string](),
|
||||
Expected: `nul.Null[string]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Null[int8](),
|
||||
Expected: `nul.Null[int8]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[int16](),
|
||||
Expected: `nul.Null[int16]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[int32](),
|
||||
Expected: `nul.Null[int32]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[int64](),
|
||||
Expected: `nul.Null[int64]()`,
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
Nullable: nul.Null[uint8](),
|
||||
Expected: `nul.Null[uint8]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[uint16](),
|
||||
Expected: `nul.Null[uint16]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[uint32](),
|
||||
Expected: `nul.Null[uint32]()`,
|
||||
},
|
||||
{
|
||||
Nullable: nul.Null[uint64](),
|
||||
Expected: `nul.Null[uint64]()`,
|
||||
},
|
||||
}
|
||||
|
||||
for testNumber, test := range tests {
|
||||
|
||||
expected := test.Expected
|
||||
actual := test.Nullable.GoString()
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("For test #%d, the actual go-string value is not what was expected.", testNumber)
|
||||
t.Logf("EXPECTED GO-STRING: %q", expected)
|
||||
t.Logf("ACTUAL GO-STRING: %q", actual)
|
||||
t.Logf("TYPE: %T", test.Nullable)
|
||||
/////////////// CONTINUE
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue