Compare commits

..

21 commits

Author SHA1 Message Date
34dd908590
Merge pull request #10 from wneessen/omitted
Some checks failed
Codecov workflow / run (push) Failing after 5s
golangci-lint / lint (push) Failing after 5s
Govulncheck Security Scan / test (push) Failing after 25s
REUSE Compliance Check / test (push) Failing after 3s
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1s
SonarQube / Build and analyze (push) Failing after 2s
Add omitted functionallity
2024-09-11 11:38:00 +02:00
68fe249669
Fix typo in Omitted method name
Corrected the spelling of the `Omitted` method to ensure consistency and avoid potential confusion. This change does not affect the functionality but improves code readability and accuracy.
2024-09-11 11:34:59 +02:00
754b2b90aa
Add test for omitted field
Introduce a new test, `TestVariable_Omitted`, to verify the behavior of the `NilBoolean` type fields, ensuring the correct handling of omitted and non-omitted fields during JSON unmarshalling.
2024-09-11 11:34:44 +02:00
7f2cf28053
Moved NewVariable to top
Moved NewVariable above the receiver methods
2024-09-11 11:26:58 +02:00
270111e53f
Reorder type declarations and JSON marshal/unmarshal methods
Moved type declarations for Nil* variables to the top for better readability and organization. JSON marshal and unmarshal methods have been repositioned towards the bottom of the file to keep related logic together.
2024-09-11 11:25:37 +02:00
61e2f10196
Refactor Variable type and add omitted status
Reorganized methods to ensure a logical method order and added the `present` field to track omitted values in JSON. This improves clarity and functionality by correctly indicating when a value was omitted.
2024-09-11 11:23:33 +02:00
ab766b23fa
Merge pull request #9 from wneessen/update-readme
Fix typo and improve readability in README.md
2024-09-11 11:08:30 +02:00
bc611894a8
Fix typo and improve readability in README.md
Corrected misspelling of 'niljson' and clarified punctuation. These changes enhance the clarity of sentences, ensuring better readability and comprehension for users.
2024-09-11 11:08:03 +02:00
7bddca99ae
Merge pull request #8 from wneessen/more-cleanup-cleanup
More code cleanup and security workflows
2024-09-11 11:00:07 +02:00
10d77340d5
Add security workflows for code analysis
This commit introduces three GitHub Actions workflows: `govulncheck`, `dependency-review`, and `scorecards`. These workflows enhance security by scanning for vulnerabilities, reviewing dependencies, and analyzing the supply-chain, respectively.
2024-09-11 10:58:53 +02:00
50877176f5
Simplify error reporting in niljson tests
Replaced t.Errorf with t.Error in niljson test cases for more concise error reporting. This change improves readability and maintains consistency across tests by using the simpler t.Error method.
2024-09-11 10:55:36 +02:00
d427f46eda
Merge pull request #7 from wneessen/more-cleanup
Refactor error messages in niljson tests.
2024-09-11 10:43:55 +02:00
0922c9d322
Refactor error messages in niljson tests.
Replaced hard-coded error strings with constant variables to improve code maintenance and readability. This ensures consistency across error messages and makes future updates easier.
2024-09-11 10:43:31 +02:00
c602cb5a96
Merge pull request #6 from wneessen/code-cleanup
Code cleanup
2024-09-11 10:32:10 +02:00
9584d3ec3c
Refactor error messages in niljson_test.go
Replaced hardcoded error strings with `ErrExpectedJSONInt` constant for consistency. This improves maintainability and readability of the test code by centralizing error message definitions.
2024-09-11 10:31:42 +02:00
98bcb37c50
Refactor error messages to use constants in tests
Added a new constant ErrExpectedJSONString for uniformity in error messages. Updated all relevant test cases to utilize this new constant instead of hardcoding the error message, enhancing code maintainability and readability.
2024-09-11 10:30:02 +02:00
296050ca70
Define error constants for JSON marshaling/unmarshaling tests
Introduced `ErrUnmarshalFailed` and `ErrMarshalFailed` constants to standardize error messages in JSON tests. This enhances code readability and maintainability by avoiding repeated strings directly in the test cases.
2024-09-11 10:27:55 +02:00
44cc717bc3
Merge pull request #5 from wneessen/fix-sonarqube
Fix Go version syntax in SonarQube workflow
2024-09-11 10:23:09 +02:00
926cfc9581
Fix Go version syntax in SonarQube workflow
Corrected the Go version syntax from '1.23.x' to '1.23' in the SonarQube GitHub Action workflow configuration to ensure proper version setup. This change addresses potential issues with version resolution in the setup-go action.
2024-09-11 10:22:51 +02:00
31d2bea9c6
Merge pull request #4 from wneessen/sonarqube-action
Add SonarQube integration for code analysis
2024-09-11 10:20:55 +02:00
e557e4caac
Add SonarQube integration for code analysis
Introduce a new SonarQube configuration to the project. This includes a GitHub action workflow for continuous integration on the main branch, setting up Go environment, running unit tests, and performing SonarQube analysis. This addition aims to ensure code quality and coverage are continuously monitored.
2024-09-11 10:19:00 +02:00
8 changed files with 351 additions and 125 deletions

31
.github/workflows/dependency-review.yml vendored Normal file
View file

@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
#
# SPDX-License-Identifier: CC0-1.0
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request,
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
# Once installed, if the workflow run is marked as required,
# PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
with:
egress-policy: audit
- name: 'Checkout Repository'
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: 'Dependency Review'
uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4

21
.github/workflows/govulncheck.yml vendored Normal file
View file

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: Govulncheck Security Scan
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
with:
egress-policy: audit
- name: Run govulncheck
uses: golang/govulncheck-action@dd0578b371c987f96d1185abb54344b44352bd58 # v1.0.3

80
.github/workflows/scorecards.yml vendored Normal file
View file

@ -0,0 +1,80 @@
# SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
#
# SPDX-License-Identifier: CC0-1.0
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '20 7 * * 2'
push:
branches: ["main"]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
contents: read
actions: read
steps:
- name: Harden Runner
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
with:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecards on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6
with:
sarif_file: results.sarif

47
.github/workflows/sonarqube.yml vendored Normal file
View file

@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: 2024 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
name: SonarQube
permissions:
contents: read
on:
push:
branches:
- main
jobs:
build:
name: Build and analyze
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
with:
egress-policy: audit
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: '1.23'
- name: Run unit Tests
run: |
go test -v -race --coverprofile=./cov.out ./...
- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- uses: sonarsource/sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View file

@ -14,10 +14,11 @@ SPDX-License-Identifier: CC0-1.0
niljson provides a simple and efficient way to handle nullable JSON fields during the (un-)marshalling process. niljson provides a simple and efficient way to handle nullable JSON fields during the (un-)marshalling process.
In JSON, it's common to encounter fields that can be `null`, but handling these fields in Go can be cumbersome, In JSON, it's common to encounter fields that can be `null`, but handling these fields in Go can be cumbersome,
especially when dealing with primitive types like `int`, `float64`, `bool`. These types can all be either `0` (as value) especially when dealing with primitive types like `int`, `float64`, and `bool`. These types can all be either `0`
or `null`. In Go you can always work with pointers but these, of course, can lead to unhandled nil pointer dereferences. (as a value) or `null`. In Go you can always work with pointers, but these can lead to unhandled nil
pointer dereferences.
**niljaon** addresses this challenge by offering a set of types that can seamlessly handle `null` values during **niljson** addresses this challenge by offering a set of types that can seamlessly handle `null` values during
unmarshalling, allowing your Go applications to work with JSON data more naturally and with fewer boilerplate unmarshalling, allowing your Go applications to work with JSON data more naturally and with fewer boilerplate
checks for `nil` values. checks for `nil` values.

View file

@ -8,42 +8,6 @@ import (
"encoding/json" "encoding/json"
) )
// Variable is a generic variable type that can be null.
type Variable[T any] struct {
value T
notNil bool
}
// Value returns the value of the Variable
func (v *Variable[T]) Value() T {
return v.value
}
// NotNil returns true when a Variable is not nil
func (v *Variable[T]) NotNil() bool {
return v.notNil
}
// IsNil returns true when a Variable is nil
func (v *Variable[T]) IsNil() bool {
return !v.notNil
}
// Reset resets the value to the Variable to a zero value and sets it to be nil
func (v *Variable[T]) Reset() {
var newVal T
v.value = newVal
v.notNil = false
}
// NewVariable returns a new Variable of generic type
func NewVariable[T any](value T) Variable[T] {
return Variable[T]{
notNil: true,
value: value,
}
}
// NilBoolean is an boolean type that can be nil // NilBoolean is an boolean type that can be nil
type NilBoolean = Variable[bool] type NilBoolean = Variable[bool]
@ -80,14 +44,46 @@ type NilFloat64 = Variable[float64]
// NilString is a string type that can be nil // NilString is a string type that can be nil
type NilString = Variable[string] type NilString = Variable[string]
// UnmarshalJSON satisfies the json.Unmarshaler interface for generic Variable types // Variable is a generic variable type that can be null.
func (v *Variable[T]) UnmarshalJSON(data []byte) error { type Variable[T any] struct {
if string(data) != "null" { value T
v.value = *new(T) notNil bool
v.notNil = true present bool
return json.Unmarshal(data, &v.value)
} }
return nil
// NewVariable returns a new Variable of generic type
func NewVariable[T any](value T) Variable[T] {
return Variable[T]{
notNil: true,
value: value,
}
}
// IsNil returns true when a Variable is nil
func (v *Variable[T]) IsNil() bool {
return !v.notNil
}
// NotNil returns true when a Variable is not nil
func (v *Variable[T]) NotNil() bool {
return v.notNil
}
// Omitted returns true if a value was omitted in the JSON
func (v *Variable[T]) Omitted() bool {
return !v.present
}
// Reset resets the value to the Variable to a zero value and sets it to be nil
func (v *Variable[T]) Reset() {
var newVal T
v.value = newVal
v.notNil = false
}
// Value returns the value of the Variable
func (v *Variable[T]) Value() T {
return v.value
} }
// MarshalJSON satisfies the json.Marshaler interface for generic Variable types // MarshalJSON satisfies the json.Marshaler interface for generic Variable types
@ -97,3 +93,14 @@ func (v *Variable[T]) MarshalJSON() ([]byte, error) {
} }
return json.Marshal(v.value) return json.Marshal(v.value)
} }
// UnmarshalJSON satisfies the json.Unmarshaler interface for generic Variable types
func (v *Variable[T]) UnmarshalJSON(data []byte) error {
v.present = true
if string(data) != "null" {
v.value = *new(T)
v.notNil = true
return json.Unmarshal(data, &v.value)
}
return nil
}

View file

@ -12,6 +12,17 @@ import (
"testing" "testing"
) )
// List of common errors
const (
ErrUnmarshalFailed = "failed to unmarshal json with nil types: %s"
ErrMarshalFailed = "failed to marshal json with nil types: %s"
ErrExpectedJSONString = "expected json to be %q, got %q"
ErrExpectedJSONInt = "expected json to be %d, got %d"
ErrExpectedValue = "expected value, but got nil"
ErrExpectedNil = "expected nil, but got value"
ErrExpectedNilReset = "expected value to be nil after reset"
)
var jsonBytes = []byte( var jsonBytes = []byte(
`{ `{
"bool": true, "bool": true,
@ -37,14 +48,14 @@ func TestVariable_UnmarshalJSON_Boolean(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if !jt.Value.Value() { if !jt.Value.Value() {
t.Errorf("expected value to be true, got %t", jt.Value.Value()) t.Errorf("expected value to be true, got %t", jt.Value.Value())
@ -52,7 +63,7 @@ func TestVariable_UnmarshalJSON_Boolean(t *testing.T) {
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -68,10 +79,10 @@ func TestVariable_MarshalJSON_Boolean(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -83,14 +94,14 @@ func TestVariable_UnmarshalJSON_ByteSlice(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if !bytes.Equal(jt.Value.Value(), []byte("bytes")) { if !bytes.Equal(jt.Value.Value(), []byte("bytes")) {
t.Errorf("expected value to be %q, got %q", "bytes", jt.Value.Value()) t.Errorf("expected value to be %q, got %q", "bytes", jt.Value.Value())
@ -98,7 +109,7 @@ func TestVariable_UnmarshalJSON_ByteSlice(t *testing.T) {
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -114,10 +125,10 @@ func TestVariable_MarshalJSON_ByteSlice(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -130,14 +141,14 @@ func TestVariable_UnmarshalJSON_Float32(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %f, got %f", expected, jt.Value.Value()) t.Errorf("expected value to be %f, got %f", expected, jt.Value.Value())
@ -145,7 +156,7 @@ func TestVariable_UnmarshalJSON_Float32(t *testing.T) {
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -161,10 +172,10 @@ func TestVariable_MarshalJSON_Float32(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -177,14 +188,14 @@ func TestVariable_UnmarshalJSON_Float64(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %f, got %f", expected, jt.Value.Value()) t.Errorf("expected value to be %f, got %f", expected, jt.Value.Value())
@ -192,7 +203,7 @@ func TestVariable_UnmarshalJSON_Float64(t *testing.T) {
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -208,10 +219,10 @@ func TestVariable_MarshalJSON_Float64(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -224,22 +235,22 @@ func TestVariable_UnmarshalJSON_Int(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -255,10 +266,10 @@ func TestVariable_MarshalJSON_Int(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -271,22 +282,22 @@ func TestVariable_UnmarshalJSON_Int64(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -302,10 +313,10 @@ func TestVariable_MarshalJSON_Int64(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -318,14 +329,14 @@ func TestVariable_UnmarshalJSON_String(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %s, got %s", expected, jt.Value.Value()) t.Errorf("expected value to be %s, got %s", expected, jt.Value.Value())
@ -333,7 +344,7 @@ func TestVariable_UnmarshalJSON_String(t *testing.T) {
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -349,10 +360,10 @@ func TestVariable_MarshalJSON_String(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -365,22 +376,22 @@ func TestVariable_UnmarshalJSON_UInt(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -396,10 +407,10 @@ func TestVariable_MarshalJSON_UInt(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -412,22 +423,22 @@ func TestVariable_UnmarshalJSON_UInt8(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -443,10 +454,10 @@ func TestVariable_MarshalJSON_UInt8(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -459,22 +470,22 @@ func TestVariable_UnmarshalJSON_UInt16(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -490,10 +501,10 @@ func TestVariable_MarshalJSON_UInt16(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -506,22 +517,22 @@ func TestVariable_UnmarshalJSON_UInt32(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -537,10 +548,10 @@ func TestVariable_MarshalJSON_UInt32(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
} }
} }
@ -553,22 +564,22 @@ func TestVariable_UnmarshalJSON_UInt64(t *testing.T) {
var jt JSONType var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil { if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf("failed to unmarshal json with nil types: %s", err) t.Errorf(ErrUnmarshalFailed, err)
} }
if jt.Value.IsNil() { if jt.Value.IsNil() {
t.Errorf("expected value, but got nil") t.Error(ErrExpectedValue)
} }
if jt.NilValue.NotNil() { if jt.NilValue.NotNil() {
t.Errorf("expected nil, but got value") t.Error(ErrExpectedNil)
} }
if jt.Value.Value() != expected { if jt.Value.Value() != expected {
t.Errorf("expected value to be %d, got %d", expected, jt.Value.Value()) t.Errorf(ErrExpectedJSONInt, expected, jt.Value.Value())
} }
jt.Value.Reset() jt.Value.Reset()
if jt.Value.NotNil() { if jt.Value.NotNil() {
t.Errorf("expected value to be nil after reset") t.Error(ErrExpectedNilReset)
} }
} }
@ -584,10 +595,32 @@ func TestVariable_MarshalJSON_UInt64(t *testing.T) {
} }
data, err := json.Marshal(&jt) data, err := json.Marshal(&jt)
if err != nil { if err != nil {
t.Errorf("failed to marshal json with nil types: %s", err) t.Errorf(ErrMarshalFailed, err)
} }
if !bytes.Equal(data, []byte(expected)) { if !bytes.Equal(data, []byte(expected)) {
t.Errorf("expected json to be %q, got %q", expected, string(data)) t.Errorf(ErrExpectedJSONString, expected, string(data))
}
}
func TestVariable_Omitted(t *testing.T) {
type JSONType struct {
NilValue NilBoolean `json:"nilvalue"`
Omitted NilBoolean `json:"omitted,omitempty"`
}
var jt JSONType
if err := json.Unmarshal(jsonBytes, &jt); err != nil {
t.Errorf(ErrUnmarshalFailed, err)
}
if jt.NilValue.NotNil() {
t.Error(ErrExpectedNil)
}
if jt.NilValue.Omitted() {
t.Error("expected nil value to be not omitted")
}
if !jt.Omitted.Omitted() {
t.Error("expected omitted value to be omitted")
} }
} }

6
sonar-project.properties Normal file
View file

@ -0,0 +1,6 @@
# SPDX-FileCopyrightText: 2024 Winni Neessen <wn@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0
sonar.projectKey=niljson
sonar.go.coverage.reportPaths=cov.out