Skip to content
54 changes: 53 additions & 1 deletion pkl/external_reader_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
// Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,10 +17,12 @@
package pkl

import (
"bytes"
"context"
"path/filepath"
"runtime"
"testing"
"testing/fstest"

"github.com/apple/pkl-go/pkl/internal"
"github.com/stretchr/testify/assert"
Expand All @@ -38,6 +40,56 @@ fibErrB = test.catch(() -> read("fib:abc"))
fibErrC = test.catch(() -> read("fib:-10"))
`

func TestWithExternalClientResourceReader(t *testing.T) {
t.Parallel()
reader := &fsResourceReader{&fsReader{fs: fstest.MapFS{}, scheme: "test"}}
opts := &ExternalReaderClientOptions{}
WithExternalClientResourceReader(reader)(opts)

assert.NotNil(t, opts.ResourceReaders)
assert.Len(t, opts.ResourceReaders, 1)
assert.Equal(t, "test", opts.ResourceReaders[0].Scheme())
}

func TestWithExternalClientModuleReader(t *testing.T) {
t.Parallel()
reader := &fsModuleReader{&fsReader{fs: fstest.MapFS{}, scheme: "test"}}
opts := &ExternalReaderClientOptions{}
WithExternalClientModuleReader(reader)(opts)

assert.NotNil(t, opts.ModuleReaders)
assert.Len(t, opts.ModuleReaders, 1)
assert.Equal(t, "test", opts.ModuleReaders[0].Scheme())
}

func TestWithExternalClientStreams(t *testing.T) {
t.Parallel()
requestReader := &bytes.Buffer{}
responseWriter := &bytes.Buffer{}
opts := &ExternalReaderClientOptions{}
WithExternalClientStreams(requestReader, responseWriter)(opts)

assert.NotNil(t, opts.RequestReader)
assert.NotNil(t, opts.ResponseWriter)
}

func TestWithExternalClientFs(t *testing.T) {
t.Parallel()
fsTest := fstest.MapFS{
"hello.txt": &fstest.MapFile{Data: []byte("hello")},
}
opts := &ExternalReaderClientOptions{}
WithExternalClientFs(fsTest, "fsTest")(opts)

assert.NotNil(t, opts.ResourceReaders)
assert.Len(t, opts.ResourceReaders, 1)
assert.Equal(t, "fsTest", opts.ResourceReaders[0].Scheme())

assert.NotNil(t, opts.ModuleReaders)
assert.Len(t, opts.ModuleReaders, 1)
assert.Equal(t, "fsTest", opts.ModuleReaders[0].Scheme())
}

func TestExternalReaderE2E(t *testing.T) {
manager := NewEvaluatorManager()
defer func() { _ = manager.Close() }()
Expand Down
18 changes: 17 additions & 1 deletion pkl/unmarshal_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
// Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,6 +19,7 @@ package pkl_test
import (
"bytes"
_ "embed"
"fmt"
"testing"

"github.com/apple/pkl-go/pkl"
Expand Down Expand Up @@ -483,3 +484,18 @@ func TestUnmarshal_Types_Pre_030(t *testing.T) {

assert.Equal(t, types.Types{}, res)
}

func TestUnmarshal_NonPointerTypes(t *testing.T) {
var res types.Types
err := pkl.Unmarshal([]byte{}, res)
assert.NotNil(t, err)
assert.EqualError(t, fmt.Errorf("cannot unmarshal non-pointer. Got kind: struct"), err.Error())
}

func TestUnmarshal_Nil(t *testing.T) {
var s *string
err := pkl.Unmarshal([]byte{}, s)
assert.NotNil(t, err)

assert.EqualError(t, fmt.Errorf("cannot unmarshal into nil"), err.Error())
}
190 changes: 189 additions & 1 deletion pkl/values_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
// Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,7 +17,9 @@
package pkl

import (
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -54,11 +56,39 @@ func TestDataSize_String(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expected, test.input.String())
})
}
}

func TestDataSizeUnit_String(t *testing.T) {
tests := []struct {
name string
unit DataSizeUnit
want string
}{
{name: "byte", unit: Bytes, want: "b"},
{name: "kilobyte", unit: Kilobytes, want: "kb"},
{name: "kibibyte", unit: Kibibytes, want: "kib"},
{name: "megabyte", unit: Megabytes, want: "mb"},
{name: "mebibyte", unit: Mebibytes, want: "mib"},
{name: "gigabyte", unit: Gigabytes, want: "gb"},
{name: "gibibyte", unit: Gibibytes, want: "gib"},
{name: "terabyte", unit: Terabytes, want: "tb"},
{name: "tebibyte", unit: Tebibytes, want: "tib"},
{name: "petabyte", unit: Petabytes, want: "pb"},
{name: "pebibyte", unit: Pebibytes, want: "pib"},
{name: "invalid", unit: DataSizeUnit(-1), want: "<invalid>"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.want, test.unit.String())
})
}
}

func TestDataSize_ConvertToUnit(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -95,3 +125,161 @@ func TestDataSize_ConvertToUnit(t *testing.T) {
})
}
}

func TestDuration_String(t *testing.T) {
tests := map[string]struct {
d Duration
want string
}{
"should successfully return valid second string": {
d: Duration{
Unit: Second,
},
want: "s",
},
"should successfully return valid millisecond string": {
d: Duration{
Unit: Millisecond,
},
want: "ms",
},
"should successfully return valid nanosecond string": {
d: Duration{
Unit: Nanosecond,
},
want: "ns",
},
"should successfully return valid microsecond string": {
d: Duration{
Unit: Microsecond,
},
want: "us",
},
"should successfully return valid minute string": {
d: Duration{
Unit: Minute,
},
want: "min",
},
"should successfully return valid hour string": {
d: Duration{
Unit: Hour,
},
want: "h",
},
"should successfully return valid day string": {
d: Duration{
Unit: Day,
},
want: "d",
},
"should return invalid string when provided unknown DurationUnit": {
d: Duration{
Unit: DurationUnit(-1),
},
want: "<invalid>",
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()

assert.Equal(t, tc.want, fmt.Sprintf("%s", tc.d.Unit.String()))
})
}
}

func TestDuration_GoDuration(t *testing.T) {
t.Run("should successfully convert to GoDuration in second", func(t *testing.T) {
t.Parallel()
d := Duration{
Value: 1,
Unit: Second,
}
assert.Equal(t, d.GoDuration(), 1*time.Second)
})
}

func TestDuration_UnmarshalBinary(t *testing.T) {
tests := map[string]struct {
input []byte
want DurationUnit
expectedErr error
}{
"should successfully unmarshal binary from nanosecond": {
input: []byte("ns"),
want: Nanosecond,
},
"should successfully unmarshal binary from microsecond": {
input: []byte("us"),
want: Microsecond,
},
"should successfully unmarshal binary from millisecond": {
input: []byte("ms"),
want: Millisecond,
},
"should successfully unmarshal binary from second": {
input: []byte("s"),
want: Second,
},
"should successfully unmarshal binary from minute": {
input: []byte("min"),
want: Minute,
},
"should successfully unmarshal binary from hour": {
input: []byte("h"),
want: Hour,
},
"should successfully unmarshal binary from day": {
input: []byte("d"),
want: Day,
},
"should fail unmarshal binary from unknown field": {
input: []byte("unknown"),
expectedErr: fmt.Errorf("unrecognized Duration unit: `unknown`"),
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()
var unit DurationUnit
err := unit.UnmarshalBinary(tc.input)

assert.Equal(t, tc.want, unit)
assert.Equal(t, tc.expectedErr, err)
})
}
}

func TestDataSizeUnit_UnmarshalBinary(t *testing.T) {
tests := []struct {
name string
input []byte
want DataSizeUnit
expectedErr error
}{
{name: "byte", input: []byte("b"), want: Bytes},
{name: "kilobyte", input: []byte("kb"), want: Kilobytes},
{name: "kibibyte", input: []byte("kib"), want: Kibibytes},
{name: "megabyte", input: []byte("mb"), want: Megabytes},
{name: "mebibyte", input: []byte("mib"), want: Mebibytes},
{name: "gigabyte", input: []byte("gb"), want: Gigabytes},
{name: "gibibyte", input: []byte("gib"), want: Gibibytes},
{name: "terabyte", input: []byte("tb"), want: Terabytes},
{name: "tebibyte", input: []byte("tib"), want: Tebibytes},
{name: "petabyte", input: []byte("pb"), want: Petabytes},
{name: "pebibyte", input: []byte("pib"), want: Pebibytes},
{name: "unknown", input: []byte("unknown"), expectedErr: fmt.Errorf("unrecognized DataSize unit: `unknown`")},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var unit DataSizeUnit
err := unit.UnmarshalBinary(test.input)

assert.Equal(t, test.want, unit)
assert.Equal(t, test.expectedErr, err)
})
}
}